conduit 1.0.9.3 → 1.0.10
raw patch · 4 files changed
+88/−3 lines, 4 files
Files
- Data/Conduit/Binary.hs +20/−1
- Data/Conduit/Util.hs +40/−1
- conduit.cabal +1/−1
- test/main.hs +27/−0
Data/Conduit/Binary.hs view
@@ -30,13 +30,14 @@ , drop , sinkCacheLength , sinkLbs+ , mapM_ -- ** Conduits , isolate , takeWhile , Data.Conduit.Binary.lines ) where -import Prelude hiding (head, take, drop, takeWhile, dropWhile)+import Prelude hiding (head, take, drop, takeWhile, dropWhile, mapM_) import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import Data.Conduit@@ -45,6 +46,7 @@ import Control.Monad (unless) import Control.Monad.IO.Class (liftIO, MonadIO) import Control.Monad.Trans.Resource (allocate, release)+import Control.Monad.Trans.Class (lift) import qualified System.IO as IO import Data.Word (Word8, Word64) import Control.Applicative ((<$>))@@ -377,3 +379,20 @@ -- Since 1.0.5 sinkLbs :: Monad m => Sink S.ByteString m L.ByteString sinkLbs = fmap L.fromChunks consume++-- | Perform a computation on each @Word8@ in a stream.+--+-- Since 1.0.10+mapM_ :: Monad m => (Word8 -> m ()) -> Consumer S.ByteString m ()+mapM_ f =+ awaitForever (lift . go)+ where+ go bs =+ loop 0+ where+ len = S.length bs+ loop i+ | i < len = do+ f (S.index bs i)+ loop (i + 1)+ | otherwise = return ()
Data/Conduit/Util.hs view
@@ -3,12 +3,14 @@ ( -- * Misc zip , zipSinks+ , passthroughSink ) where import Prelude hiding (zip) import Control.Monad (liftM, liftM2)-import Data.Conduit.Internal (Pipe (..), Source, Sink, injectLeftovers, ConduitM (..))+import Data.Conduit.Internal (Pipe (..), Source, Sink, injectLeftovers, ConduitM (..), Conduit, awaitForever, yield, await) import Data.Void (Void, absurd)+import Control.Monad.Trans.Class (lift) -- | Combines two sources. The new source will stop producing once either -- source has been exhausted.@@ -55,3 +57,40 @@ NeedInput px cx >< NeedInput py cy = NeedInput (\i -> px i >< py i) (\() -> cx () >< cy ()) NeedInput px cx >< y@Done{} = NeedInput (\i -> px i >< y) (\u -> cx u >< y) x@Done{} >< NeedInput py cy = NeedInput (\i -> x >< py i) (\u -> x >< cy u)++-- | Turn a @Sink@ into a @Conduit@ in the following way:+--+-- * All input passed to the @Sink@ is yielded downstream.+--+-- * When the @Sink@ finishes processing, the result is passed to the provided to the finalizer function.+--+-- Note that the @Sink@ will stop receiving input as soon as the downstream it+-- is connected to shuts down.+--+-- An example usage would be to write the result of a @Sink@ to some mutable+-- variable while allowing other processing to continue.+--+-- Since 1.0.10+passthroughSink :: Monad m+ => Sink i m r+ -> (r -> m ()) -- ^ finalizer+ -> Conduit i m i+passthroughSink (ConduitM sink0) final =+ ConduitM $ go [] sink0+ where+ go _ (Done r) = do+ lift $ final r+ awaitForever yield+ go is (Leftover sink i) = go (i:is) sink+ go _ (HaveOutput _ _ o) = absurd o+ go is (PipeM mx) = do+ x <- lift mx+ go is x+ go (i:is) (NeedInput next _) = go is (next i)+ go [] (NeedInput next done) = do+ mx <- await+ case mx of+ Nothing -> go [] (done ())+ Just x -> do+ yield x+ go [] (next x)
conduit.cabal view
@@ -1,5 +1,5 @@ Name: conduit-Version: 1.0.9.3+Version: 1.0.10 Synopsis: Streaming data processing library. Description: @conduit@ is a solution to the streaming data problem, allowing for production, transformation, and consumption of streams of data in constant memory. It is an alternative to lazy I\/O which guarantees deterministic resource handling, and fits in the same general solution space as @enumerator@\/@iteratee@ and @pipes@. For a tutorial, please visit <https://haskell.fpcomplete.com/user/snoyberg/library-documentation/conduit-overview>.
test/main.hs view
@@ -936,6 +936,33 @@ lbs' `shouldBe` lbs fromIntegral len `shouldBe` L.length lbs' + describe "Data.Conduit.Binary.mapM_" $ do+ prop "telling works" $ \bytes ->+ let lbs = L.pack bytes+ src = CB.sourceLbs lbs+ sink = CB.mapM_ (tell . return . S.singleton)+ bss = execWriter $ src C.$$ sink+ in L.fromChunks bss == lbs++ describe "passthroughSink" $ do+ it "works" $ do+ ref <- I.newIORef (-1)+ let sink = CL.fold (+) (0 :: Int)+ conduit = C.passthroughSink sink (I.writeIORef ref)+ input = [1..10]+ output <- mapM_ C.yield input C.$$ conduit C.=$ CL.consume+ output `shouldBe` input+ x <- I.readIORef ref+ x `shouldBe` sum input+ it "does nothing when downstream does nothing" $ do+ ref <- I.newIORef (-1)+ let sink = CL.fold (+) (0 :: Int)+ conduit = C.passthroughSink sink (I.writeIORef ref)+ input = [undefined]+ mapM_ C.yield input C.$$ conduit C.=$ return ()+ x <- I.readIORef ref+ x `shouldBe` (-1)+ describe "mtl instances" $ do it "ErrorT" $ do let src = flip catchError (const $ C.yield 4) $ do