cereal-conduit 0.0.4 → 0.0.5
raw patch · 3 files changed
+82/−17 lines, 3 filesdep +HUnitPVP ok
version bump matches the API change (PVP)
Dependencies added: HUnit
API changes (from Hackage documentation)
+ Data.Conduit.Cereal: conduitGet :: Monad m => Get output -> Conduit ByteString m output
+ Data.Conduit.Cereal: instance Exception GetException
+ Data.Conduit.Cereal: instance Show GetException
+ Data.Conduit.Cereal: instance Typeable GetException
Files
- Data/Conduit/Cereal.hs +28/−5
- Test/CerealConduit.hs +50/−9
- cereal-conduit.cabal +4/−3
Data/Conduit/Cereal.hs view
@@ -1,13 +1,22 @@+{-# LANGUAGE DeriveDataTypeable #-}+ -- | Turn a 'Get' into a 'Sink' and a 'Put' into a 'Source' -module Data.Conduit.Cereal where+module Data.Conduit.Cereal (sinkGet, conduitGet, sourcePut) where import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import qualified Data.Conduit as C import Data.Conduit.List (sourceList)-import Data.Serialize+import Data.Serialize hiding (get, put)+import Data.Typeable+import Control.Exception +data GetException = GetException String+ deriving (Show, Typeable)++instance Exception GetException+ -- | Convert a 'Get' into a 'Sink'. The 'Get' will be streamed bytes until it returns 'Done' or 'Fail'. -- -- If 'Get' succeed it will return the data read and unconsumed part of the input stream.@@ -22,9 +31,23 @@ Partial f' -> C.NeedInput (push f') (close f') Done r s' -> C.Done (streamToMaybe s') (Right r) close f = let Fail r = f BS.empty in C.Done Nothing (Left r)- streamToMaybe s = if BS.null s- then Nothing- else Just s++-- | Run a 'Get' repeatedly on the input stream, producing an output stream of whatever the 'Get' outputs.+conduitGet :: Monad m => Get output -> C.Conduit BS.ByteString m output+conduitGet get = consume (runGetPartial get) BS.empty BS.empty+ where push f b input+ | BS.null input = C.NeedInput (push f b) (C.Done (streamToMaybe b) ())+ | otherwise = consume f b input+ consume f b s = case f s of+ Fail msg -> throw $ GetException msg+ Partial f' -> C.NeedInput (push f' consumed) $ C.Done (streamToMaybe consumed) ()+ Done r s' -> C.HaveOutput (push (runGetPartial get) BS.empty s') (return ()) r+ where consumed = BS.concat [b, s]++streamToMaybe :: BS.ByteString -> Maybe BS.ByteString+streamToMaybe s = if BS.null s+ then Nothing+ else Just s -- | Convert a 'Put' into a 'Source'. Runs in constant memory. sourcePut :: Monad m => Put -> C.Source m BS.ByteString
Test/CerealConduit.hs view
@@ -9,32 +9,73 @@ import qualified Data.ByteString as BS import Test.Framework.Providers.HUnit import System.Exit+import Data.Word -test1 :: Test-test1 = TestCase (assertEqual "Handles starting with empty bytestring"+sinktest1 :: Test+sinktest1 = TestCase (assertEqual "Handles starting with empty bytestring" (Right 1) (runIdentity $ (sourceList [BS.pack [], BS.pack [1]]) C.$$ (sinkGet getWord8))) -test2 :: Test-test2 = TestCase (assertEqual "Handles empty bytestring in middle"+sinktest2 :: Test+sinktest2 = TestCase (assertEqual "Handles empty bytestring in middle" (Right [1, 3]) (runIdentity $ (sourceList [BS.pack [1], BS.pack [], BS.pack [3]]) C.$$ (sinkGet (do x <- getWord8 y <- getWord8 return [x, y])))) -test3 :: Test-test3 = TestCase (assertBool "Handles no data"+sinktest3 :: Test+sinktest3 = TestCase (assertBool "Handles no data" (case (runIdentity $ (sourceList []) C.$$ (sinkGet getWord8)) of Right _ -> False Left _ -> True)) -test4 :: Test-test4 = TestCase (assertEqual "Consumes no data"+sinktest4 :: Test+sinktest4 = TestCase (assertEqual "Consumes no data" (Right ()) (runIdentity $ (sourceList [BS.pack [1]]) C.$$ (sinkGet $ return ()))) -hunittests = TestList [test1, test2, test3, test4]+twoItemGet :: Get Word8+twoItemGet = do+ x <- getWord8+ y <- getWord8+ return $ x + y++conduittest1 :: Test+conduittest1 = TestCase (assertEqual "Handles starting with empty bytestring"+ []+ (runIdentity $ (sourceList [BS.pack [], BS.pack [1]]) C.$= conduitGet twoItemGet C.$$ consume))++conduittest2 :: Test+conduittest2 = TestCase (assertEqual "Works when the get is split across items"+ [3]+ (runIdentity $ (sourceList [BS.pack [1], BS.pack [2]]) C.$= conduitGet twoItemGet C.$$ consume))++conduittest3 :: Test+conduittest3 = TestCase (assertEqual "Works when empty bytestring in middle of get"+ [3]+ (runIdentity $ (sourceList [BS.pack [1], BS.pack [], BS.pack [2]]) C.$= conduitGet twoItemGet C.$$ consume))++conduittest4 :: Test+conduittest4 = TestCase (assertEqual "Works when empty bytestring at end of get"+ [3, 7]+ (runIdentity $ (sourceList [BS.pack [1, 2], BS.pack [], BS.pack [3, 4]]) C.$= conduitGet twoItemGet C.$$ consume))++conduittest5 :: Test+conduittest5 = TestCase (assertEqual "Works when multiple gets are in an item"+ [3, 7]+ (runIdentity $ (sourceList [BS.pack [1, 2, 3, 4]]) C.$= conduitGet twoItemGet C.$$ consume))++conduittest6 :: Test+conduittest6 = TestCase (assertEqual "Works with leftovers"+ [3]+ (runIdentity $ (sourceList [BS.pack [1, 2, 3]]) C.$= conduitGet twoItemGet C.$$ consume))++sinktests = TestList [sinktest1, sinktest2, sinktest3, sinktest4]++conduittests = TestList [conduittest1, conduittest2, conduittest3, conduittest4, conduittest5, conduittest6]++hunittests = TestList [sinktests, conduittests] tests = hUnitTestToTests hunittests
cereal-conduit.cabal view
@@ -1,11 +1,11 @@ name: cereal-conduit-version: 0.0.4+version: 0.0.5 license: BSD3 license-file: LICENSE author: Myles C. Maxfield <myles.maxfield@gmail.com> maintainer: Myles C. Maxfield <myles.maxfield@gmail.com>-synopsis: Turn Data.Serialize Gets and Puts into Sources and Sinks-description: Turn Data.Serialize Gets and Puts into Sources and Sinks+synopsis: Turn Data.Serialize Gets and Puts into Sources, Sinks, and Conduits+description: Turn Data.Serialize Gets and Puts into Sources, Sinks, and Conduits category: Conduit stability: Experimental cabal-version: >= 1.8@@ -30,6 +30,7 @@ , mtl , bytestring , test-framework-hunit+ , HUnit source-repository head type: git