packages feed

borsh 0.2.0 → 0.3.0

raw patch · 11 files changed

+415/−123 lines, 11 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

- Codec.Borsh: Struct :: a -> Struct a
- Codec.Borsh: newtype Struct a
+ Codec.Borsh: AsEnum :: a -> AsEnum a
+ Codec.Borsh: AsStruct :: a -> AsStruct a
+ Codec.Borsh: KnownImpliesMax :: a -> KnownImpliesMax a
+ Codec.Borsh: [getEnum] :: AsEnum a -> a
+ Codec.Borsh: [getKnownImpliesMax] :: KnownImpliesMax a -> a
+ Codec.Borsh: borshMaxSize :: BorshMaxSize a => Proxy a -> Word32
+ Codec.Borsh: class BorshMaxSize (a :: Type)
+ Codec.Borsh: newtype AsEnum a
+ Codec.Borsh: newtype AsStruct a
+ Codec.Borsh: newtype KnownImpliesMax a
- Codec.Borsh: [SizeKnown] :: Int -> Size 'HasKnownSize
+ Codec.Borsh: [SizeKnown] :: Word32 -> Size 'HasKnownSize
- Codec.Borsh: [getStruct] :: Struct a -> a
+ Codec.Borsh: [getStruct] :: AsStruct a -> a
- Codec.Borsh: borshSize :: (BorshSize a, StaticBorshSize a ~ SumKnownSize (Code a), BorshSizeSum (Code a)) => Proxy a -> Size (StaticBorshSize a)
+ Codec.Borsh: borshSize :: BorshSize a => Proxy a -> Size (StaticBorshSize a)
- Codec.Borsh: decodeBorsh :: (FromBorsh a, Generic a, BorshSizeSum (Code a), All2 FromBorsh (Code a)) => Decoder s a
+ Codec.Borsh: decodeBorsh :: FromBorsh a => Decoder s a
- Codec.Borsh: encodeBorsh :: (ToBorsh a, Generic a, BorshSizeSum (Code a), All2 ToBorsh (Code a)) => Encoder a
+ Codec.Borsh: encodeBorsh :: ToBorsh a => Encoder a
- Codec.Borsh: type StaticBorshSize a = SumKnownSize (Code a);
+ Codec.Borsh: type StaticBorshSize a :: KnownSize;

Files

CHANGELOG.md view
@@ -1,5 +1,14 @@ # Revision history for borsh +## 0.3.0 -- 2023-03-17++* Introduce `BorshMaxSize`+* Rename `Struct` (for deriving-via) to `AsStruct`+* Introduce `AsEnum` (for deriving-via) alongside `AsStruct`+  (this is also the reason for the renaming: `Enum` is in the prelude.)+* Remove the generic defaults for `ToBorsh`, `FromBorsh`, `BorshSize` and+  `MaxBorshSize`; users should instead use `AsEnum` or `AsStruct` (#10).+ ## 0.2.0 -- 2022-11-15  * Remove dependency on `memory`
borsh.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               borsh-version:            0.2.0+version:            0.3.0 synopsis:           Implementation of BORSH serialisation description:   This package provides type classes and combinators for
src/Codec/Borsh.hs view
@@ -13,20 +13,27 @@   , Size(..)   , KnownSize(..)   , BorshSizeSum(..)+  , BorshMaxSize(..)     -- * Deriving-via support-  , Struct(..)+  , AsEnum(..)+  , AsStruct(..)+  , KnownImpliesMax(..)   ) where  import Codec.Borsh.Class-    ( BorshSizeSum(..),-      Struct(..),-      FromBorsh(..),-      ToBorsh(..),-      BorshSize(..),-      Size(..),-      KnownSize(..),-      serialiseBorsh,-      deserialiseBorsh )+    ( BorshSizeSum(..)+    , AsEnum(..)+    , AsStruct(..)+    , FromBorsh(..)+    , ToBorsh(..)+    , BorshSize(..)+    , Size(..)+    , KnownSize(..)+    , BorshMaxSize(..)+    , KnownImpliesMax(..)+    , serialiseBorsh+    , deserialiseBorsh+    ) import Codec.Borsh.Encoding (Encoder(..)) import Codec.Borsh.Incremental (Decoder) import Codec.Borsh.Incremental.Monad (DeserialiseFailure(..))
src/Codec/Borsh/Class.hs view
@@ -5,12 +5,15 @@     ToBorsh(..)   , FromBorsh(..)     -- ** Deriving-via support-  , Struct(..)+  , AsEnum(..)+  , AsStruct(..)+  , KnownImpliesMax(..)     -- * Size information   , KnownSize(..)   , Size(..)   , BorshSize(..)   , BorshSizeSum(..)+  , BorshMaxSize(..)     -- * Derived functionality   , serialiseBorsh   , deserialiseBorsh@@ -50,7 +53,7 @@  -- | The statically known size of encodings of values of a particular type. data Size (a :: KnownSize) where-  SizeKnown    :: Int -> Size 'HasKnownSize+  SizeKnown    :: Word32 -> Size 'HasKnownSize   SizeVariable :: Size 'HasVariableSize  deriving instance Show (Size a)@@ -58,20 +61,33 @@  class BorshSize (a :: Type) where   type StaticBorshSize a :: KnownSize-  type StaticBorshSize a = SumKnownSize (Code a) -  -- | Size of the Borsh encoding, if known ahead of time+  -- | Size of the Borsh encoding, if known statically (independent of a value)   ---  -- See 'encodeBorsh' for discussion of the generic instance.+  -- There is no generic default implementation of 'borshSize'; instead use+  -- deriving-via using 'AsStruct' or 'AsEnum'.   borshSize :: Proxy a -> Size (StaticBorshSize a) -  default borshSize ::-       ( StaticBorshSize a ~ SumKnownSize (Code a)-       , BorshSizeSum (Code a)-       )-    => Proxy a -> Size (StaticBorshSize a)-  borshSize _ = borshSizeSum (Proxy @(Code a))+class BorshMaxSize (a :: Type) where+  -- | Maximum size of the Borsh encoding+  --+  -- There is no generic default implementation of 'borshMaxSize'; instead use+  -- deriving-via using 'AsStruct' or 'AsEnum'.+  --+  -- However, while it is possible to use deriving-via to derive 'BorshMaxSize'+  -- for your own types, recursive types should /not/ be given an instance (and+  -- the derived function will not terminate).+  borshMaxSize :: Proxy a -> Word32 +-- | If the size of a type's Borsh encoding is statically known then we also+-- know the maximum size of the encoding. Useful for deriving-via.+newtype KnownImpliesMax a = KnownImpliesMax { getKnownImpliesMax :: a }++instance ( BorshSize a+         , StaticBorshSize a ~ 'HasKnownSize+         ) => BorshMaxSize (KnownImpliesMax a) where+  borshMaxSize _ = case borshSize (Proxy @a) of SizeKnown n -> n+ {-------------------------------------------------------------------------------   Definition -------------------------------------------------------------------------------}@@ -79,33 +95,22 @@ class BorshSize a => ToBorsh a where   -- | Encoder to Borsh   ---  -- NOTE: The default generic encoder uses the Borsh encoding for enums,-  -- and will therefore use constructor tag; see 'Struct' for detailed-  -- discussion. Since the spec mandates the presence of that constructor tag,-  -- the generic encoder/decoder does not apply to types without constructors.+  -- There is no generic default implementation of 'encodeBorsh'; instead use+  -- deriving-via using 'AsStruct' or 'AsEnum'.   encodeBorsh :: Encoder a -  default encodeBorsh ::-       (Generic a, BorshSizeSum (Code a), All2 ToBorsh (Code a))-    => Encoder a-  encodeBorsh = Encoder $ runEncoder encodeBorsh . from- class BorshSize a => FromBorsh a where   -- | Decode from Borsh   ---  -- See 'encodeBorsh' for discussion of the generic instance.+  -- There is no generic default implementation of 'decodeBorsh'; instead use+  -- deriving-via using 'AsStruct' or 'AsEnum'.   decodeBorsh :: Decoder s a -  default decodeBorsh ::-       (Generic a, BorshSizeSum (Code a), All2 FromBorsh (Code a))-    => Decoder s a-  decodeBorsh = to <$> decodeBorsh- {--------------------------------------------------------------------------------  Structs+  Enums -------------------------------------------------------------------------------} --- | Deriving-via support for structs+-- | Deriving-via support for enums (general ADTs) -- -- The Borsh spec <https://borsh.io/> mandates that enums have a tag indicating -- the constructor, even when there is only a single constructor in the enum.@@ -114,34 +119,76 @@ -- the only difference between them is that a struct is an enum with a single -- constructor. ----- The default generic encoder en decoder you get in 'ToBorsh' and 'FromBorsh'--- will therefore add the tag, independent of the number of constructors. If--- you want the encoding of a struct, without the tag, you need to use deriving--- via:+-- The generic encoder en decoder you get in 'ToBorsh' and 'FromBorsh' when+-- deriving via @AsEnum@ will therefore add the tag, independent of the number of+-- constructors: --+-- > data MyEnum = ..+-- >   deriving (BorshSize, ToBorsh, FromBorsh) via AsEnum MyEnum+--+-- If you want the encoding of a struct, without the tag, you need to derive via+-- 'AsStruct'.+newtype AsEnum a = AsEnum { getEnum :: a }++instance BorshSizeSum (Code a) => BorshSize (AsEnum a) where+  type StaticBorshSize (AsEnum a) = SumKnownSize (Code a)+  borshSize _ = borshSizeSum (Proxy @(Code a))++instance ( Generic a+         , All2 BorshMaxSize (Code a)+         ) => BorshMaxSize (AsEnum a) where+  borshMaxSize _ = borshMaxSize (Proxy @(SOP I (Code a)))++instance ( Generic a+         , BorshSizeSum (Code a)+         , All2 ToBorsh (Code a)+         ) => ToBorsh (AsEnum a) where+  encodeBorsh = contramap (from . getEnum) encodeBorsh++instance ( Generic a+         , BorshSizeSum  (Code a)+         , All2 FromBorsh (Code a)+         ) => FromBorsh (AsEnum a) where+  decodeBorsh = fmap (AsEnum . to) decodeBorsh++{-------------------------------------------------------------------------------+  Structs+-------------------------------------------------------------------------------}++-- | Deriving-via support for structs+--+-- Usage:+-- -- > data MyStruct = ..--- >   deriving (BorshSize, ToBorsh, FromBorsh) via Struct MyStruct+-- >   deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct MyStruct -- -- NOTE: Doing so may have consequences for forwards compatibility: if a tag -- is present, additional constructors can be added without invalidating the--- encoding of existing constructors.-newtype Struct a = Struct { getStruct :: a }+-- encoding of existing constructors. See also 'AsEnum'.+newtype AsStruct a = AsStruct { getStruct :: a } -instance (IsProductType a xs, All BorshSize xs) => BorshSize (Struct a) where-  type StaticBorshSize (Struct a) = ProdKnownSize (ProductCode a)+instance ( IsProductType a xs+         , All BorshSize xs+         ) => BorshSize (AsStruct a) where+  type StaticBorshSize (AsStruct a) = ProdKnownSize (ProductCode a)   borshSize _ = sizeOfProd (Proxy @(ProductCode a))  instance ( IsProductType a xs+         , All BorshMaxSize xs+         ) => BorshMaxSize (AsStruct a) where+  borshMaxSize _ = borshMaxSize (Proxy @(NP I (ProductCode a)))++instance ( IsProductType a xs          , All BorshSize xs          , All ToBorsh xs-         ) => ToBorsh (Struct a) where+         ) => ToBorsh (AsStruct a) where   encodeBorsh = contramap (productTypeFrom . getStruct) encodeBorsh  instance ( IsProductType a xs          , All BorshSize xs          , All FromBorsh xs-         ) => FromBorsh (Struct a) where-  decodeBorsh = fmap (Struct . productTypeTo) decodeBorsh+         ) => FromBorsh (AsStruct a) where+  decodeBorsh = fmap (AsStruct . productTypeTo) decodeBorsh  {-------------------------------------------------------------------------------   Derived functionality@@ -220,11 +267,8 @@   type StaticBorshSize Text = 'HasVariableSize   borshSize _ = SizeVariable -instance BorshSize [a] where-  -- Use generic defaults--instance BorshSize (Maybe a) where-  -- Use generic defaults+deriving via AsEnum [a]       instance BorshSize [a]+deriving via AsEnum (Maybe a) instance BorshSize (Maybe a)  instance BorshSize (Set a) where   type StaticBorshSize (Set a) = 'HasVariableSize@@ -243,6 +287,54 @@   borshSize _ = borshSizeSum (Proxy @xss)  {-------------------------------------------------------------------------------+  Maximum sizes+-------------------------------------------------------------------------------}++deriving via KnownImpliesMax Word8   instance BorshMaxSize Word8+deriving via KnownImpliesMax Word16  instance BorshMaxSize Word16+deriving via KnownImpliesMax Word32  instance BorshMaxSize Word32+deriving via KnownImpliesMax Word64  instance BorshMaxSize Word64+deriving via KnownImpliesMax Word128 instance BorshMaxSize Word128++deriving via KnownImpliesMax Int8   instance BorshMaxSize Int8+deriving via KnownImpliesMax Int16  instance BorshMaxSize Int16+deriving via KnownImpliesMax Int32  instance BorshMaxSize Int32+deriving via KnownImpliesMax Int64  instance BorshMaxSize Int64+deriving via KnownImpliesMax Int128 instance BorshMaxSize Int128++deriving via KnownImpliesMax Float  instance BorshMaxSize Float+deriving via KnownImpliesMax Double instance BorshMaxSize Double++instance ( KnownNat n+         , BorshMaxSize a+         ) => BorshMaxSize (FixedSizeArray n a) where+  borshMaxSize _ = fromIntegral (natVal (Proxy @n)) * borshMaxSize (Proxy @a)++deriving via AsEnum (Maybe a) instance BorshMaxSize a => BorshMaxSize (Maybe a)++instance (All2 BorshMaxSize xss, All SListI xss) => BorshMaxSize (SOP I xss) where+  borshMaxSize _ = aux . hcollapse $ sizes+    where+      aux :: [[Word32]] -> Word32+      aux [] = 1+      aux xs = 1 + maximum (map sum xs)++      borshMaxSize' :: forall a. (BorshMaxSize a) => K Word32 a+      borshMaxSize' = K $ borshMaxSize (Proxy @a)++      sizes :: POP (K Word32) xss+      sizes = hcpure (Proxy @BorshMaxSize) borshMaxSize'++instance (All BorshMaxSize xs) => BorshMaxSize (NP I xs) where+  borshMaxSize _ = sum . hcollapse $ sizes+    where+      borshMaxSize' :: forall a. (BorshMaxSize a) => K Word32 a+      borshMaxSize' = K $ borshMaxSize (Proxy @a)++      sizes :: NP (K Word32) xs+      sizes = hcpure (Proxy @BorshMaxSize) borshMaxSize'++{-------------------------------------------------------------------------------   ToBorsh instances -------------------------------------------------------------------------------} @@ -334,25 +426,32 @@  -- size 0 -deriving via Struct () instance BorshSize ()-deriving via Struct () instance ToBorsh   ()-deriving via Struct () instance FromBorsh ()+deriving via AsStruct () instance BorshSize    ()+deriving via AsStruct () instance BorshMaxSize ()+deriving via AsStruct () instance ToBorsh      ()+deriving via AsStruct () instance FromBorsh    ()  -- size 2 -deriving via Struct (a, b)+deriving via AsStruct (a, b)          instance               ( BorshSize a               , BorshSize b               )            => BorshSize (a, b)-deriving via Struct (a, b)+deriving via AsStruct (a, b)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              )+           => BorshMaxSize (a, b)+deriving via AsStruct (a, b)+         instance               ( ToBorsh a               , ToBorsh b               )            => ToBorsh (a, b)-deriving via Struct (a, b)+deriving via AsStruct (a, b)          instance               ( FromBorsh a               , FromBorsh b@@ -361,21 +460,28 @@  -- size 3 -deriving via Struct (a, b, c)+deriving via AsStruct (a, b, c)          instance               ( BorshSize a               , BorshSize b               , BorshSize c               )            => BorshSize (a, b, c)-deriving via Struct (a, b, c)+deriving via AsStruct (a, b, c)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              )+           => BorshMaxSize (a, b, c)+deriving via AsStruct (a, b, c)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c               )            => ToBorsh (a, b, c)-deriving via Struct (a, b, c)+deriving via AsStruct (a, b, c)          instance               ( FromBorsh a               , FromBorsh b@@ -385,7 +491,7 @@  -- size 4 -deriving via Struct (a, b, c, d)+deriving via AsStruct (a, b, c, d)          instance               ( BorshSize a               , BorshSize b@@ -393,15 +499,23 @@               , BorshSize d               )            => BorshSize (a, b, c, d)-deriving via Struct (a, b, c, d)+deriving via AsStruct (a, b, c, d)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              , BorshMaxSize d+              )+           => BorshMaxSize (a, b, c, d)+deriving via AsStruct (a, b, c, d)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c               , ToBorsh d               )            => ToBorsh (a, b, c, d)-deriving via Struct (a, b, c, d)+deriving via AsStruct (a, b, c, d)          instance               ( FromBorsh a               , FromBorsh b@@ -412,7 +526,7 @@  -- size 5 -deriving via Struct (a, b, c, d, e)+deriving via AsStruct (a, b, c, d, e)          instance               ( BorshSize a               , BorshSize b@@ -421,8 +535,17 @@               , BorshSize e               )            => BorshSize (a, b, c, d, e)-deriving via Struct (a, b, c, d, e)+deriving via AsStruct (a, b, c, d, e)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              , BorshMaxSize d+              , BorshMaxSize e+              )+           => BorshMaxSize (a, b, c, d, e)+deriving via AsStruct (a, b, c, d, e)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c@@ -430,7 +553,7 @@               , ToBorsh e               )            => ToBorsh (a, b, c, d, e)-deriving via Struct (a, b, c, d, e)+deriving via AsStruct (a, b, c, d, e)          instance               ( FromBorsh a               , FromBorsh b@@ -442,7 +565,7 @@  -- size 6 -deriving via Struct (a, b, c, d, e, f)+deriving via AsStruct (a, b, c, d, e, f)          instance               ( BorshSize a               , BorshSize b@@ -452,8 +575,18 @@               , BorshSize f               )            => BorshSize (a, b, c, d, e, f)-deriving via Struct (a, b, c, d, e, f)+deriving via AsStruct (a, b, c, d, e, f)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              , BorshMaxSize d+              , BorshMaxSize e+              , BorshMaxSize f+              )+           => BorshMaxSize (a, b, c, d, e, f)+deriving via AsStruct (a, b, c, d, e, f)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c@@ -462,7 +595,7 @@               , ToBorsh f               )            => ToBorsh (a, b, c, d, e, f)-deriving via Struct (a, b, c, d, e, f)+deriving via AsStruct (a, b, c, d, e, f)          instance               ( FromBorsh a               , FromBorsh b@@ -475,7 +608,7 @@  -- size 7 -deriving via Struct (a, b, c, d, e, f, g)+deriving via AsStruct (a, b, c, d, e, f, g)          instance               ( BorshSize a               , BorshSize b@@ -486,8 +619,19 @@               , BorshSize g               )            => BorshSize (a, b, c, d, e, f, g)-deriving via Struct (a, b, c, d, e, f, g)+deriving via AsStruct (a, b, c, d, e, f, g)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              , BorshMaxSize d+              , BorshMaxSize e+              , BorshMaxSize f+              , BorshMaxSize g+              )+           => BorshMaxSize (a, b, c, d, e, f, g)+deriving via AsStruct (a, b, c, d, e, f, g)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c@@ -497,7 +641,7 @@               , ToBorsh g               )            => ToBorsh (a, b, c, d, e, f, g)-deriving via Struct (a, b, c, d, e, f, g)+deriving via AsStruct (a, b, c, d, e, f, g)          instance               ( FromBorsh a               , FromBorsh b@@ -511,7 +655,7 @@  -- size 8 -deriving via Struct (a, b, c, d, e, f, g, h)+deriving via AsStruct (a, b, c, d, e, f, g, h)          instance               ( BorshSize a               , BorshSize b@@ -523,8 +667,20 @@               , BorshSize h               )            => BorshSize (a, b, c, d, e, f, g, h)-deriving via Struct (a, b, c, d, e, f, g, h)+deriving via AsStruct (a, b, c, d, e, f, g, h)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              , BorshMaxSize d+              , BorshMaxSize e+              , BorshMaxSize f+              , BorshMaxSize g+              , BorshMaxSize h+              )+           => BorshMaxSize (a, b, c, d, e, f, g, h)+deriving via AsStruct (a, b, c, d, e, f, g, h)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c@@ -535,7 +691,7 @@               , ToBorsh h               )            => ToBorsh (a, b, c, d, e, f, g, h)-deriving via Struct (a, b, c, d, e, f, g, h)+deriving via AsStruct (a, b, c, d, e, f, g, h)          instance               ( FromBorsh a               , FromBorsh b@@ -550,7 +706,7 @@  -- size 9 -deriving via Struct (a, b, c, d, e, f, g, h, i)+deriving via AsStruct (a, b, c, d, e, f, g, h, i)          instance               ( BorshSize a               , BorshSize b@@ -563,8 +719,21 @@               , BorshSize i               )            => BorshSize (a, b, c, d, e, f, g, h, i)-deriving via Struct (a, b, c, d, e, f, g, h, i)+deriving via AsStruct (a, b, c, d, e, f, g, h, i)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              , BorshMaxSize d+              , BorshMaxSize e+              , BorshMaxSize f+              , BorshMaxSize g+              , BorshMaxSize h+              , BorshMaxSize i+              )+           => BorshMaxSize (a, b, c, d, e, f, g, h, i)+deriving via AsStruct (a, b, c, d, e, f, g, h, i)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c@@ -576,7 +745,7 @@               , ToBorsh i               )            => ToBorsh (a, b, c, d, e, f, g, h, i)-deriving via Struct (a, b, c, d, e, f, g, h, i)+deriving via AsStruct (a, b, c, d, e, f, g, h, i)          instance               ( FromBorsh a               , FromBorsh b@@ -592,7 +761,7 @@  -- size 10 -deriving via Struct (a, b, c, d, e, f, g, h, i, j)+deriving via AsStruct (a, b, c, d, e, f, g, h, i, j)          instance               ( BorshSize a               , BorshSize b@@ -606,8 +775,22 @@               , BorshSize j               )            => BorshSize (a, b, c, d, e, f, g, h, i, j)-deriving via Struct (a, b, c, d, e, f, g, h, i, j)+deriving via AsStruct (a, b, c, d, e, f, g, h, i, j)          instance+              ( BorshMaxSize a+              , BorshMaxSize b+              , BorshMaxSize c+              , BorshMaxSize d+              , BorshMaxSize e+              , BorshMaxSize f+              , BorshMaxSize g+              , BorshMaxSize h+              , BorshMaxSize i+              , BorshMaxSize j+              )+           => BorshMaxSize (a, b, c, d, e, f, g, h, i, j)+deriving via AsStruct (a, b, c, d, e, f, g, h, i, j)+         instance               ( ToBorsh a               , ToBorsh b               , ToBorsh c@@ -620,7 +803,7 @@               , ToBorsh j               )            => ToBorsh (a, b, c, d, e, f, g, h, i, j)-deriving via Struct (a, b, c, d, e, f, g, h, i, j)+deriving via AsStruct (a, b, c, d, e, f, g, h, i, j)          instance               ( FromBorsh a               , FromBorsh b@@ -669,6 +852,8 @@   type StaticBorshSize Char = 'HasKnownSize   borshSize _ = SizeKnown 4 +deriving via KnownImpliesMax Char instance BorshMaxSize Char+ instance ToBorsh Char where   encodeBorsh = encodeChar @@ -681,6 +866,8 @@   type StaticBorshSize Bool = 'HasKnownSize   borshSize _ = SizeKnown 1 +deriving via KnownImpliesMax Bool instance BorshMaxSize Bool+ instance ToBorsh Bool where   encodeBorsh = encodeBool @@ -689,10 +876,22 @@  -- Either -deriving instance BorshSize (Either a b)-deriving instance (ToBorsh   a, ToBorsh   b) => ToBorsh   (Either a b)-deriving instance (FromBorsh a, FromBorsh b) => FromBorsh (Either a b)+deriving+  via AsEnum (Either a b)+  instance BorshSize (Either a b) +deriving+  via AsEnum (Either a b)+  instance (BorshMaxSize a, BorshMaxSize b) => BorshMaxSize (Either a b)++deriving+  via AsEnum (Either a b)+  instance (ToBorsh a, ToBorsh b) => ToBorsh (Either a b)++deriving+  via AsEnum (Either a b)+  instance (FromBorsh a, FromBorsh b) => FromBorsh (Either a b)+ {-------------------------------------------------------------------------------   Internal auxiliary: size of products and sums-of-products -------------------------------------------------------------------------------}@@ -749,7 +948,7 @@ instance All BorshSize xs => BorshSizeSum '[xs] where   borshSizeSum _ =     -- This assumes the presence of the constructor tag-    -- (see detailed discussion in 'Struct')+    -- (see detailed discussion in 'AsStruct')     case sizeOfProd (Proxy @xs) of       SizeKnown sz -> SizeKnown (sz + 1)       SizeVariable -> SizeVariable
src/Codec/Borsh/Incremental/Decoder.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP #-}+ {-# OPTIONS_GHC -Wno-incomplete-patterns #-}  module Codec.Borsh.Incremental.Decoder (@@ -16,9 +18,12 @@  import Control.Applicative import Control.Monad-import Control.Monad.Fail import Control.Monad.ST import Data.Word++#if !MIN_VERSION_base(4,13,0)+import Control.Monad.Fail+#endif  import qualified Data.ByteString      as S import qualified Data.ByteString.Lazy as L
test/Test/Codec/Borsh/ExampleType/BTree.hs view
@@ -15,18 +15,8 @@  -- | Binary trees data BTree a = BTip | BLeaf a | BNode (BTree a) (BTree a)-  deriving (-      Show-    , Eq-    , Ord-    , Functor-    , Foldable-    , Traversable-    , GHC.Generic-    , Generic-    , BorshSize-    , FromBorsh-    )+  deriving (Show, Eq, Ord, Functor, Foldable, Traversable, GHC.Generic, Generic)+  deriving (BorshSize, FromBorsh) via AsEnum (BTree a)  -- Manual ToBorsh instance as a sort of "golden" test for the derived FromBorsh -- instance
test/Test/Codec/Borsh/ExampleType/NTree.hs view
@@ -15,18 +15,9 @@  -- | N-ary trees data NTree a = NLeaf | NNode a [NTree a]-  deriving (-      Show-    , Eq-    , Ord-    , Functor-    , Foldable-    , Traversable-    , GHC.Generic-    , Generic-    , BorshSize-    , ToBorsh-    )+  deriving (Show, Eq, Ord, Functor, Foldable, Traversable, GHC.Generic, Generic)+  deriving (BorshSize, ToBorsh) via AsEnum (NTree a)+  -- Manual FromBorsh instance as a sort of "golden" test for the derived ToBorsh -- instance instance FromBorsh a => FromBorsh (NTree a) where
test/Test/Codec/Borsh/ExampleType/SimpleStructs.hs view
@@ -19,7 +19,11 @@  data PolyStruct a = Poly a a a   deriving (Show, Eq, Ord, GHC.Generic, Generic)-  deriving (BorshSize, ToBorsh, FromBorsh) via Struct (PolyStruct a)+  deriving ( BorshSize+           , BorshMaxSize+           , ToBorsh+           , FromBorsh+           ) via AsStruct (PolyStruct a)  instance Arbitrary a => Arbitrary (PolyStruct a) where   arbitrary = Poly <$> arbitrary <*> arbitrary <*> arbitrary@@ -31,7 +35,11 @@  data SimpleStruct1 = Struct1 Word8 () Word64   deriving (Show, Eq, Ord, GHC.Generic, Generic)-  deriving (BorshSize, ToBorsh, FromBorsh) via Struct SimpleStruct1+  deriving ( BorshSize+           , BorshMaxSize+           , ToBorsh+           , FromBorsh+           ) via AsStruct SimpleStruct1  instance Arbitrary SimpleStruct1 where   arbitrary = Struct1 <$> arbitrary <*> arbitrary <*> arbitrary@@ -48,7 +56,7 @@  data SimpleStruct2 = Struct2 () SimpleStruct1 Word16   deriving (Show, Eq, Ord, GHC.Generic, Generic)-  deriving (ToBorsh, FromBorsh) via Struct SimpleStruct2+  deriving (BorshMaxSize, ToBorsh, FromBorsh) via AsStruct SimpleStruct2  instance BorshSize SimpleStruct2 where   type StaticBorshSize SimpleStruct2 = 'HasKnownSize
test/Test/Codec/Borsh/Size.hs view
@@ -1,6 +1,7 @@ module Test.Codec.Borsh.Size (tests) where  import Data.Proxy+import Data.SOP.Dict import Test.Tasty import Test.Tasty.QuickCheck @@ -9,10 +10,12 @@ import Codec.Borsh  import Test.Codec.Borsh.Util.RandomType+import Test.Codec.Borsh.Util.QuickCheck  tests :: TestTree tests = testGroup "Test.Codec.Borsh.Size" [-      testProperty "size" test_size+      testProperty "size"    test_size+    , testProperty "maxSize" test_maxSize     ]  test_size :: SomeBorshValue -> Property@@ -24,5 +27,18 @@         case borshSize (Proxy @a) of           SizeVariable -> label "Trivial" $ True           SizeKnown n  -> L.length (serialiseBorsh val) === fromIntegral n+++test_maxSize :: SomeBorshValue -> Property+test_maxSize =+    \(SomeValue typ val) -> aux typ val+  where+    aux :: forall a. ToBorsh a => BorshType a -> a -> Property+    aux typ val =+        case borshTypeMaxSize typ of+          Nothing   -> label "Trivial" $ True+          Just Dict ->+                       L.length (serialiseBorsh val)+            `assertLE` fromIntegral (borshMaxSize (Proxy @a))  
test/Test/Codec/Borsh/Util/QuickCheck.hs view
@@ -5,6 +5,8 @@     -- * Generators   , split2   , splitN+    -- * Assertions+  , assertLE   ) where  import Control.Monad@@ -49,3 +51,13 @@         (xs',y:ys) ->           return $ xs' ++ (x:y):ys +{-------------------------------------------------------------------------------+  Assertions+-------------------------------------------------------------------------------}++assertLE :: (Show a, Ord a) => a -> a -> Property+assertLE x y =+  if x <= y then+    property True+  else+    counterexample (show y ++ " > " ++ show x) $ property False
test/Test/Codec/Borsh/Util/RandomType.hs view
@@ -1,16 +1,15 @@ -- 11 iterations needed for GHC 9.2.2 {-# OPTIONS_GHC -fconstraint-solver-iterations=11 #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}  module Test.Codec.Borsh.Util.RandomType (     -- * Types     BorshType(..)   , SomeBorshType(..)+  , borshTypeMaxSize+     -- * Values of those types   , SomeBorshValue(..)--  -- TODO remove these-  , arbitraryValue-  , arbitraryType   ) where  import Control.Monad@@ -327,6 +326,7 @@   BtEnum ::        ( All2 CanTest (xs ': xss)        , All (Compose Show (NP BorshType)) (xs ': xss)+       , All SListI (xs ': xss)        )     => -- POP: For every constructor, and every argument to every constructor,        -- what is the type of that argument?@@ -359,6 +359,61 @@   SomeType :: CanTest a => BorshType a -> SomeBorshType  deriving instance Show SomeBorshType++{-------------------------------------------------------------------------------+  Maximum size+-------------------------------------------------------------------------------}++borshTypeMaxSize :: BorshType a -> Maybe (Dict BorshMaxSize a)+borshTypeMaxSize = \case+    BtSimple bt -> borshSimpleTypeMaxSize bt+    BtArray _ bt -> do+      Dict <- borshTypeMaxSize bt+      return Dict+    BtVec _ -> Nothing+    BtOption bt -> do+      Dict <- borshTypeMaxSize bt+      return Dict+    BtHashSet _ -> Nothing+    BtHashMap _ _ -> Nothing+    BtStruct xs -> do+      Dict <- fmap all_NP . hsequence' $ hmap (Comp . borshTypeMaxSize) xs+      return Dict+    BtEnum xss -> do+      Dict <- fmap all_POP . hsequence' $ hmap (Comp . borshTypeMaxSize) xss+      return Dict+    BtBTree _ -> Nothing+    BtNTree _ -> Nothing+    BtPolyStruct bt -> do+      Dict <- borshTypeMaxSize bt+      return Dict+    BtEither bt1 bt2 -> do+      Dict <- borshTypeMaxSize bt1+      Dict <- borshTypeMaxSize bt2+      return Dict++borshSimpleTypeMaxSize :: BorshSimpleType a -> Maybe (Dict BorshMaxSize a)+borshSimpleTypeMaxSize = \case+    BtU8            -> Just Dict+    BtU16           -> Just Dict+    BtU32           -> Just Dict+    BtU64           -> Just Dict+    BtU128          -> Just Dict+    BtI8            -> Just Dict+    BtI16           -> Just Dict+    BtI32           -> Just Dict+    BtI64           -> Just Dict+    BtI128          -> Just Dict+    BtF32           -> Just Dict+    BtF64           -> Just Dict+    BtText          -> Nothing+    BtUnit          -> Just Dict+    BtSimpleList    -> Nothing+    BtSimpleStruct1 -> Just Dict+    BtSimpleStruct2 -> Just Dict+    BtByteString    -> Nothing+    BtChar          -> Just Dict+    BtBool          -> Just Dict  {-------------------------------------------------------------------------------   Shrinking types