conduit 1.0.0.2 → 1.0.1
raw patch · 5 files changed
+163/−438 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Conduit: data ConduitM i o m r
+ Data.Conduit.Text: DecodeException :: Codec -> Word8 -> TextException
+ Data.Conduit.Text: EncodeException :: Codec -> Char -> TextException
+ Data.Conduit.Text: TextException :: SomeException -> TextException
+ Data.Conduit.Text: data TextException
Files
- Data/Conduit.hs +140/−421
- Data/Conduit/Internal.hs +19/−8
- Data/Conduit/Text.hs +1/−1
- conduit.cabal +2/−2
- test/doctests.hs +1/−6
Data/Conduit.hs view
@@ -1,126 +1,49 @@ {-# LANGUAGE RankNTypes #-}-{- |--Let's start off with a few simple examples of @conduit@ usage. First, a file-copy utility:-->>> :load Data.Conduit.Binary->>> runResourceT $ sourceFile "input.txt" $$ sinkFile "output.txt"--@runResourceT@ is a function provided by the @resourcet@ package, and ensures-that resources are properly cleaned up, even in the presence of exceptions. The-type system will enforce that @runResourceT@ is called as needed. The remainder-of this tutorial will not discuss @runResourceT@; please see the documentation-in @resourcet@ for more information.--Looking at the rest of our example, there are three components to understand:-@sourceFile@, @sinkFile@, and the @$$@ operator (called \"connect\"). These-represent the most basic building blocks in @conduit@: a @Source@ produces a-stream of values, a @Sink@ consumes such a stream, and @$$@ will combine these-together.--In the case of file copying, there was no value produced by the @Sink@.-However, often times a @Sink@ will produce some result value. For example:-->>> :load Data.Conduit.List->>> :module +Prelude->>> sourceList [1..10] $$ fold (+) 0-55--@sourceList@ is a convenience function for turning a list into a @Source@.-@fold@ implements a strict left fold for consuming the input stream.--The next major aspect to the @conduit@ library is the @Conduit@ type.-This type represents a stream /transformer/. In order to use a @Conduit@, we-must /fuse/ it with either a @Source@ or @Sink@. For example:-->>> :load Data.Conduit.List->>> :module +Prelude->>> sourceList [1..10] $= Data.Conduit.List.map (+1) $$ consume-[2,3,4,5,6,7,8,9,10,11]--Notice the addition of the @$=@, or /left fuse/ operator. This combines a-@Source@ and a @Conduit@ into a new @Source@, which can then be connected to a-@Sink@ (in this case, @consume@). We can similarly perform /right fusion/ to-combine a @Conduit@ and @Sink@, or /middle fusion/ to combine two @Conduit@s.--A number of very common functions are provided in the "Data.Conduit.List"-module. Many of these functions correspond very closely to standard Haskell-functions.--In addition to connecting and fusing components together, we can also build up-more sophisticated components through monadic composition. For example, to-create a @Sink@ that ignores the first 3 numbers and returns the sum of the-remaining numbers, we can use:-->>> :load Data.Conduit.List->>> :module +Prelude->>> sourceList [1..10] $$ Data.Conduit.List.drop 3 >> fold (+) 0-49--In some cases, we might end up consuming more input than we needed, and want to-provide that input to the next component in our monadic chain. We refer to this-as /leftovers/. The simplest example of this is @peek@.-->>> :load Data.Conduit.List->>> :set -XNoMonomorphismRestriction->>> :module +Prelude->>> let sink = do { first <- peek; total <- fold (+) 0; return (first, total) }->>> sourceList [1..10] $$ sink-(Just 1,55)--Notice that, although we \"consumed\" the first value from the stream via-@peek@, it was still available to @fold@. This idea becomes even more important-when dealing with chunked data such as @ByteString@s or @Text@.--/Final note/: Notice in the types below that @Source@, @Sink@, and @Conduit@-are just type aliases. This will be explained later. Another important aspect-is resource finalization, which will also be covered below.---}+-- | If this is your first time with conduit, you should probably start with+-- the tutorial:+-- <https://haskell.fpcomplete.com/user/snoyberg/library-documentation/conduit-overview>. module Data.Conduit- ( -- * Conduit interface+ ( -- * Core interface+ -- ** Types Source , Conduit , Sink- -- ** Connect/fuse- -- $lifecycle+ , ConduitM+ -- ** Connect/fuse operators , ($$) , ($=) , (=$) , (=$=) - -- * Primitives- -- $primitives+ -- ** Primitives , await- , awaitForever , yield- , yieldOr , leftover+ -- ** Finalization , bracketP , addCleanup+ , yieldOr - -- * Connect-and-resume- -- $connectAndResume- , ResumableSource- , ($$+)- , ($$++)- , ($$+-)- , unwrapResumable+ -- * Generalized conduit types+ , Producer+ , Consumer+ , toProducer+ , toConsumer -- * Utility functions+ , awaitForever , transPipe , mapOutput , mapOutputMaybe , mapInput - -- * Generalized conduit types- -- $generalizedConduitTypes- , Producer- , Consumer- , toProducer- , toConsumer+ -- * Connect-and-resume+ , ResumableSource+ , ($$+)+ , ($$++)+ , ($$+-)+ , unwrapResumable -- * Flushing , Flush (..)@@ -142,277 +65,6 @@ import Data.Conduit.Internal hiding (await, awaitForever, yield, yieldOr, leftover, bracketP, addCleanup, transPipe, mapOutput, mapOutputMaybe, mapInput) import qualified Data.Conduit.Internal as CI --{- $lifecycle--It is important to understand the lifecycle of our components. Notice that we-can connect or fuse two components together. When we do this, the component-providing output is called /upstream/, and the component consuming this input-is called /downstream/. We can have arbitrarily long chains of such fusion, so-a single component can simultaneously function as /upstream/ and /downstream/.--Each component can be in one of four states of operation at any given time:--* It hasn't yet started operating.--* It is providing output downstream.--* It is waiting for input from upstream.--* It has completed processing.--Let\'s use @sourceFile@ and @sinkFile@ as an example. When we run @sourceFile-"input" $$ sinkFile "output"@, both components begin in the \"not started\"-state. Next, we start running @sinkFile@ (note: we /always/ begin processing on-the downstream component). @sinkFile@ will open up the file, and then wait for-input from upstream.--Next, we\'ll start running @sourceFile@, which will open the file, read some-data from it, and provide it as output downstream. This will be fed to-@sinkFile@ (which was already waiting). @sinkFile@ will write the data to a-file, then ask for more input. This process will continue until @sourceFile@-reaches the end of the input. It will close the file handle and switch to the-completed state. When this happens, @sinkFile@ is sent a signal that no more-input is available. It will then close its file and return a result.--Now let\'s change things up a bit. Suppose we were instead connecting-@sourceFile@ to @take 1@. We start by running @take 1@, which will wait for-some input. We\'ll then start @sourceFile@, which will open the file, read a-chunk, and send it downstream. @take 1@ will take that single chunk and return-it as a result. Once it does this, it has transitioned to the complete state.--We don\'t want to pull any more data from @sourceFile@, as we do not need it.-So instead, we call @sourceFile@\'s finalizer. Each time upstream provides-output, it also provides a finalizer to be run if downstream finishes-processing.--One final case: suppose we connect @sourceFile@ to @return ()@. The latter does-nothing: it immediately switches to the complete state. In this case, we never-even start running @sourceFile@ (it stays in the \"not yet started\" state),-and so no finalization occurs.--So here are the takeaways from the above discussion:--* When upstream completes before downstream, it cleans up all of its resources- and sends some termination signal. We never think about upstream again. This- can only occur while downstream is in the \"waiting for input\" state, since- that is the only time that upstream is called.--* When downstream completes before upstream, we finalize upstream immediately.- This can only occur when upstream produces output, because that\'s the only- time when control is passed back to downstream.--* If downstream never awaits for input before it terminates, upstream was never- started, and therefore it does not need to be finalized.--Note that all of the discussion above applies equally well to chains of-components. If you have an upstream, middle, and downstream component, and-downstream terminates, then the middle component will be finalized, which in-turn will trigger upstream to be finalized. This setup ensures that we always-have prompt resource finalization.---}--{- $pipeInterface--We discussed three main types in the @conduit@ package: @Source@, @Sink@, and-@Conduit@. In fact, these are all unified into a single type, @Pipe@. This-greatly simplifies the internal workings of this package, and makes it much-easier to build more powerful components from simpler ones. For example, it is-easy to combine a number of simple @Sink@s together to produce a more powerful-@Conduit@. To create a @Conduit@ which drops 3 input elements and doubles the-rest, we could use:-->>> :load Data.Conduit.List->>> :set -XNoMonomorphismRestriction->>> let conduit = do { drop 3; map (Prelude.* 2) }->>> sourceList [1..10] $$ conduit =$ consume-[8,10,12,14,16,18,20]--If we look again at our examples from above, we'll see a few different aspects-to @Pipe@s:--* @Sink@s and @Conduit@s can consume a stream of /input/ values. Both @map@ and- @fold@ took a stream of @Int@s, while @sinkFile@ took a stream of- @ByteString@s.--* @Source@s and @Conduit@s can produce a stream of /output/ values. @sourceFile@- produced a stream of @ByteString@s, which was then consumed by @sinkFile@. This- is an important point in @conduit@: the output of the left-hand pipe (a.k.a.,- /upstream/) must match the input of the right-hand pipe (a.k.a., /downstream/).--* All @Pipe@s have some underlying @Monad@. The @sourceFile@ and @sinkFile@- functions needed to use @MonadResource@ from @resourcet@ to get exception- handling, but our other functions could live in any monad. Since @Pipe@- provides a @MonadTrans@ instance, you can actually lift any action from the- underlying @Monad@ into your @Pipe@.--* @Sink@s can provide a /result/ type. Our @fold@ returned a final @Int@, while- @sinkFile@ returned @()@.--A @Pipe@ also exposes two other features as well, not covered by the above-three types:--* Each @Pipe@ has some /leftover/ value. Above, we described a situation where- the leftover would be identical to the input type. However, @Pipe@ provides a- type parameter for this instead, so that you can alternatively set the leftover- type to 'Void', thereby ensuring that a @Pipe@ does not provide any leftover- values. This is important for ensuring that leftover values aren't accidentally- discarded.--* Above, we described a situation where only @Sink@s could return results.- However, sometimes it's advantageous to allow stream producers to also produce- a result type. We call this the /upstream/ result.--Putting this all together, a @Pipe@ has six type parameters: @Pipe l i o u m r@,-corresponding to each of the bullets above. @Source@, @Conduit@, and @Sink@ are-simply type aliases that restrict one or more of these type parameters to-specific types. For example, both @Source@ and @Conduit@ have @r@ restricted to-@()@, since neither may return a result.--There are two ways that @Pipe@s can be composed: via the @Monad@ instance, and-via fusion. (/Note/: connecting is just a special case of fusion, where the-@Pipe@ is then run. We'll discuss that more later on.) In the @pipes@ package,-these are referred to as /vertical/ and /horizontal/ composition, respectively.-Let's clarify the distinction between these two:--Monadic composition takes two @Pipe@s with the same input and output types, and-combines them into a single @Pipe@. These two @Pipe@s will be run one after the-other, and they will share the same input and output streams. Essentially, the-second @Pipe@ will continue consuming input where the first left off, and the-output streams of each will be concatenated. Any leftover values from the first-@Pipe@ will be fed to the second @Pipe@. Let\'s see a simple example:-->>> :load Data.Conduit.List->>> sourceList [1..10] $$ do { x <- take 3; y <- take 2; return (x, y) }-([1,2,3],[4,5])--Fusion, on the other hand, will connect the output from an upstream @Pipe@ to-the input of a downstream @Pipe@. The upstream @Pipe@ is required to have a-result type of @()@, since any results it produces are thrown out. This form of-composition produces a new @Pipe@ with the input parameter of the upstream-@Pipe@ and the output and result parameters of the downstream @Pipe@. (For-examples, see the initial examples on this page. Every usage of the connect or-fusion operators is fusion composition.)--/Note/: If you are building a library of @conduit@ functions, it is best to-keep the type signatures as general as possible. For example, even though the-simplest type signature for the @drop@ function would be @Int -> Sink i m ()@,-this would prevent it from being used in construction of @Conduit@s. Instead,-we give it a type signature of @Int -> Pipe l i o u m ()@.---}--{- $primitives--While @conduit@ provides a number of built-in @Source@s, @Sink@s, and-@Conduit@s, you will almost certainly want to construct some of your own.-Previous versions recommended using the constructors directly. Beginning with-0.5, the recommended approach is to compose existing @Pipe@s into larger ones.--It is certainly possible (and advisable!) to leverage existing @Pipe@s- like-those in "Data.Conduit.List". However, you will often need to go to a lower-level set of @Pipe@s to start your composition. The following few functions-should be sufficient for expressing all constructs besides finalization. Adding-in @bracketP@ and @addCleanup@, you should be able to create any @Pipe@ you-need. (In fact, that's precisely how the remainder of this package is written.)--The three basic operations are /awaiting/, /yielding/, and /leftovers/.-Awaiting asks for a new value from upstream, or returns @Nothing@ if upstream-is done. For example:-->>> :load Data.Conduit.List->>> sourceList [1..10] $$ await-Just 1-->>> :load Data.Conduit.List->>> sourceList [] $$ await-Nothing--Similarly, we have a @yield@ function, which provides a value to the downstream-@Pipe@. @yield@ features /auto-termination/: if the downstream @Pipe@ has-already completed processing, the upstream @Pipe@ will stop processing when it-tries to @yield@.--The upshot of this is that you can write code that appears to loop infinitely,-and yet will terminate.-->>> :set -XNoMonomorphismRestriction->>> let infinite = yield () >> infinite->>> infinite $$ await-Just ()--Or for something a bit more sophisticated:-->>> let enumFrom' i = yield i >> enumFrom' (succ i)->>> enumFrom' 1 $$ take 5-[1,2,3,4,5]--The final primitive @Pipe@ is @leftover@. This allows you to return unused-input to be used by the next @Pipe@ in the monadic chain. A simple use case-would be implementing the @peek@ function:-->>> let peek = await >>= maybe (return Nothing) (\x -> leftover x >> return (Just x))->>> enumFrom' 1 $$ do { mx <- peek; my <- await; mz <- await; return (mx, my, mz) }-(Just 1,Just 1,Just 2)--Note that you should only return leftovers that were previously yielded from-upstream.---}--{- $connectAndResume--Sometimes, we do not want to force our entire application to live inside the-@Pipe@ monad. It can be convenient to keep normal control flow of our program,-and incrementally apply data from a @Source@ to various @Sink@s. A strong-motivating example for this use case is interleaving multiple @Source@s, such-as combining a @conduit@-powered HTTP server and client into an HTTP proxy.--Normally, when we run a @Pipe@, we get a result and can never run it again.-Connect-and-resume allows us to connect a @Source@ to a @Sink@ until the latter-completes, and then return the current state of the @Source@ to be applied-later. To do so, we introduce three new operators. Let\' start off by-demonstrating them:-->>> :load Data.Conduit.List->>> (next, x) <- sourceList [1..10] $$+ take 5->>> Prelude.print x-[1,2,3,4,5]->>> (next, y) <- next $$++ (isolate 4 =$ fold (Prelude.+) 0)->>> Prelude.print y-30->>> next $$+- consume-[10]---}--{- $generalizedConduitTypes--It's recommended to keep your type signatures as general as possible to-encourage reuse. For example, a theoretical signature for the @head@ function-would be:--> head :: Sink a m (Maybe a)--However, doing so would prevent usage of @head@ from inside a @Conduit@, since-a @Sink@ sets its output type parameter to @Void@. The most general type-signature would instead be:--> head :: Pipe l a o u m (Maybe a)--However, that signature is much more confusing. To bridge this gap, we also-provide some generalized conduit types. They follow a simple naming convention:--* They have the same name as their non-generalized types, with a @G@ prepended.--* If they have leftovers, we add an @L@.--* If they consume the entirety of their input stream and return the upstream- result, we add @Inf@ to indicate /infinite consumption/.---}- -- Define fixity of all our operators infixr 0 $$ infixl 1 $=@@ -423,8 +75,7 @@ infixr 0 $$+- -- | The connect operator, which pulls data from a source and pushes to a sink.--- When either side closes, the other side will immediately be closed as well.--- If you would like to keep the @Source@ open to be used for another+-- If you would like to keep the @Source@ open to be used for other -- operations, use the connect-and-resume operator '$$+'. -- -- Since 0.4.0@@ -470,6 +121,123 @@ ConduitM left =$= ConduitM right = ConduitM $ pipeL left right {-# INLINE (=$=) #-} +-- | Wait for a single input value from upstream. If no data is available,+-- returns @Nothing@.+--+-- Since 0.5.0+await :: Monad m => Consumer i m (Maybe i)+await = ConduitM CI.await++-- | Send a value downstream to the next component to consume. If the+-- downstream component terminates, this call will never return control. If you+-- would like to register a cleanup function, please use 'yieldOr' instead.+--+-- Since 0.5.0+yield :: Monad m+ => o -- ^ output value+ -> ConduitM i o m ()+yield = ConduitM . CI.yield++-- | Provide a single piece of leftover input to be consumed by the next+-- component in the current monadic binding.+--+-- /Note/: it is highly encouraged to only return leftover values from input+-- already consumed from upstream.+--+-- Since 0.5.0+leftover :: i -> ConduitM i o m ()+leftover = ConduitM . CI.leftover++-- | Perform some allocation and run an inner component. Two guarantees are+-- given about resource finalization:+--+-- 1. It will be /prompt/. The finalization will be run as early as possible.+--+-- 2. It is exception safe. Due to usage of @resourcet@, the finalization will+-- be run in the event of any exceptions.+--+-- Since 0.5.0+bracketP :: MonadResource m+ => IO a+ -> (a -> IO ())+ -> (a -> ConduitM i o m r)+ -> ConduitM i o m r+bracketP alloc free inside = ConduitM $ CI.bracketP alloc free $ unConduitM . inside++-- | Add some code to be run when the given component cleans up.+--+-- The supplied cleanup function will be given a @True@ if the component ran to+-- completion, or @False@ if it terminated early due to a downstream component+-- terminating.+--+-- Note that this function is not exception safe. For that, please use+-- 'bracketP'.+--+-- Since 0.4.1+addCleanup :: Monad m+ => (Bool -> m ())+ -> ConduitM i o m r+ -> ConduitM i o m r+addCleanup f = ConduitM . CI.addCleanup f . unConduitM++-- | Similar to 'yield', but additionally takes a finalizer to be run if the+-- downstream component terminates.+--+-- Since 0.5.0+yieldOr :: Monad m+ => o+ -> m () -- ^ finalizer+ -> ConduitM i o m ()+yieldOr o m = ConduitM $ CI.yieldOr o m++-- | Wait for input forever, calling the given inner component for each piece of+-- new input. Returns the upstream result type.+--+-- This function is provided as a convenience for the common pattern of+-- @await@ing input, checking if it's @Just@ and then looping.+--+-- Since 0.5.0+awaitForever :: Monad m => (i -> ConduitM i o m r) -> ConduitM i o m ()+awaitForever f = ConduitM $ CI.awaitForever (unConduitM . f)++-- | Transform the monad that a @ConduitM@ lives in.+--+-- Note that the monad transforming function will be run multiple times,+-- resulting in unintuitive behavior in some cases. For a fuller treatment,+-- please see:+--+-- <https://github.com/snoyberg/conduit/wiki/Dealing-with-monad-transformers>+--+-- Since 0.4.0+transPipe :: Monad m => (forall a. m a -> n a) -> ConduitM i o m r -> ConduitM i o n r+transPipe f = ConduitM . CI.transPipe f . unConduitM++-- | Apply a function to all the output values of a @ConduitM@.+--+-- This mimics the behavior of `fmap` for a `Source` and `Conduit` in pre-0.4+-- days. It can also be simulated by fusing with the @map@ conduit from+-- "Data.Conduit.List".+--+-- Since 0.4.1+mapOutput :: Monad m => (o1 -> o2) -> ConduitM i o1 m r -> ConduitM i o2 m r+mapOutput f (ConduitM p) = ConduitM $ CI.mapOutput f p++-- | Same as 'mapOutput', but use a function that returns @Maybe@ values.+--+-- Since 0.5.0+mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> ConduitM i o1 m r -> ConduitM i o2 m r+mapOutputMaybe f (ConduitM p) = ConduitM $ CI.mapOutputMaybe f p++-- | Apply a function to all the input values of a @ConduitM@.+--+-- Since 0.5.0+mapInput :: Monad m+ => (i1 -> i2) -- ^ map initial input to new input+ -> (i2 -> Maybe i1) -- ^ map new leftovers to initial leftovers+ -> ConduitM i2 o m r+ -> ConduitM i1 o m r+mapInput f g (ConduitM p) = ConduitM $ CI.mapInput f g p+ -- | The connect-and-resume operator. This does not close the @Source@, but -- instead returns it to be used again. This allows a @Source@ to be used -- incrementally in a large program, without forcing the entire program to live@@ -513,52 +281,3 @@ instance Functor Flush where fmap _ Flush = Flush fmap f (Chunk a) = Chunk (f a)--await :: Monad m => Consumer i m (Maybe i)-await = ConduitM CI.await--mapOutput :: Monad m => (o1 -> o2) -> ConduitM i o1 m r -> ConduitM i o2 m r-mapOutput f (ConduitM p) = ConduitM $ CI.mapOutput f p--mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> ConduitM i o1 m r -> ConduitM i o2 m r-mapOutputMaybe f (ConduitM p) = ConduitM $ CI.mapOutputMaybe f p--mapInput :: Monad m- => (i1 -> i2) -- ^ map initial input to new input- -> (i2 -> Maybe i1) -- ^ map new leftovers to initial leftovers- -> ConduitM i2 o m r- -> ConduitM i1 o m r-mapInput f g (ConduitM p) = ConduitM $ CI.mapInput f g p--transPipe :: Monad m => (forall a. m a -> n a) -> ConduitM i o m r -> ConduitM i o n r-transPipe f = ConduitM . CI.transPipe f . unConduitM--addCleanup :: Monad m- => (Bool -> m ()) -- ^ @True@ if @Pipe@ ran to completion, @False@ for early termination.- -> ConduitM i o m r- -> ConduitM i o m r-addCleanup f = ConduitM . CI.addCleanup f . unConduitM--bracketP :: MonadResource m- => IO a- -> (a -> IO ())- -> (a -> ConduitM i o m r)- -> ConduitM i o m r-bracketP alloc free inside = ConduitM $ CI.bracketP alloc free $ unConduitM . inside--leftover :: i -> ConduitM i o m ()-leftover = ConduitM . CI.leftover--yield :: Monad m- => o -- ^ output value- -> ConduitM i o m ()-yield = ConduitM . CI.yield--yieldOr :: Monad m- => o- -> m () -- ^ finalizer- -> ConduitM i o m ()-yieldOr o m = ConduitM $ CI.yieldOr o m--awaitForever :: Monad m => (i -> ConduitM i o m r) -> ConduitM i o m ()-awaitForever f = ConduitM $ CI.awaitForever (unConduitM . f)
Data/Conduit/Internal.hs view
@@ -139,6 +139,13 @@ instance MonadResource m => MonadResource (Pipe l i o u m) where liftResourceT = lift . liftResourceT +-- | Core datatype of the conduit package. This type represents a general+-- component which can consume a stream of input values @i@, produce a stream+-- of output values @o@, perform actions in the @m@ monad, and produce a final+-- result @r@. The type synonyms provided here are simply wrappers around this+-- type.+--+-- Since 1.0.0 newtype ConduitM i o m r = ConduitM { unConduitM :: Pipe i i o () m r } deriving (Functor, Applicative, Monad, MonadIO, MonadTrans, MonadThrow, MonadActive, MonadResource) instance MonadBase base m => MonadBase base (ConduitM i o m) where@@ -153,9 +160,11 @@ -- Since 0.5.0 type Source m o = ConduitM () o m () --- | Generalized 'Source'.+-- | A component which produces a stream of output values, regardless of the+-- input stream. A @Producer@ is a generalization of a @Source@, and can be+-- used as either a @Source@ or a @Conduit@. ----- Since 0.5.0+-- Since 1.0.0 type Producer m o = forall i. ConduitM i o m () -- | Consumes a stream of input values and produces a final result, without@@ -164,9 +173,11 @@ -- Since 0.5.0 type Sink i m r = ConduitM i Void m r --- | Generalized 'Sink' without leftovers.+-- | A component which consumes a stream of input values and produces a final+-- result, regardless of the output stream. A @Consumer@ is a generalization of+-- a @Sink@, and can be used as either a @Sink@ or a @Conduit@. ----- Since 0.5.0+-- Since 1.0.0 type Consumer i m r = forall o. ConduitM i o m r -- | Consumes a stream of input values and produces a stream of output values,@@ -183,8 +194,7 @@ -- Since 0.5.0 data ResumableSource m o = ResumableSource (Source m o) (m ()) --- | Wait for a single input value from upstream, terminating immediately if no--- data is available.+-- | Wait for a single input value from upstream. -- -- Since 0.5.0 await :: Pipe l i o u m (Maybe i)@@ -548,6 +558,7 @@ -- appropriately. By appropriately, I mean: -- -- * If a new finalizer is registered, the old one should not be called.+-- -- * If the old one is called, it should not be called again. -- -- This function returns both a @Source@ and a finalizer which ensures that the@@ -584,7 +595,7 @@ (<+<) = flip pipe {-# INLINE (<+<) #-} --- | Convert a 'Source' into a 'Producer'.+-- | Generalize a 'Source' to a 'Producer'. -- -- Since 1.0.0 toProducer :: Monad m => Source m a -> Producer m a@@ -597,7 +608,7 @@ go (PipeM mp) = PipeM (liftM go mp) go (Leftover p ()) = go p --- | Convert a 'Sink' into a 'Consumer'.+-- | Generalize a 'Sink' to a 'Consumer'. -- -- Since 1.0.0 toConsumer :: Monad m => Sink a m b -> Consumer a m b
Data/Conduit/Text.hs view
@@ -21,7 +21,7 @@ , ascii , iso8859_1 , lines-+ , TextException (..) ) where import qualified Prelude
conduit.cabal view
@@ -1,8 +1,8 @@ Name: conduit-Version: 1.0.0.2+Version: 1.0.1 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 brief tutorial, please see the "Data.Conduit" module.+ @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>. . Release history: .
test/doctests.hs view
@@ -1,11 +1,6 @@ module Main where -import System.Directory import Test.DocTest main :: IO ()-main = do- writeFile "input.txt" "some dummy content"- doctest ["Data/Conduit.hs"]- removeFile "input.txt"- removeFile "output.txt"+main = doctest ["Data/Conduit.hs"]