packages feed

cereal 0.3.0.0 → 0.3.1.0

raw patch · 6 files changed

+120/−59 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Serialize.Get: Done :: r -> ByteString -> Result r
+ Data.Serialize.Get: Fail :: String -> Result r
+ Data.Serialize.Get: Partial :: (ByteString -> Result r) -> Result r
+ Data.Serialize.Get: data Result r
+ Data.Serialize.Get: ensure :: Int -> Get ByteString
+ Data.Serialize.Get: instance Eq More
+ Data.Serialize.Get: instance Functor Result
+ Data.Serialize.Get: instance Show r => Show (Result r)
+ Data.Serialize.Get: runGetPartial :: Get a -> ByteString -> Result a

Files

cereal.cabal view
@@ -1,8 +1,10 @@ name:                   cereal-version:                0.3.0.0+version:                0.3.1.0 license:                BSD3 license-file:           LICENSE-author:                 Lennart Kolmodin <kolmodin@dtek.chalmers.se>, Galois Inc.+author:                 Lennart Kolmodin <kolmodin@dtek.chalmers.se>,+                        Galois Inc.,+                        Lemmih <lemmih@gmail.com> maintainer:             Trevor Elliott <trevor@galois.com> category:               Data, Parsing stability:              provisional
src/Data/Serialize/Get.hs view
@@ -27,8 +27,11 @@       Get     , runGet     , runGetState+    , Result(..)+    , runGetPartial      -- * Parsing+    , ensure     , isolate     , label     , skip@@ -91,6 +94,7 @@  import qualified Data.ByteString          as B import qualified Data.ByteString.Internal as B+import qualified Data.ByteString.Unsafe   as B import qualified Data.ByteString.Lazy     as L import qualified Data.IntMap              as IntMap import qualified Data.IntSet              as IntSet@@ -105,18 +109,47 @@ import GHC.Word #endif -type Failure   r = [String]     -> String -> Either String (r, B.ByteString)-type Success a r = B.ByteString -> a      -> Either String (r, B.ByteString)+type Failure   r = [String]     -> String -> Result r+type Success a r = B.ByteString -> More -> a      -> Result r +-- | The result of a parse.+data Result r = Fail String+              -- ^ The parse failed. The 'String' is the+              --   message describing the error, if any.+              | Partial (B.ByteString -> Result r)+              -- ^ Supply this continuation with more input so that+              --   the parser can resume. To indicate that no more+              --   input is available, use an 'B.empty' string.+              | Done r B.ByteString+              -- ^ The parse succeeded.  The 'B.ByteString' is the+              --   input that had not yet been consumed (if any) when+              --   the parse succeeded.++instance Show r => Show (Result r) where+    show (Fail msg)  = "Fail " ++ show msg+    show (Partial _) = "Partial _"+    show (Done r bs) = "Done " ++ show r ++ " " ++ show bs++instance Functor Result where+    fmap _ (Fail msg)  = Fail msg+    fmap f (Partial k) = Partial (fmap f . k)+    fmap f (Done r bs) = Done (f r) bs+ -- | The Get monad is an Exception and State monad. newtype Get a = Get   { unGet :: forall r. B.ByteString+                    -> More                     -> Failure   r                     -> Success a r-                    -> Either String (r, B.ByteString) }+                   -- -> Either String (r, B.ByteString) }+                    -> Result r } +-- | Have we read all available input?+data More = Complete | Incomplete+    deriving (Eq)+ instance Functor Get where-    fmap p m = Get (\s0 f k -> unGet m s0 f (\s a -> k s (p a)))+    fmap p m = Get (\s0 m0 f k -> unGet m s0 m0 f (\s m1 a -> k s m1 (p a)))  instance Applicative Get where     pure  = return@@ -128,13 +161,13 @@  -- Definition directly from Control.Monad.State.Strict instance Monad Get where-    return a = Get (\s0 _ k -> k s0 a)-    m >>= g  = Get (\s0 f k -> unGet m s0 f (\s a -> unGet (g a) s f k))+    return a = Get (\s0 m _ k -> k s0 m a)+    m >>= g  = Get (\s0 m0 f k -> unGet m s0 m0 f (\s m1 a -> unGet (g a) s m1 f k))     fail     = failDesc  instance MonadPlus Get where     mzero = failDesc "mzero"-    mplus a b = Get (\s0 f k -> unGet a s0 (\_ _ -> unGet b s0 f k) k)+    mplus a b = Get (\s0 m0 f k -> unGet a s0 m0 (\_ _ -> unGet b s0 m0 f k) k)  ------------------------------------------------------------------------ @@ -143,48 +176,70 @@ formatTrace ls = "From:\t" ++ intercalate "\n\t" ls ++ "\n"  get :: Get B.ByteString-get  = Get (\s0 _ k -> k s0 s0)+get  = Get (\s0 m0 _ k -> k s0 m0 s0)  put :: B.ByteString -> Get ()-put s = Get (\_ _ k -> k s ())+put s = Get (\_ m _ k -> k s m ())  label :: String -> Get a -> Get a-label l m = Get (\s0 f k -> unGet m s0 (\ls -> f (l:ls)) k)+label l m = Get (\s0 m0 f k -> unGet m s0 m0 (\ls -> f (l:ls)) k)  finalK :: Success a a-finalK s a = Right (a,s)+finalK s _ a = Done a s  failK :: Failure a-failK ls s = Left (unlines [s, formatTrace ls])+failK ls s = Fail (unlines [s, formatTrace ls])  -- | Run the Get monad applies a 'get'-based parser on the input ByteString runGet :: Get a -> B.ByteString -> Either String a-runGet m str = case unGet m str failK finalK of-  Left  i      -> Left i-  Right (a, _) -> Right a+runGet m str = case unGet m str Complete failK finalK of+  Fail i    -> Left i+  Done a _  -> Right a+  Partial{} -> Left "Failed reading: Internal error: unexpected Partial." {-# INLINE runGet #-} +-- | Run the Get monad applies a 'get'-based parser on the input ByteString+runGetPartial :: Get a -> B.ByteString -> Result a+runGetPartial m str = unGet m str Incomplete failK finalK+{-# INLINE runGetPartial #-}+ -- | Run the Get monad applies a 'get'-based parser on the input -- ByteString. Additional to the result of get it returns the number of -- consumed bytes and the rest of the input. runGetState :: Get a -> B.ByteString -> Int             -> Either String (a, B.ByteString) runGetState m str off =-    case unGet m (B.drop off str) failK finalK of-      Left i        -> Left i-      Right (a, bs) -> Right (a, bs)+    case unGet m (B.drop off str) Complete failK finalK of+      Fail i      -> Left i+      Done a bs   -> Right (a, bs)+      Partial{}   -> Left "Failed reading: Internal error: unexpected Partial." {-# INLINE runGetState #-}  ------------------------------------------------------------------------ +-- | If at least @n@ bytes of input are available, return the current+--   input, otherwise fail.+ensure :: Int -> Get B.ByteString+ensure n = n `seq` Get $ \i0 m0 kf ks ->+    if B.length i0 >= n+    then ks i0 m0 i0+    else unGet (demandInput >> ensureRec n) i0 m0 kf ks+{-# INLINE ensure #-}++-- | If at least @n@ bytes of input are available, return the current+--   input, otherwise fail.+ensureRec :: Int -> Get B.ByteString+ensureRec n = Get $ \i0 m0 kf ks ->+    if B.length i0 >= n+    then ks i0 m0 i0+    else unGet (demandInput >> ensureRec n) i0 m0 kf ks+ -- | Isolate an action to operating within a fixed block of bytes.  The action --   is required to consume all the bytes that it is isolated to. isolate :: Int -> Get a -> Get a isolate n m = do   when (n < 0) (fail "Attempted to isolate a negative number of bytes")-  s <- get-  let left = B.length s-  unless (n <= left) (fail "not enough space left to isolate")+  s <- ensure n   let (s',rest) = B.splitAt n s   put s'   a    <- m@@ -193,16 +248,26 @@   put rest   return a +-- | Immediately demand more input via a 'Partial' continuation+--   result.+demandInput :: Get ()+demandInput = Get $ \i0 m0 kf ks ->+    if m0 == Complete+    then kf ["demandInput"] "too few bytes"+    else Partial $ \s ->+         if B.null s+         then kf ["demandInput"] "too few bytes"+         else ks (i0 `B.append` s) Incomplete ()+ failDesc :: String -> Get a failDesc err = do     let msg = "Failed reading: " ++ err-    Get (\_ f _ -> f [] msg)+    Get (\_ _ f _ -> f [] msg)  -- | Skip ahead @n@ bytes. Fails if fewer than @n@ bytes are available. skip :: Int -> Get () skip n = do-  s <- get-  when (B.length s < n) (fail "too few bytes")+  s <- ensure n   put (B.drop n s)  -- | Skip ahead @n@ bytes. No error if there isn't enough bytes.@@ -282,9 +347,10 @@ -- | Pull @n@ bytes from the input, as a strict ByteString. getBytes :: Int -> Get B.ByteString getBytes n = do-    s <- get-    when (n > B.length s) (fail "too few bytes")-    let (consume,rest) = B.splitAt n s+    s <- ensure n+    let consume = B.unsafeTake n s+        rest    = B.unsafeDrop n s+        -- (consume,rest) = B.splitAt n s     put rest     return consume 
src/Data/Serialize/Put.hs view
@@ -8,7 +8,7 @@ -- Stability   : -- Portability : ----- The Put monad. A monad for efficiently constructing lazy bytestrings.+-- The Put monad. A monad for efficiently constructing bytestrings. -- ----------------------------------------------------------------------------- 
tests/Benchmark.hs view
@@ -7,6 +7,7 @@ import Data.Serialize.Get  import Control.Exception+import Data.Word import System.CPUTime import Numeric import Text.Printf
tests/Makefile view
@@ -1,10 +1,14 @@-GHC	= ghc -O2 -fasm -fforce-recomp+GHC	= ghc -O2 -fasm -fforce-recomp -i../src -prof  all: bench qc  bench:: Benchmark.hs MemBench.hs CBenchmark.o 	$(GHC) -fliberate-case-threshold=1000 --make Benchmark.hs CBenchmark.o -o $@ 	./$@ 100++bench-prof: Benchmark.hs MemBench.hs CBenchmark.o+	$(GHC) -auto-all -rtsopts -fliberate-case-threshold=1000 --make Benchmark.hs CBenchmark.o -o $@+	./$@ 100 +RTS -p  CBenchmark.o: CBenchmark.c 	gcc -O3 -c $< -o $@
tests/Tests.hs view
@@ -14,20 +14,8 @@ import Data.Serialize import Data.Serialize.Get import Data.Serialize.Put-import Data.Word (Word8)-import Test.QuickCheck--instance Arbitrary Word8 where-  arbitrary = arbitraryBoundedIntegral--instance Arbitrary Word16 where-  arbitrary = arbitraryBoundedIntegral--instance Arbitrary Word32 where-  arbitrary = arbitraryBoundedIntegral--instance Arbitrary Word64 where-  arbitrary = arbitraryBoundedIntegral+import Data.Word (Word8,Word16,Word32,Word64)+import Test.QuickCheck as QC   roundTrip :: Eq a => Putter a -> Get a -> a -> Bool@@ -36,25 +24,25 @@  main :: IO () main  = mapM_ quickCheck-  [ label "Word8         Round Trip" $ roundTrip putWord8      getWord8-  , label "Word16be      Round Trip" $ roundTrip putWord16be   getWord16be-  , label "Word16le      Round Trip" $ roundTrip putWord16le   getWord16le-  , label "Word32be      Round Trip" $ roundTrip putWord32be   getWord32be-  , label "Word32le      Round Trip" $ roundTrip putWord32le   getWord32le-  , label "Word64be      Round Trip" $ roundTrip putWord64be   getWord64be-  , label "Word64le      Round Trip" $ roundTrip putWord64le   getWord64le-  , label "Word16host    Round Trip" $ roundTrip putWord16host getWord16host-  , label "Word32host    Round Trip" $ roundTrip putWord32host getWord32host-  , label "Word64host    Round Trip" $ roundTrip putWord64host getWord64host+  [ QC.label "Word8         Round Trip" $ roundTrip putWord8      getWord8+  , QC.label "Word16be      Round Trip" $ roundTrip putWord16be   getWord16be+  , QC.label "Word16le      Round Trip" $ roundTrip putWord16le   getWord16le+  , QC.label "Word32be      Round Trip" $ roundTrip putWord32be   getWord32be+  , QC.label "Word32le      Round Trip" $ roundTrip putWord32le   getWord32le+  , QC.label "Word64be      Round Trip" $ roundTrip putWord64be   getWord64be+  , QC.label "Word64le      Round Trip" $ roundTrip putWord64le   getWord64le+  , QC.label "Word16host    Round Trip" $ roundTrip putWord16host getWord16host+  , QC.label "Word32host    Round Trip" $ roundTrip putWord32host getWord32host+  , QC.label "Word64host    Round Trip" $ roundTrip putWord64host getWord64host      -- Containers-  , label "(Word8,Word8) Round Trip"+  , QC.label "(Word8,Word8) Round Trip"     $ roundTrip (putTwoOf putWord8 putWord8) (getTwoOf getWord8 getWord8)-  , label "[Word8] Round Trip"+  , QC.label "[Word8] Round Trip"     $ roundTrip (putListOf putWord8) (getListOf getWord8)-  , label "Maybe Word8 Round Trip"+  , QC.label "Maybe Word8 Round Trip"     $ roundTrip (putMaybeOf putWord8) (getMaybeOf getWord8)-  , label "Either Word8 Word16be Round Trip "+  , QC.label "Either Word8 Word16be Round Trip "     $ roundTrip (putEitherOf putWord8 putWord16be)                 (getEitherOf getWord8 getWord16be)   ]