packages feed

flat 0.5.2 → 0.6

raw patch · 23 files changed

+482/−272 lines, 23 filesdep ~semigroupsPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: semigroups

API changes (from Hackage documentation)

- Flat.Class: SizeOf :: NumBits -> SizeOf a
- Flat.Class: instance (Flat.Class.GFlatSize (GHC.Generics.Rep a), Flat.Class.GFlatDecode (GHC.Generics.Rep a)) => Flat.Class.Flat (Flat.Class.SizeOf a)
- Flat.Class: instance GHC.Show.Show (Flat.Class.SizeOf a)
- Flat.Class: newtype SizeOf a
- Flat.Repr: Repr :: ByteString -> Repr a
- Flat.Repr: [repr] :: Repr a -> ByteString
- Flat.Repr: instance Flat.Class.Flat a => Flat.Class.Flat (Flat.Repr.Repr a)
- Flat.Repr: instance GHC.Show.Show (Flat.Repr.Repr a)
- Flat.Repr: newtype Repr a
- Flat.Repr: unrepr :: Flat a => Repr a -> a
+ Flat.AsBin: data AsBin a
+ Flat.AsBin: instance Flat.Class.Flat a => Flat.Class.Flat (Flat.AsBin.AsBin a)
+ Flat.AsBin: instance Flat.Class.Flat a => Text.PrettyPrint.HughesPJClass.Pretty (Flat.AsBin.AsBin a)
+ Flat.AsBin: instance GHC.Show.Show (Flat.AsBin.AsBin a)
+ Flat.AsBin: unbin :: Flat a => AsBin a -> a
+ Flat.AsSize: AsSize :: NumBits -> AsSize a
+ Flat.AsSize: instance Flat.Class.Flat a => Flat.Class.Flat (Flat.AsSize.AsSize a)
+ Flat.AsSize: instance GHC.Classes.Eq (Flat.AsSize.AsSize a)
+ Flat.AsSize: instance GHC.Classes.Ord (Flat.AsSize.AsSize a)
+ Flat.AsSize: instance GHC.Show.Show (Flat.AsSize.AsSize a)
+ Flat.AsSize: newtype AsSize a
+ Flat.Decoder.Prim: binOf :: Get a -> Get (ByteString, Int)
+ Flat.Decoder.Prim: sizeOf :: Get a -> Get Int
+ Flat.Memory: peekByteString :: Ptr Word8 -> Int -> ByteString
+ Flat.Run: unflatRawWithOffset :: AsByteString b => Get a -> b -> NumBits -> Decoded a
- Flat.Decoder: strictDecoder :: Get a -> ByteString -> Either DecodeException a
+ Flat.Decoder: strictDecoder :: Get a -> ByteString -> Int -> Either DecodeException a
- Flat.Decoder.Run: strictDecoder :: Get a -> ByteString -> Either DecodeException a
+ Flat.Decoder.Run: strictDecoder :: Get a -> ByteString -> Int -> Either DecodeException a

Files

CHANGELOG view
@@ -1,5 +1,11 @@ Significant and compatibility-breaking changes. ++Version 0.6:+    - [**breaking**] Renamed Repr to AsBin and SizeOf to AsSize+    - Faster AsBin implementation +    - Fixed AsSize implementation (SizeOf worked only for types with custom size implementation and returned max size, not actual size)+ Version 0.5.2:     - Fixed https://github.com/Quid2/flat/issues/28 that could cause an undetected overflow when decoding out of range Int/Word values     - Added UTF16Text and Data.ByteString.Short support for ghcjs
README.md view
@@ -78,10 +78,11 @@  Tested with: -* [GHC](https://www.haskell.org/ghc/) 7.10.3 to 9.4.2 (x64)+* [GHC](https://www.haskell.org/ghc/) 7.10.3 to 9.4.3 (x64)   * [GHCJS](https://github.com/ghcjs/ghcjs) version 8.6.0.1 (GHC 8.6.2) +   ### Known Bugs and Infelicities
flat.cabal view
@@ -1,16 +1,29 @@ cabal-version:      >=1.10 name:               flat-version:            0.5.2+version:            0.6 homepage:           http://quid2.org synopsis:           Principled and efficient bit-oriented binary serialization.-description:        Reference implementation of `flat`, a principled and efficient binary serialization format.+description:+  Reference implementation of `flat`, a principled and efficient binary serialization format.+ category:           Data,Parsing,Serialization license:            BSD3 license-file:       LICENSE copyright:          Copyright: (c) 2016-2022 Pasqualino `Titto` Assini maintainer:         tittoassini@gmail.com author:             Pasqualino `Titto` Assini-tested-with:        GHC ==7.10.3 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.4 || ==9.4.2+tested-with:+  GHC ==7.10.3+   || ==8.0.2+   || ==8.2.2+   || ==8.4.4+   || ==8.6.5+   || ==8.8.4+   || ==8.10.7+   || ==9.0.2+   || ==9.2.4+   || ==9.4.3+ build-type:         Simple extra-source-files:   stack.yaml@@ -27,6 +40,8 @@     Data.FloatCast     Data.ZigZag     Flat+    Flat.AsBin+    Flat.AsSize     Flat.Bits     Flat.Class     Flat.Decoder@@ -56,7 +71,6 @@     Flat.Instances.Vector     Flat.Memory     Flat.Run-    Flat.Repr     Flat.Tutorial     Flat.Types @@ -84,11 +98,12 @@   ghc-options:     -Wall -O2 -funbox-strict-fields -fno-warn-orphans     -fno-warn-name-shadowing-    -- -Werror -    -- Stan options-    -- -fwrite-ide-info -hiedir=.hie+  -- -Werror +  -- Stan options+  -- -fwrite-ide-info -hiedir=.hie+   if impl(eta -any)     build-depends:         array                 ==0.5.2.0@@ -120,32 +135,34 @@       , deepseq               >=1.4       , dlist                 >=0.6       , ghc-prim+      , list-t                >1       , mono-traversable       , pretty                >=1.1.2       , primitive       , text       , unordered-containers       , vector-      , list-t > 1-  +   if impl(ghc <8)-    build-depends: -      semigroups < 0.19-      , hashable              >=1.2.4.0  && <=1.2.7.0-  else -    build-depends: hashable >= 1.4.0.1+    build-depends:+        hashable    >=1.2.4.0 && <=1.2.7.0+      , semigroups  >=0       && <0.19 +  else+    build-depends: hashable >=1.4.0.1+ test-suite spec   type:             exitcode-stdio-1.0   main-is:          Spec.hs   cpp-options:      -DLIST_BIT -DTEST_DECBITS    -- if impl(ghc <8.6)-  cpp-options: -DENUM_LARGE +  cpp-options:      -DENUM_LARGE    -- -DETA_VERSION -Dghcjs_HOST_OS -  ghc-options: -O0+  ghc-options:      -O0+   if impl(ghc >8)     ghc-options:       -Wno-unused-top-binds -Wno-type-defaults -Wno-missing-signatures@@ -173,7 +190,7 @@     , text    if impl(ghc <8)-    build-depends: semigroups < 0.19+    build-depends: semigroups <0.19    if impl(eta -any)     build-depends:@@ -196,9 +213,9 @@       , deepseq       , filepath       , mono-traversable+      , QuickCheck        >=2.14.2       , tasty       , text-      , QuickCheck >= 2.14.2   -- dynamic doctests and generation of static doctests -- Usable only with recent versions of ghc (no ghcjs or eta)@@ -211,10 +228,10 @@ --   build-depends: --       base --     , directory---     , doctest    ==0.16.3.1---     , filemanip  >=0.3.6.3+--     , doctest     ==0.16.3.1+--     , filemanip   >=0.3.6.3+--     , QuickCheck  >=2.14.2 --     , text---     , QuickCheck >= 2.14.2   -- static doctests (faster, useful for test coverage and to test ghcjs and eta) test-suite doc-static@@ -225,22 +242,23 @@     DocTest     DocTest.Data.FloatCast     DocTest.Data.ZigZag+    DocTest.Flat.AsBin+    DocTest.Flat.AsSize     DocTest.Flat.Bits     DocTest.Flat.Decoder.Prim+    DocTest.Flat.Encoder.Prim     DocTest.Flat.Endian-    DocTest.Flat.Repr     DocTest.Flat.Instances.Array     DocTest.Flat.Instances.Base     DocTest.Flat.Instances.ByteString     DocTest.Flat.Instances.Containers     DocTest.Flat.Instances.DList+    DocTest.Flat.Instances.Extra     DocTest.Flat.Instances.Mono     DocTest.Flat.Instances.Text     DocTest.Flat.Instances.Unordered     DocTest.Flat.Instances.Vector     DocTest.Flat.Tutorial-    DocTest.Flat.Encoder.Prim-    DocTest.Flat.Instances.Extra    default-language: Haskell2010   build-depends:@@ -251,31 +269,31 @@     , dlist     , flat     , pretty+    , QuickCheck            >=2.14.2     , tasty     , tasty-hunit     , tasty-quickcheck     , text     , unordered-containers     , vector-    , QuickCheck >= 2.14.2     if impl(ghc <8)     build-depends: semigroups <0.19 --- Test for Flat.Repr-test-suite repr+-- Test for Flat.AsBin Flat.AsSize and listTDecoder+test-suite big   type:             exitcode-stdio-1.0-  main-is:          FlatRepr.hs+  main-is:          Big.hs   hs-source-dirs:   test   default-language: Haskell2010   build-depends:       base     , bytestring     , flat-    , timeit     , list-t+    , timeit -  ghc-options: -rtsopts+  ghc-options:      -rtsopts  -- test-suite text --   type:             exitcode-stdio-1.0
src/Flat.hs view
@@ -11,9 +11,11 @@   ) where +import           Flat.AsBin     as X+import           Flat.AsSize    as X import           Flat.Class import           Flat.Decoder import           Flat.Filler-import           Flat.Instances                as X-import           Flat.Run                      as X-import           Flat.Types                     ( )+import           Flat.Instances as X+import           Flat.Run       as X+import           Flat.Types     ()
+ src/Flat/AsBin.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE InstanceSigs              #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE ScopedTypeVariables       #-}++{- | Wrapper type to decode a value to its flat serialisation.++See <../test/Big.hs> for an example of use.++See also 'Flat.Decoder.listTDecoder' and "Flat.AsSize" for other ways to handle large decoded values.++In 0.5.X this type was called @Repr@.++@since 0.6+-}+module Flat.AsBin(AsBin,unbin) where++import qualified Data.ByteString                as B+import           Flat.Bits                      (bits, fromBools, toBools)+import           Flat.Class                     (Flat (..))+import           Flat.Decoder.Prim              (binOf)+import           Flat.Decoder.Types             (Get (Get, runGet),+                                                 GetResult (GetResult),+                                                 S (S, currPtr, usedBits))+import           Flat.Run                       (unflatRawWithOffset)+import           Foreign                        (plusPtr)+import           Text.PrettyPrint.HughesPJClass (Doc, Pretty (pPrint),+                                                 prettyShow, text)++-- $setup+-- >>> :set -XScopedTypeVariables+-- >>> import Flat.Instances.Base+-- >>> import Flat.Instances.Text+-- >>> import Flat.Decoder.Types+-- >>> import Flat.Types+-- >>> import Flat.Run+-- >>> import Data.Word+-- >>> import qualified Data.Text as T+-- >>> import Text.PrettyPrint.HughesPJClass++{- |++When the flat serialisation of a value takes a lot less memory than the value itself, it can be convenient to keep the value in its encoded representation and decode it on demand.++To do so, just decode a value `a` as a `AsBin a`.++Examples:++Encode a list of Ints and then decode it to a list of AsBin Int:++>>> unflat (flat [1::Int .. 3]) :: Decoded ([AsBin Int])+Right [AsBin {repr = "\129A", offsetBits = 1},AsBin {repr = "A ", offsetBits = 2},AsBin {repr = " \193", offsetBits = 3}]++To decode an `AsBin a` to an `a`, use `unbin`:++>>> unbin <$> (unflat (flat 'a') :: Decoded (AsBin Char))+Right 'a'++Keep the values of a list of Ints encoded and decode just one on demand:++>>> let Right l :: Decoded [AsBin Int] = unflat (flat [1..5]) in unbin (l  !! 2)+3++Show exactly how values are encoded:++>>> let Right t :: Decoded (AsBin Bool,AsBin Word8,AsBin Bool) = unflat (flat (False,3:: Word64,True)) in prettyShow t+"(0, _0000001 1, _1)"++Ten bits in total spread over two bytes:++@+0+_0000001 1+         _1+=+00000001 11+@++Tests:++>>> unflat (flat ()) :: Decoded (AsBin ())+Right (AsBin {repr = "", offsetBits = 0})++>>> unflat (flat (False,True)) :: Decoded (Bool,AsBin Bool)+Right (False,AsBin {repr = "A", offsetBits = 1})++>>> unflat (flat (False,False,255 :: Word8)) :: Decoded (Bool,Bool,AsBin Word8)+Right (False,False,AsBin {repr = "?\193", offsetBits = 2})++>>> let Right (b0,b1,rw,b3) :: Decoded (Bool,Bool,AsBin Word8,Bool) = unflat (flat (False,False,255 :: Word8,True)) in (b0,b1,unbin rw,b3)+(False,False,255,True)+-}++data AsBin a = AsBin {+    repr        :: B.ByteString -- ^ Flat encoding of the value (encoding starts after offset bits in the first byte and ends in an unspecified position in the last byte)+    ,offsetBits :: Int -- ^ First byte offset: number of unused most significant bits in the first byte+    } deriving Show++instance Flat a => Pretty (AsBin a) where+    pPrint :: AsBin a -> Doc+    pPrint r = let n = replicate (offsetBits r) in text $ n '_' ++  (drop (offsetBits r) . prettyShow . fromBools . (n False ++) . toBools . bits $ unbin r)++-- | Decode a value+unbin :: Flat a => AsBin a -> a+unbin a =+    case unflatRawWithOffset dec (repr a) (offsetBits a) of+        Right a -> a+        Left e  -> error (show e) -- impossible, as it is a valid encoding+    where+        dec = Get $ \end s -> do+          GetResult s' a <- runGet decode end s+          let s'' = S (currPtr s' `plusPtr` if usedBits s' == 0 then 0 else 1) 0+          return $ GetResult s'' a++instance Flat a => Flat (AsBin a) where+    size = error "unused"++    encode = error "unused"++    decode :: Flat a => Get (AsBin a)+    decode = uncurry AsBin <$> binOf (decode :: Get a)
+ src/Flat/AsSize.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE InstanceSigs              #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE ScopedTypeVariables       #-}++{- |+Wrapper type to decode a value to its size in bits.++See also "Flat.AsBin".++In 0.5.X this type was called @SizeOf@.++@since 0.6+-}+module Flat.AsSize(AsSize(..)) where++import           Flat.Class         (Flat (..))+import           Flat.Decoder.Prim  (sizeOf)+import           Flat.Decoder.Types (Get)+import           Flat.Types         (NumBits)++-- $setup+-- >>> :set -XScopedTypeVariables+-- >>> import Flat.Instances.Base+-- >>> import Flat.Instances.Text+-- >>> import Flat.Decoder.Types+-- >>> import Flat.Types+-- >>> import Flat.Run+-- >>> import Data.Word+-- >>> import qualified Data.Text as T++{- |+Useful to skip unnecessary values and to check encoding sizes.++Examples:++Ignore the second and fourth component of a tuple:++>>> let v = flat ('a',"abc",'z',True) in unflat v :: Decoded (Char,AsSize String,Char,AsSize Bool)+Right ('a',AsSize 28,'z',AsSize 1)++Notice the variable size encoding of Words:++>>> unflat (flat (1::Word16,1::Word64)) :: Decoded (AsSize Word16,AsSize Word64)+Right (AsSize 8,AsSize 8)++Text:++>>> unflat (flat (T.pack "",T.pack "a",T.pack "主",UTF8Text $ T.pack "主",UTF16Text $ T.pack "主",UTF16Text $ T.pack "a")) :: Decoded (AsSize T.Text,AsSize T.Text,AsSize T.Text,AsSize UTF8Text,AsSize UTF16Text,AsSize UTF16Text)+Right (AsSize 16,AsSize 32,AsSize 48,AsSize 48,AsSize 40,AsSize 40)++Various encodings:++>>> unflat (flat (False,[T.pack "",T.pack "a",T.pack "主"],'a')) :: Decoded (AsSize Bool,AsSize [T.Text],AsSize Char)+Right (AsSize 1,AsSize 96,AsSize 8)+-}+newtype AsSize a = AsSize NumBits deriving (Eq,Ord,Show)++instance Flat a => Flat (AsSize a) where+    size :: Flat a => AsSize a -> NumBits -> NumBits+    size = error "unused"++    encode = error "unused"++    decode :: Flat a => Get (AsSize a)+    decode = AsSize <$> sizeOf (decode :: Get a)
src/Flat/Class.hs view
@@ -21,7 +21,6 @@   , getSize   , module GHC.Generics   , GFlatEncode,GFlatDecode,GFlatSize-  , SizeOf(..)   ) where @@ -31,7 +30,6 @@                                      consClose, consOpen, dBool) import           Flat.Decoder.Types (Get) import           Flat.Encoder       (Encoding, NumBits, eBits16, mempty)-import           GHC.Base           (Any) import           GHC.Generics import           GHC.TypeLits       (Nat, type (+), type (<=)) import           Prelude            hiding (mempty)@@ -102,21 +100,6 @@     {-# NOINLINE decode #-}     {-# NOINLINE encode #-} #endif---- | Skip a value, return its size in bits-skip :: forall a. (GFlatSize (Rep a),GFlatDecode (Rep a)) => Get (SizeOf a)-skip = SizeOf . (gsize 0 :: Rep a Any -> NumBits) <$> (gget :: Get (Rep a Any))-{-# INLINE skip #-}---- | Decode to the size in bits of a value rather than to the value itself (see "Flat.Repr")-newtype SizeOf a = SizeOf NumBits deriving Show--instance (GFlatSize (Rep a),GFlatDecode (Rep a)) => Flat (SizeOf a) where-    size = error "unused"-    encode = error "unused"--    decode = skip-  -- |Generic Encoder class GFlatEncode f where gencode :: f a -> Encoding
src/Flat/Decoder/Prim.hs view
@@ -22,7 +22,9 @@     dLazyByteString_,     dByteArray_, -    ConsState(..),consOpen,consClose,consBool,consBits+    ConsState(..),consOpen,consClose,consBool,consBits,++    sizeOf,binOf     ) where  import           Control.Monad        (when)@@ -30,11 +32,13 @@ import qualified Data.ByteString.Lazy as L import           Data.FloatCast       (wordToDouble, wordToFloat) import           Data.Word            (Word16, Word32, Word64, Word8)-import           Flat.Decoder.Types   (Get (Get), GetResult (..), S (..),-                                       badEncoding, badOp, notEnoughSpace)+import           Flat.Decoder.Types   (Get (Get, runGet), GetResult (..),+                                       S (..), badEncoding, badOp,+                                       notEnoughSpace) import           Flat.Endian          (toBE16, toBE32, toBE64) import           Flat.Memory          (ByteArray, chunksToByteArray,-                                       chunksToByteString, minusPtr)+                                       chunksToByteString, minusPtr,+                                       peekByteString) import           Foreign              (Bits (unsafeShiftL, unsafeShiftR, (.&.), (.|.)),                                        FiniteBits (finiteBitSize), Ptr,                                        Storable (peek), castPtr, plusPtr,@@ -410,3 +414,26 @@    when (usedBits s /=0) $ badEncoding endPtr s "usedBits /= 0"    (currPtr',ns) <- getChunks (currPtr s) id    return $ GetResult (s {currPtr=currPtr'}) (currPtr s `plusPtr` 1,ns)++{- | Given a value's decoder, returns the size in bits of the encoded value++@since 0.6+-}+sizeOf :: Get a -> Get Int+sizeOf g =+    Get $ \end s -> do+      GetResult s' _ <- runGet g end s+      return $ GetResult s' $ (currPtr s' `minusPtr` currPtr s) * 8 - usedBits s + usedBits s'++{- | Given a value's decoder, returns the value's bit encoding.++The encoding starts at the returned bit position in the return bytestring's first byte+and ends in an unspecified bit position in its final byte++@since 0.6+-}+binOf :: Get a -> Get (B.ByteString,Int)+binOf g =+    Get $ \end s -> do+      GetResult s' _ <- runGet g end s+      return $ GetResult s' (peekByteString (currPtr s) (currPtr s' `minusPtr` currPtr s + if usedBits s' == 0 then 0 else 1),usedBits s)
src/Flat/Decoder/Run.hs view
@@ -10,10 +10,10 @@ import           ListT                    (ListT (..)) import           System.IO.Unsafe         (unsafePerformIO) --- | Given a decoder and an input buffer returns either the decoded value or an error  (if the input buffer is not fully consumed)-strictDecoder :: Get a -> B.ByteString -> Either DecodeException a-strictDecoder get bs =-  strictDecoder_ get bs $ \(GetResult s'@(S ptr' o') a) endPtr ->+-- | Given a decoder and an input buffer returns either the decoded value or an error (if the input buffer is not fully consumed)+strictDecoder :: Get a -> B.ByteString -> Int -> Either DecodeException a+strictDecoder get bs usedBits=+  strictDecoder_ get bs usedBits $ \(GetResult s'@(S ptr' o') a) endPtr ->     if ptr' /= endPtr || o' /= 0       then tooMuchSpace endPtr s'       else return a@@ -22,14 +22,15 @@      Exception e   => Get a1   -> BS.ByteString+  -> Int   -> (GetResult a1 -> Ptr b -> IO a)   -> Either e a-strictDecoder_ get (BS.PS base off len) check =+strictDecoder_ get (BS.PS base off len) usedBits check =   unsafePerformIO . try $   withForeignPtr base $ \base0 ->     let ptr = base0 `plusPtr` off         endPtr = ptr `plusPtr` len-     in do res <- runGet get endPtr (S ptr 0)+     in do res <- runGet get endPtr (S ptr usedBits)            check res endPtr {-# NOINLINE strictDecoder_ #-} @@ -43,12 +44,14 @@ --       GetResult (S ptr' o') a <- runGet get endPtr (S ptr 0) --       return (a, BS.PS base (ptr' `minusPtr` base0) (endPtr `minusPtr` ptr'), o') -{-| +{-| Decode a list of values, one value at a time.  Useful in case that the decoded values takes a lot more memory than the encoded ones. -See test/FlatRepr.hs for a test and an example of use.+See <../test/Big.hs> for a test and an example of use.++See also "Flat.AsBin".  @since 0.5 -}
src/Flat/Instances/Mono.hs view
@@ -168,6 +168,12 @@ decodeList :: (IsSequence b, Flat (Element b)) => Get b decodeList = S.fromList <$> decodeListWith decode +{-|+Sets are saved as lists of values.++>>> tstBits $ AsSet (Data.Set.fromList ([False,True,False]::[Bool]))+(True,5,"10110")+-} newtype AsSet a =   AsSet     { unSet :: a
src/Flat/Memory.hs view
@@ -15,29 +15,25 @@   , pokeByteString   , unsafeCreateUptoN'   , minusPtr-  --, peekByteString+  , peekByteString   ) where -import Control.Monad ( foldM_, when )-import           Control.Monad.Primitive        ( PrimMonad(..) )-import qualified Data.ByteString.Internal      as BS-import           Data.Primitive.ByteArray       ( MutableByteArray(..)-                                                , ByteArray#-                                                , ByteArray-                                                , newByteArray-                                                , unsafeFreezeByteArray-                                                )-import Foreign ( Word8, Ptr, withForeignPtr, minusPtr, plusPtr )-import           GHC.Prim                       ( copyAddrToByteArray#-                                                , copyByteArrayToAddr#-                                                )-import           GHC.Ptr                        ( Ptr(..) )-import           GHC.Types                      ( IO(..)-                                                , Int(..)-                                                )-import System.IO.Unsafe ( unsafeDupablePerformIO, unsafePerformIO )-import qualified Data.ByteString               as B+import           Control.Monad            (foldM_, when)+import           Control.Monad.Primitive  (PrimMonad (..))+import qualified Data.ByteString          as B+import qualified Data.ByteString.Internal as BS+import           Data.Primitive.ByteArray (ByteArray, ByteArray#,+                                           MutableByteArray (..), newByteArray,+                                           unsafeFreezeByteArray)+import           Foreign                  (Ptr, Word8, minusPtr, plusPtr,+                                           withForeignPtr)+import           GHC.Prim                 (copyAddrToByteArray#,+                                           copyByteArrayToAddr#)+import           GHC.Ptr                  (Ptr (..))+import           GHC.Types                (IO (..), Int (..))+import           System.IO.Unsafe         (unsafeDupablePerformIO,+                                           unsafePerformIO)  unsafeCreateUptoN' :: Int -> (Ptr Word8 -> IO (Int, a)) -> (BS.ByteString, a) unsafeCreateUptoN' l f = unsafeDupablePerformIO (createUptoN' l f)@@ -65,10 +61,16 @@       sourceLength     return (destPointer `plusPtr` sourceLength) --- Create a new bytestring, copying from sourcePtr sourceLength number of bytes--- peekByteString :: Ptr Word8 -> Int -> BS.ByteString--- peekByteString sourcePtr sourceLength = BS.unsafeCreate sourceLength $ \destPointer -> BS.memcpy destPointer sourcePtr sourceLength+{-| Create a new bytestring, copying sourceLen bytes from sourcePtr +@since 0.6+-}+peekByteString ::+  Ptr Word8 -- ^ sourcePtr+  -> Int -- ^ sourceLen+  -> BS.ByteString+peekByteString sourcePtr sourceLength = BS.unsafeCreate sourceLength $ \destPointer -> BS.memcpy destPointer sourcePtr sourceLength+ -- |Copy ByteArray to given pointer, returns new pointer pokeByteArray :: ByteArray# -> Int -> Int -> Ptr Word8 -> IO (Ptr Word8) pokeByteArray sourceArr sourceOffset len dest = do@@ -115,7 +117,7 @@   -- | Wrapper around @copyAddrToByteArray#@ primop.--- +-- -- Copied from the store-core package copyAddrToByteArray   :: Ptr a -> MutableByteArray (PrimState IO) -> Int -> Int -> IO ()
− src/Flat/Repr.hs
@@ -1,62 +0,0 @@-{-# LANGUAGE InstanceSigs        #-}-{-# LANGUAGE ScopedTypeVariables #-}-module Flat.Repr where--import qualified Data.ByteString    as B-import           Flat.Class         (Flat (..))-import           Flat.Decoder.Types (Get)-import           Flat.Run           (flat, unflat)---- $setup--- >>> :set -XScopedTypeVariables--- >>> import Flat.Instances.Base--- >>> import Flat.Decoder.Types--- >>> import Flat.Types--- >>> import Flat.Run--- >>> import Flat.Class--{- | Flat representation of a value--== Repr -It is occasionally useful to keep a decoded value, or part of it, in its encoded binary representation and decode it later on demand.--To do so, just decode a value `a` to a `Repr a`.--For example, we encode a list of Ints and then decode it to a list of Repr Int:-->>> unflat (flat [1::Int .. 5]) :: Decoded ([Repr Int])-Right [Repr {repr = "\STX\SOH"},Repr {repr = "\EOT\SOH"},Repr {repr = "\ACK\SOH"},Repr {repr = "\b\SOH"},Repr {repr = "\n\SOH"}]--To decode a `Repr a` to an `a`, we use `unrepr`:-->>> let Right l = unflat (flat [1..5]) :: Decoded [Repr Int] in unrepr (l  !! 2)-3--See "test/FlatRepr.hs" for a test and a longer example of use.--== SizeOf-If a decoded value is not required, it can be skipped completely using `SizeOf a`.--For example, to ignore the second and fourth component of the following tuple, it can be decoded as:-->>> let v = flat ('a',"abc",'z',True) in unflat v :: Decoded (Char,SizeOf String,Char,SizeOf Bool)-Right ('a',SizeOf 28,'z',SizeOf 1)--The unused values have not been decoded and instead their size (in bits) is returned.--}--newtype Repr a = Repr {repr :: B.ByteString} deriving Show---- Get the underlying value-unrepr :: Flat a => Repr a -> a-unrepr (Repr bs)=-    case unflat bs of-        Right a -> a-        Left _  -> error "impossible"--instance Flat a => Flat (Repr a) where-    size = error "unused"-    encode = error "unused"--    -- To create the representation we just re 'flat' the parsed value (this could be optimised by copying directly the parsed representation)-    decode = Repr . flat <$> (decode :: Get a)
src/Flat/Run.hs view
@@ -1,6 +1,6 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE CPP                   #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE MultiParamTypeClasses #-}  -- |Encoding and decoding functions@@ -11,14 +11,16 @@     unflatWith,     unflatRaw,     unflatRawWith,+    unflatRawWithOffset, ) where -import qualified Data.ByteString as B-import Data.ByteString.Convert (AsByteString (..))-import Flat.Class (Flat (decode, encode), getSize)-import Flat.Decoder (Decoded, Get, strictDecoder)-import qualified Flat.Encoder as E-import Flat.Filler (postAligned, postAlignedDecoder)+import qualified Data.ByteString         as B+import           Data.ByteString.Convert (AsByteString (..))+import           Flat.Class              (Flat (decode, encode), getSize)+import           Flat.Decoder            (Decoded, Get, strictDecoder)+import           Flat.Encoder            (NumBits)+import qualified Flat.Encoder            as E+import           Flat.Filler             (postAligned, postAlignedDecoder)  -- |Encode padded value. flat :: Flat a => a -> B.ByteString@@ -38,7 +40,16 @@  -- |Unflat unpadded value, using provided decoder unflatRawWith :: AsByteString b => Get a -> b -> Decoded a-unflatRawWith dec = strictDecoder dec . toByteString+unflatRawWith dec bs = unflatRawWithOffset dec bs 0++unflatRawWithOffset :: AsByteString b => Get a -> b -> NumBits -> Decoded a+unflatRawWithOffset dec bs = strictDecoder dec (toByteString bs)++-- unflatRawWith :: AsByteString b => Get a -> b -> Decoded a+-- unflatRawWith dec bs = unflatRawWithOffset dec bs 0++-- unflatRawWithOffset :: AsByteString b => Get a -> b -> Int -> Decoded a+-- unflatRawWithOffset dec bs = strictDecoder dec (toByteString bs)  -- |Encode unpadded value flatRaw :: (Flat a, AsByteString b) => a -> b
src/Flat/Tutorial.hs view
@@ -56,7 +56,7 @@ A pecularity of Flat is that it uses an optimal bit-encoding rather than the usual byte-oriented one. -One bit is all we need for a 'Result' or for an empty 'List' value:+One bit is sufficient to encode a 'Result' or an empty 'List':  >>> flatBits Good "1"@@ -64,7 +64,7 @@ >>> flatBits (Nil::List Direction) "0" -Two or three bits suffice for a 'Direction' value:+Two or three bits suffice for a 'Direction':  >>> flatBits South "01"@@ -100,6 +100,17 @@  >>> flatBits $ Just True "11"++=== Wrapper Types++There are a few wrapper types that modify the way encoding and/or decoding occur.++* "Flat.AsBin" and "Flat.AsSize" decode to a value's flat binary representation or size in bits respectively.++* 'Flat.Instances.Mono.AsArray' and 'Flat.Instances.Mono.AsList' encode/decode a sequence as a List or Array respectively, see "Flat.Instances.Mono" for details.++* 'Flat.Instances.Text.UTF8Text' and 'Flat.Instances.Text.UTF16Text' encode/decode a Text as UTF8 or UTF16 respectively.+ -}  
src/Flat/Types.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE FlexibleInstances    #-}-{-# LANGUAGE TypeSynonymInstances #-} -- |Common Types module Flat.Types (     NumBits,
stack.yaml view
@@ -39,4 +39,5 @@   # - Cabal-3.6.3.0@sha256:ff97c442b0c679c1c9876acd15f73ac4f602b973c45bde42b43ec28265ee48f4,12459   # - parsec-3.1.15.0@sha256:a162d4cc8884014ba35192545cad293af0529fe11497aad8834bbaaa3dfffc26,4429   # - hashable-1.4.1.0@sha256:50b2f002c68fe67730ee7a3cd8607486197dd99b084255005ad51ecd6970a41b,5019+ allow-newer: true
+ test/Big.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE ScopedTypeVariables #-}++{-+Test different ways of handlings a data type that has large values and a small encoding.++To run with limited memory: cabal run big -- +RTS  -M2g+-}++module Main where+import qualified Data.ByteString as B+import           Data.List       (foldl')+import           Flat            (Decoded, Flat (..), flat, unflat, unflatWith)+import           Flat.AsBin      (AsBin, unbin)+import           Flat.AsSize+import           Flat.Decoder    (Get, listTDecoder)+import qualified ListT           as L+import           System.TimeIt   (timeIt)++-- Big is a type that has a small encoded representation but a very large in-memory footprint.+-- It is a very large bytestring whose bytes are all set to 0+newtype Big = Big B.ByteString++newBig :: Int -> Big+newBig gigas = Big $ B.replicate (gigas*giga) 0++-- length of Big in gigas+gigas :: Big -> Int+gigas (Big b) = B.length b `div` giga++giga :: Int+giga = 1000000000++instance Show Big where show b = "Big of " ++ show (gigas b) ++ "Gbytes"++instance Flat Big where+    -- The encoded form is just the number of giga zeros (e.g. 5 for 5Giga zeros)+    size big = size (gigas big)+    encode big = encode (gigas big)++    -- The decoded form is massive+    decode = newBig <$> decode++main :: IO ()+main = tbig++tbig = do+    let numOfBigs = 5++    -- A serialised list of Big values+    let bigsFile = flat $ replicate numOfBigs $ newBig 1+    print "Encoding Time"+    timeIt $ print $ B.length bigsFile++    tstAsSize bigsFile++    tstAsBin bigsFile++    tstListT bigsFile++    tstBig bigsFile++-- If we unserialise a list of Bigs and then process them (e.g. print them out) we end up in trouble, too much memory is required.+tstBig :: B.ByteString -> IO ()+tstBig bigsFile = timeIt $ do+    print "Decode to [Big]:"+    let Right (bs :: [Big]) = unflat bigsFile+    mapM_ print bs++-- So instead we unserialise them to a list of their flat representations, to be unflatted on demand later on+tstAsBin :: B.ByteString -> IO ()+tstAsBin bigsFile = timeIt $ do+    print "Decode to [AsBin Big]:"+    let Right (bsR :: [AsBin Big]) = unflat bigsFile+    let bs = map unbin bsR+    mapM_ print bs++tstAsSize :: B.ByteString -> IO ()+tstAsSize bigsFile = timeIt $ do+    print "Decode to [AsSize Big]:"+    let Right (bs :: [AsSize Big]) = unflat bigsFile+    mapM_ print bs++-- Or: we extract one element at the time via a ListT+-- See http://hackage.haskell.org/package/list-t-1.0.4/docs/ListT.html+tstListT :: B.ByteString -> IO ()+tstListT bigsFile = timeIt $ do+    print "Decode to ListT IO Big:"+    stream :: L.ListT IO Big <- listTDecoder decode bigsFile+    L.traverse_ print stream
+ test/DocTest/Flat/AsBin.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE ScopedTypeVariables#-}++{-# LANGUAGE NoMonomorphismRestriction, ExtendedDefaultRules#-}+module DocTest.Flat.AsBin where+import qualified DocTest+import Test.Tasty(TestTree,testGroup)+import Flat.AsBin+import Flat.Instances.Base+import Flat.Instances.Text+import Flat.Decoder.Types+import Flat.Types+import Flat.Run+import Data.Word+import qualified Data.Text as T+import Text.PrettyPrint.HughesPJClass++tests :: IO TestTree+tests = testGroup "Flat.AsBin" <$> sequence [  DocTest.test "src/Flat/AsBin.hs:50" "[ExpectedLine [LineChunk \"Right [AsBin {repr = \\\"\\\\129A\\\", offsetBits = 1},AsBin {repr = \\\"A \\\", offsetBits = 2},AsBin {repr = \\\" \\\\193\\\", offsetBits = 3}]\"]]" (DocTest.asPrint( unflat (flat [1::Int .. 3]) :: Decoded ([AsBin Int]) )),  DocTest.test "src/Flat/AsBin.hs:55" "[ExpectedLine [LineChunk \"Right 'a'\"]]" (DocTest.asPrint( unbin <$> (unflat (flat 'a') :: Decoded (AsBin Char)) )),  DocTest.test "src/Flat/AsBin.hs:60" "[ExpectedLine [LineChunk \"3\"]]" (DocTest.asPrint( let Right l :: Decoded [AsBin Int] = unflat (flat [1..5]) in unbin (l  !! 2) )),  DocTest.test "src/Flat/AsBin.hs:65" "[ExpectedLine [LineChunk \"\\\"(0, _0000001 1, _1)\\\"\"]]" (DocTest.asPrint( let Right t :: Decoded (AsBin Bool,AsBin Word8,AsBin Bool) = unflat (flat (False,3:: Word64,True)) in prettyShow t )),  DocTest.test "src/Flat/AsBin.hs:80" "[ExpectedLine [LineChunk \"Right (AsBin {repr = \\\"\\\", offsetBits = 0})\"]]" (DocTest.asPrint( unflat (flat ()) :: Decoded (AsBin ()) )),  DocTest.test "src/Flat/AsBin.hs:83" "[ExpectedLine [LineChunk \"Right (False,AsBin {repr = \\\"A\\\", offsetBits = 1})\"]]" (DocTest.asPrint( unflat (flat (False,True)) :: Decoded (Bool,AsBin Bool) )),  DocTest.test "src/Flat/AsBin.hs:86" "[ExpectedLine [LineChunk \"Right (False,False,AsBin {repr = \\\"?\\\\193\\\", offsetBits = 2})\"]]" (DocTest.asPrint( unflat (flat (False,False,255 :: Word8)) :: Decoded (Bool,Bool,AsBin Word8) )),  DocTest.test "src/Flat/AsBin.hs:89" "[ExpectedLine [LineChunk \"(False,False,255,True)\"]]" (DocTest.asPrint( let Right (b0,b1,rw,b3) :: Decoded (Bool,Bool,AsBin Word8,Bool) = unflat (flat (False,False,255 :: Word8,True)) in (b0,b1,unbin rw,b3) ))]
+ test/DocTest/Flat/AsSize.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE ScopedTypeVariables#-}++{-# LANGUAGE NoMonomorphismRestriction, ExtendedDefaultRules#-}+module DocTest.Flat.AsSize where+import qualified DocTest+import Test.Tasty(TestTree,testGroup)+import Flat.AsSize+import Flat.Instances.Base+import Flat.Instances.Text+import Flat.Decoder.Types+import Flat.Types+import Flat.Run+import Data.Word+import qualified Data.Text as T++tests :: IO TestTree+tests = testGroup "Flat.AsSize" <$> sequence [  DocTest.test "src/Flat/AsSize.hs:38" "[ExpectedLine [LineChunk \"Right ('a',AsSize 28,'z',AsSize 1)\"]]" (DocTest.asPrint( let v = flat ('a',"abc",'z',True) in unflat v :: Decoded (Char,AsSize String,Char,AsSize Bool) )),  DocTest.test "src/Flat/AsSize.hs:43" "[ExpectedLine [LineChunk \"Right (AsSize 8,AsSize 8)\"]]" (DocTest.asPrint( unflat (flat (1::Word16,1::Word64)) :: Decoded (AsSize Word16,AsSize Word64) )),  DocTest.test "src/Flat/AsSize.hs:48" "[ExpectedLine [LineChunk \"Right (AsSize 16,AsSize 32,AsSize 48,AsSize 48,AsSize 40,AsSize 40)\"]]" (DocTest.asPrint( unflat (flat (T.pack "",T.pack "a",T.pack "主",UTF8Text $ T.pack "主",UTF16Text $ T.pack "主",UTF16Text $ T.pack "a")) :: Decoded (AsSize T.Text,AsSize T.Text,AsSize T.Text,AsSize UTF8Text,AsSize UTF16Text,AsSize UTF16Text) )),  DocTest.test "src/Flat/AsSize.hs:53" "[ExpectedLine [LineChunk \"Right (AsSize 1,AsSize 96,AsSize 8)\"]]" (DocTest.asPrint( unflat (flat (False,[T.pack "",T.pack "a",T.pack "主"],'a')) :: Decoded (AsSize Bool,AsSize [T.Text],AsSize Char) ))]
test/DocTest/Flat/Decoder/Prim.hs view
@@ -12,4 +12,4 @@ import Text.PrettyPrint.HughesPJClass (Pretty (pPrint))  tests :: IO TestTree-tests = testGroup "Flat.Decoder.Prim" <$> sequence [  DocTest.test "src/Flat/Decoder/Prim.hs:194" "[ExpectedLine [LineChunk \"True\"]]" (DocTest.asPrint( unflatWith (dBEBits8 3) [0b11100001::Word8] == Right 0b00000111 )),  DocTest.test "src/Flat/Decoder/Prim.hs:197" "[ExpectedLine [LineChunk \"Left (BadOp \\\"read8: cannot read 9 bits\\\")\"]]" (DocTest.asPrint( unflatWith (dBEBits8 9) [0b11100001::Word8,0b11111111] )),  DocTest.test "src/Flat/Decoder/Prim.hs:210" "[ExpectedLine [LineChunk \"Right 00000101 10111111\"]]" (DocTest.asPrint( pPrint . asBits <$> unflatWith (dBEBits16 11) [0b10110111::Word8,0b11100001] )),  DocTest.test "src/Flat/Decoder/Prim.hs:215" "[ExpectedLine [LineChunk \"Right 00000111 11111111\"]]" (DocTest.asPrint( pPrint . asBits <$> unflatWith (dBEBits16 19) [0b00000000::Word8,0b11111111,0b11100001] ))]+tests = testGroup "Flat.Decoder.Prim" <$> sequence [  DocTest.test "src/Flat/Decoder/Prim.hs:198" "[ExpectedLine [LineChunk \"True\"]]" (DocTest.asPrint( unflatWith (dBEBits8 3) [0b11100001::Word8] == Right 0b00000111 )),  DocTest.test "src/Flat/Decoder/Prim.hs:201" "[ExpectedLine [LineChunk \"Left (BadOp \\\"read8: cannot read 9 bits\\\")\"]]" (DocTest.asPrint( unflatWith (dBEBits8 9) [0b11100001::Word8,0b11111111] )),  DocTest.test "src/Flat/Decoder/Prim.hs:214" "[ExpectedLine [LineChunk \"Right 00000101 10111111\"]]" (DocTest.asPrint( pPrint . asBits <$> unflatWith (dBEBits16 11) [0b10110111::Word8,0b11100001] )),  DocTest.test "src/Flat/Decoder/Prim.hs:219" "[ExpectedLine [LineChunk \"Right 00000111 11111111\"]]" (DocTest.asPrint( pPrint . asBits <$> unflatWith (dBEBits16 19) [0b00000000::Word8,0b11111111,0b11100001] ))]
− test/DocTest/Flat/Repr.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE ScopedTypeVariables#-}--{-# LANGUAGE NoMonomorphismRestriction, ExtendedDefaultRules#-}-module DocTest.Flat.Repr where-import qualified DocTest-import Test.Tasty(TestTree,testGroup)-import Flat.Repr-import Flat.Instances.Base-import Flat.Decoder.Types-import Flat.Types-import Flat.Run-import Flat.Class--tests :: IO TestTree-tests = testGroup "Flat.Repr" <$> sequence [  DocTest.test "src/Flat/Repr.hs:27" "[ExpectedLine [LineChunk \"Right [Repr {repr = \\\"\\\\STX\\\\SOH\\\"},Repr {repr = \\\"\\\\EOT\\\\SOH\\\"},Repr {repr = \\\"\\\\ACK\\\\SOH\\\"},Repr {repr = \\\"\\\\b\\\\SOH\\\"},Repr {repr = \\\"\\\\n\\\\SOH\\\"}]\"]]" (DocTest.asPrint( unflat (flat [1::Int .. 5]) :: Decoded ([Repr Int]) )),  DocTest.test "src/Flat/Repr.hs:32" "[ExpectedLine [LineChunk \"3\"]]" (DocTest.asPrint( let Right l = unflat (flat [1..5]) :: Decoded [Repr Int] in unrepr (l  !! 2) )),  DocTest.test "src/Flat/Repr.hs:42" "[ExpectedLine [LineChunk \"Right ('a',SizeOf 28,'z',SizeOf 1)\"]]" (DocTest.asPrint( let v = flat ('a',"abc",'z',True) in unflat v :: Decoded (Char,SizeOf String,Char,SizeOf Bool) ))]
test/DocTests.hs view
@@ -1,23 +1,6 @@ module Main where import           Test.Tasty import           Test.Tasty.HUnit-import qualified DocTest.Flat.Bits-import qualified DocTest.Flat.Repr-import qualified DocTest.Flat.Instances.Array-import qualified DocTest.Flat.Instances.ByteString-import qualified DocTest.Flat.Instances.DList-import qualified DocTest.Flat.Instances.Extra-import qualified DocTest.Flat.Instances.Containers-import qualified DocTest.Flat.Instances.Base-import qualified DocTest.Flat.Instances.Unordered-import qualified DocTest.Flat.Instances.Vector-import qualified DocTest.Flat.Instances.Mono-import qualified DocTest.Flat.Instances.Text-import qualified DocTest.Flat.Encoder.Prim-import qualified DocTest.Flat.Tutorial-import qualified DocTest.Flat.Decoder.Prim-import qualified DocTest.Flat.Endian-import qualified DocTest.Data.ZigZag-import qualified DocTest.Data.FloatCast+import qualified DocTest.Flat.AsBin -main = (testGroup "DocTests" <$> sequence [DocTest.Flat.Bits.tests,DocTest.Flat.Repr.tests,DocTest.Flat.Instances.Array.tests,DocTest.Flat.Instances.ByteString.tests,DocTest.Flat.Instances.DList.tests,DocTest.Flat.Instances.Extra.tests,DocTest.Flat.Instances.Containers.tests,DocTest.Flat.Instances.Base.tests,DocTest.Flat.Instances.Unordered.tests,DocTest.Flat.Instances.Vector.tests,DocTest.Flat.Instances.Mono.tests,DocTest.Flat.Instances.Text.tests,DocTest.Flat.Encoder.Prim.tests,DocTest.Flat.Tutorial.tests,DocTest.Flat.Decoder.Prim.tests,DocTest.Flat.Endian.tests,DocTest.Data.ZigZag.tests,DocTest.Data.FloatCast.tests]) >>= defaultMain+main = (testGroup "DocTests" <$> sequence [DocTest.Flat.AsBin.tests]) >>= defaultMain
− test/FlatRepr.hs
@@ -1,75 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}-module Main where-import qualified Data.ByteString as B-import           Data.List       (foldl')-import           Flat            (Decoded, Flat (..), flat, unflat, unflatWith)-import           Flat.Decoder    (Get, listTDecoder)-import           Flat.Repr       (Repr, unrepr)-import qualified ListT           as L-import           System.TimeIt   (timeIt)---- Big is a type that has a small encoded representation but a very large in-memory footprint.--- It is a very large bytestring whose bytes are all set to 0-newtype Big = Big B.ByteString--newBig :: Int -> Big-newBig gigas = Big $ B.replicate (gigas*giga) 0---- length of Big in gigas-gigas :: Big -> Int-gigas (Big b) = B.length b `div` giga--giga :: Int-giga = 1000000000--instance Show Big where show b = "Big of " ++ show (gigas b) ++ "Gbytes"--instance Flat Big where-    -- The encoded form is just the number of giga zeros (e.g. 5 for 5Giga zeros)-    size big = size (gigas big)-    encode big = encode (gigas big)--    -- The decoded form is massive-    decode = newBig <$> decode---- Run this as: cabal run FlatRepr -- +RTS  -M2g-main :: IO ()-main = tbig--tbig = do-    let numOfBigs = 5--    -- A serialised list of Big values-    let bigsFile = flat $ replicate numOfBigs $ newBig 1-    timeIt $ print $ B.length bigsFile--    -- tstSize bigsFile--    tstListT bigsFile--    tstRepr bigsFile--    tstBig bigsFile---- If we unserialise a list of Bigs and then process them (e.g. print them out) we end up in trouble, too much memory is required.-tstBig :: B.ByteString -> IO ()-tstBig bigsFile = timeIt $ do-    print "Decode to [Big]:"-    let Right (bs :: [Big]) = unflat bigsFile-    mapM_ print bs---- So instead we unserialise them to a list of their flat representations, to be unflatted on demand later on-tstRepr :: B.ByteString -> IO ()-tstRepr bigsFile = timeIt $ do-    print "Decode to [FlatRepl Big]:"-    let Right (bsR :: [Repr Big]) = unflat bigsFile-    let bs = map unrepr bsR-    mapM_ print bs---- Or: we extract one element at the time via a ListT--- See http://hackage.haskell.org/package/list-t-1.0.4/docs/ListT.html-tstListT :: B.ByteString -> IO ()-tstListT bigsFile = timeIt $ do-    print "Decode to ListT IO Big:"-    stream :: L.ListT IO Big <- listTDecoder decode bigsFile-    L.traverse_ print stream