conduit 1.2.13.1 → 1.3.0
raw patch · 34 files changed
+10081/−4922 lines, 34 filesdep +Win32dep +bytestringdep +directorydep −criteriondep −lifted-basedep −mmorphdep ~basedep ~exceptionsdep ~resourcetPVP ok
version bump matches the API change (PVP)
Dependencies added: Win32, bytestring, directory, filepath, gauge, mono-traversable, silently, text, unix, unliftio, unliftio-core
Dependencies removed: criterion, lifted-base, mmorph, monad-control, semigroups, transformers-base, transformers-compat, void
Dependency ranges changed: base, exceptions, resourcet, transformers
API changes (from Hackage documentation)
- Data.Conduit: addCleanup :: Monad m => (Bool -> m ()) -> ConduitM i o m r -> ConduitM i o m r
- Data.Conduit: closeResumableSource :: Monad m => ResumableSource m a -> m ()
- Data.Conduit: data ConduitM i o m r
- Data.Conduit: data ResumableConduit i m o
- Data.Conduit: data ResumableSource m o
- Data.Conduit: newResumableConduit :: Monad m => Conduit i m o -> ResumableConduit i m o
- Data.Conduit: newResumableSource :: Monad m => Source m o -> ResumableSource m o
- Data.Conduit: unwrapResumable :: MonadIO m => ResumableSource m o -> m (Source m o, m ())
- Data.Conduit: unwrapResumableConduit :: MonadIO m => ResumableConduit i m o -> m (Conduit i m o, m ())
- Data.Conduit: yieldOr :: Monad m => o -> m () -> ConduitM i o m ()
- Data.Conduit.Internal: ConduitM :: (forall b. (r -> Pipe i i o () m b) -> Pipe i i o () m b) -> ConduitM i o m r
- Data.Conduit.Internal: ResumableConduit :: (Pipe i i o () m ()) -> (m ()) -> ResumableConduit i m o
- Data.Conduit.Internal: ResumableSource :: (Pipe () () o () m ()) -> (m ()) -> ResumableSource m o
- Data.Conduit.Internal: [unConduitM] :: ConduitM i o m r -> forall b. (r -> Pipe i i o () m b) -> Pipe i i o () m b
- Data.Conduit.Internal: addCleanup :: Monad m => (Bool -> m ()) -> ConduitM i o m r -> ConduitM i o m r
- Data.Conduit.Internal: closeResumableSource :: Monad m => ResumableSource m a -> m ()
- Data.Conduit.Internal: data ResumableConduit i m o
- Data.Conduit.Internal: data ResumableSource m o
- Data.Conduit.Internal: newResumableConduit :: Monad m => Conduit i m o -> ResumableConduit i m o
- Data.Conduit.Internal: newResumableSource :: Monad m => Source m o -> ResumableSource m o
- Data.Conduit.Internal: newtype ConduitM i o m r
- Data.Conduit.Internal: unwrapResumable :: MonadIO m => ResumableSource m o -> m (Source m o, m ())
- Data.Conduit.Internal: unwrapResumableConduit :: MonadIO m => ResumableConduit i m o -> m (Conduit i m o, m ())
- Data.Conduit.Internal: yieldOr :: Monad m => o -> m () -> ConduitM i o m ()
- Data.Conduit.Internal.Fusion: type StreamConduitM i o m r = Stream m i () -> Stream m o r
- Data.Conduit.Lift: catchErrorC :: (Monad m, Error e) => ConduitM i o (ErrorT e m) r -> (e -> ConduitM i o (ErrorT e m) r) -> ConduitM i o (ErrorT e m) r
- Data.Conduit.Lift: distribute :: (Monad (t (ConduitM b o m)), Monad m, Monad (t m), MonadTrans t, MFunctor t) => ConduitM b o (t m) () -> t (ConduitM b o m) ()
- Data.Conduit.Lift: errorC :: (Monad m, Monad (t (ErrorT e m)), MonadTrans t, Error e, MFunctor t) => t m (Either e b) -> t (ErrorT e m) b
- Data.Conduit.Lift: runErrorC :: (Monad m, Error e) => ConduitM i o (ErrorT e m) r -> ConduitM i o m (Either e r)
+ Conduit: Identity :: a -> Identity a
+ Conduit: [runIdentity] :: Identity a -> a
+ Conduit: allC :: Monad m => (a -> Bool) -> ConduitT a o m Bool
+ Conduit: allCE :: (Monad m, MonoFoldable mono) => (Element mono -> Bool) -> ConduitT mono o m Bool
+ Conduit: allNewBuffersStrategy :: Int -> BufferAllocStrategy
+ Conduit: andC :: Monad m => ConduitT Bool o m Bool
+ Conduit: andCE :: (Monad m, MonoFoldable mono, Element mono ~ Bool) => ConduitT mono o m Bool
+ Conduit: anyC :: Monad m => (a -> Bool) -> ConduitT a o m Bool
+ Conduit: anyCE :: (Monad m, MonoFoldable mono) => (Element mono -> Bool) -> ConduitT mono o m Bool
+ Conduit: askUnliftIO :: MonadUnliftIO m => m UnliftIO m
+ Conduit: asumC :: (Monad m, Alternative f) => ConduitT (f a) o m (f a)
+ Conduit: awaitNonNull :: (Monad m, MonoFoldable a) => ConduitT a o m (Maybe (NonNull a))
+ Conduit: builderToByteString :: PrimMonad m => ConduitT Builder ByteString m ()
+ Conduit: builderToByteStringFlush :: PrimMonad m => ConduitT (Flush Builder) (Flush ByteString) m ()
+ Conduit: builderToByteStringWith :: PrimMonad m => BufferAllocStrategy -> ConduitT Builder ByteString m ()
+ Conduit: builderToByteStringWithFlush :: PrimMonad m => BufferAllocStrategy -> ConduitT (Flush Builder) (Flush ByteString) m ()
+ Conduit: chunksOfCE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq seq m ()
+ Conduit: chunksOfExactlyCE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq seq m ()
+ Conduit: class Monad m => MonadIO (m :: * -> *)
+ Conduit: class MonadIO m => MonadResource (m :: * -> *)
+ Conduit: class Monad m => MonadThrow (m :: * -> *)
+ Conduit: class MonadTrans (t :: (* -> *) -> * -> *)
+ Conduit: class MonadIO m => MonadUnliftIO (m :: * -> *)
+ Conduit: class Monad m => PrimMonad (m :: * -> *) where {
+ Conduit: concatC :: (Monad m, MonoFoldable mono) => ConduitT mono (Element mono) m ()
+ Conduit: concatMapAccumC :: Monad m => (a -> accum -> (accum, [b])) -> accum -> ConduitT a b m ()
+ Conduit: concatMapAccumMC :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> ConduitT a b m ()
+ Conduit: concatMapC :: (Monad m, MonoFoldable mono) => (a -> mono) -> ConduitT a (Element mono) m ()
+ Conduit: concatMapCE :: (Monad m, MonoFoldable mono, Monoid w) => (Element mono -> w) -> ConduitT mono w m ()
+ Conduit: concatMapMC :: (Monad m, MonoFoldable mono) => (a -> m mono) -> ConduitT a (Element mono) m ()
+ Conduit: conduitVector :: (Vector v a, PrimMonad m) => Int -> ConduitT a (v a) m ()
+ Conduit: data ResourceT (m :: * -> *) a :: (* -> *) -> * -> *
+ Conduit: decodeUtf8C :: MonadThrow m => ConduitT ByteString Text m ()
+ Conduit: decodeUtf8LenientC :: Monad m => ConduitT ByteString Text m ()
+ Conduit: dropC :: Monad m => Int -> ConduitT a o m ()
+ Conduit: dropCE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq o m ()
+ Conduit: dropWhileC :: Monad m => (a -> Bool) -> ConduitT a o m ()
+ Conduit: dropWhileCE :: (Monad m, IsSequence seq) => (Element seq -> Bool) -> ConduitT seq o m ()
+ Conduit: elemC :: (Monad m, Eq a) => a -> ConduitT a o m Bool
+ Conduit: elemCE :: (Monad m, IsSequence seq, Eq (Element seq)) => Element seq -> ConduitT seq o m Bool
+ Conduit: encodeUtf8C :: (Monad m, Utf8 text binary) => ConduitT text binary m ()
+ Conduit: enumFromToC :: (Monad m, Enum a, Ord a) => a -> a -> ConduitT i a m ()
+ Conduit: filterC :: Monad m => (a -> Bool) -> ConduitT a a m ()
+ Conduit: filterCE :: (IsSequence seq, Monad m) => (Element seq -> Bool) -> ConduitT seq seq m ()
+ Conduit: filterMC :: Monad m => (a -> m Bool) -> ConduitT a a m ()
+ Conduit: filterMCE :: (Monad m, IsSequence seq) => (Element seq -> m Bool) -> ConduitT seq seq m ()
+ Conduit: findC :: Monad m => (a -> Bool) -> ConduitT a o m (Maybe a)
+ Conduit: foldC :: (Monad m, Monoid a) => ConduitT a o m a
+ Conduit: foldCE :: (Monad m, MonoFoldable mono, Monoid (Element mono)) => ConduitT mono o m (Element mono)
+ Conduit: foldMC :: Monad m => (a -> b -> m a) -> a -> ConduitT b o m a
+ Conduit: foldMCE :: (Monad m, MonoFoldable mono) => (a -> Element mono -> m a) -> a -> ConduitT mono o m a
+ Conduit: foldMapC :: (Monad m, Monoid b) => (a -> b) -> ConduitT a o m b
+ Conduit: foldMapCE :: (Monad m, MonoFoldable mono, Monoid w) => (Element mono -> w) -> ConduitT mono o m w
+ Conduit: foldMapMC :: (Monad m, Monoid w) => (a -> m w) -> ConduitT a o m w
+ Conduit: foldMapMCE :: (Monad m, MonoFoldable mono, Monoid w) => (Element mono -> m w) -> ConduitT mono o m w
+ Conduit: foldlC :: Monad m => (a -> b -> a) -> a -> ConduitT b o m a
+ Conduit: foldlCE :: (Monad m, MonoFoldable mono) => (a -> Element mono -> a) -> a -> ConduitT mono o m a
+ Conduit: headC :: Monad m => ConduitT a o m (Maybe a)
+ Conduit: headCE :: (Monad m, IsSequence seq) => ConduitT seq o m (Maybe (Element seq))
+ Conduit: headDefC :: Monad m => a -> ConduitT a o m a
+ Conduit: intersperseC :: Monad m => a -> ConduitT a a m ()
+ Conduit: iterMC :: Monad m => (a -> m ()) -> ConduitT a a m ()
+ Conduit: iterateC :: Monad m => (a -> a) -> a -> ConduitT i a m ()
+ Conduit: lastC :: Monad m => ConduitT a o m (Maybe a)
+ Conduit: lastCE :: (Monad m, IsSequence seq) => ConduitT seq o m (Maybe (Element seq))
+ Conduit: lastDefC :: Monad m => a -> ConduitT a o m a
+ Conduit: lengthC :: (Monad m, Num len) => ConduitT a o m len
+ Conduit: lengthCE :: (Monad m, Num len, MonoFoldable mono) => ConduitT mono o m len
+ Conduit: lengthIfC :: (Monad m, Num len) => (a -> Bool) -> ConduitT a o m len
+ Conduit: lengthIfCE :: (Monad m, Num len, MonoFoldable mono) => (Element mono -> Bool) -> ConduitT mono o m len
+ Conduit: lift :: (MonadTrans t, Monad m) => m a -> t m a
+ Conduit: liftIO :: MonadIO m => IO a -> m a
+ Conduit: lineAsciiC :: (Monad m, IsSequence seq, Element seq ~ Word8) => ConduitT seq o m r -> ConduitT seq o m r
+ Conduit: lineC :: (Monad m, IsSequence seq, Element seq ~ Char) => ConduitT seq o m r -> ConduitT seq o m r
+ Conduit: linesUnboundedAsciiC :: (Monad m, IsSequence seq, Element seq ~ Word8) => ConduitT seq seq m ()
+ Conduit: linesUnboundedC :: (Monad m, IsSequence seq, Element seq ~ Char) => ConduitT seq seq m ()
+ Conduit: mapAccumS :: Monad m => (a -> s -> ConduitT b Void m s) -> s -> ConduitT () b m () -> ConduitT a Void m s
+ Conduit: mapAccumWhileC :: Monad m => (a -> s -> Either s (s, b)) -> s -> ConduitT a b m s
+ Conduit: mapAccumWhileMC :: Monad m => (a -> s -> m (Either s (s, b))) -> s -> ConduitT a b m s
+ Conduit: mapC :: Monad m => (a -> b) -> ConduitT a b m ()
+ Conduit: mapCE :: (Monad m, Functor f) => (a -> b) -> ConduitT (f a) (f b) m ()
+ Conduit: mapMC :: Monad m => (a -> m b) -> ConduitT a b m ()
+ Conduit: mapMCE :: (Monad m, Traversable f) => (a -> m b) -> ConduitT (f a) (f b) m ()
+ Conduit: mapM_C :: Monad m => (a -> m ()) -> ConduitT a o m ()
+ Conduit: mapM_CE :: (Monad m, MonoFoldable mono) => (Element mono -> m ()) -> ConduitT mono o m ()
+ Conduit: mapWhileC :: Monad m => (a -> Maybe b) -> ConduitT a b m ()
+ Conduit: maximumC :: (Monad m, Ord a) => ConduitT a o m (Maybe a)
+ Conduit: maximumCE :: (Monad m, IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))
+ Conduit: minimumC :: (Monad m, Ord a) => ConduitT a o m (Maybe a)
+ Conduit: minimumCE :: (Monad m, IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))
+ Conduit: newtype Identity a :: * -> *
+ Conduit: notElemC :: (Monad m, Eq a) => a -> ConduitT a o m Bool
+ Conduit: notElemCE :: (Monad m, IsSequence seq, Eq (Element seq)) => Element seq -> ConduitT seq o m Bool
+ Conduit: nullC :: Monad m => ConduitT a o m Bool
+ Conduit: nullCE :: (Monad m, MonoFoldable mono) => ConduitT mono o m Bool
+ Conduit: omapCE :: (Monad m, MonoFunctor mono) => (Element mono -> Element mono) -> ConduitT mono mono m ()
+ Conduit: omapMCE :: (Monad m, MonoTraversable mono) => (Element mono -> m (Element mono)) -> ConduitT mono mono m ()
+ Conduit: orC :: Monad m => ConduitT Bool o m Bool
+ Conduit: orCE :: (Monad m, MonoFoldable mono, Element mono ~ Bool) => ConduitT mono o m Bool
+ Conduit: peekC :: Monad m => ConduitT a o m (Maybe a)
+ Conduit: peekCE :: (Monad m, MonoFoldable mono) => ConduitT mono o m (Maybe (Element mono))
+ Conduit: peekForever :: Monad m => ConduitT i o m () -> ConduitT i o m ()
+ Conduit: peekForeverE :: (Monad m, MonoFoldable i) => ConduitT i o m () -> ConduitT i o m ()
+ Conduit: primitive :: PrimMonad m => (State# PrimState m -> (# TupleRep [] RuntimeRep, LiftedRep, State# PrimState m, a #)) -> m a
+ Conduit: printC :: (Show a, MonadIO m) => ConduitT a o m ()
+ Conduit: productC :: (Monad m, Num a) => ConduitT a o m a
+ Conduit: productCE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)
+ Conduit: repeatC :: Monad m => a -> ConduitT i a m ()
+ Conduit: repeatMC :: Monad m => m a -> ConduitT i a m ()
+ Conduit: repeatWhileMC :: Monad m => m a -> (a -> Bool) -> ConduitT i a m ()
+ Conduit: replicateC :: Monad m => Int -> a -> ConduitT i a m ()
+ Conduit: replicateMC :: Monad m => Int -> m a -> ConduitT i a m ()
+ Conduit: reuseBufferStrategy :: IO Buffer -> BufferAllocStrategy
+ Conduit: runResourceT :: MonadUnliftIO m => ResourceT m a -> m a
+ Conduit: scanlC :: Monad m => (a -> b -> a) -> a -> ConduitT b a m ()
+ Conduit: scanlMC :: Monad m => (a -> b -> m a) -> a -> ConduitT b a m ()
+ Conduit: sinkFile :: MonadResource m => FilePath -> ConduitT ByteString o m ()
+ Conduit: sinkFileBS :: MonadResource m => FilePath -> ConduitT ByteString o m ()
+ Conduit: sinkFileCautious :: MonadResource m => FilePath -> ConduitM ByteString o m ()
+ Conduit: sinkHandle :: MonadIO m => Handle -> ConduitT ByteString o m ()
+ Conduit: sinkHandleBuilder :: MonadIO m => Handle -> ConduitM Builder o m ()
+ Conduit: sinkHandleFlush :: MonadIO m => Handle -> ConduitM (Flush ByteString) o m ()
+ Conduit: sinkIOHandle :: MonadResource m => IO Handle -> ConduitT ByteString o m ()
+ Conduit: sinkLazy :: (Monad m, LazySequence lazy strict) => ConduitT strict o m lazy
+ Conduit: sinkLazyBuilder :: Monad m => ConduitT Builder o m ByteString
+ Conduit: sinkList :: Monad m => ConduitT a o m [a]
+ Conduit: sinkNull :: Monad m => ConduitT a o m ()
+ Conduit: sinkSystemTempFile :: MonadResource m => String -> ConduitM ByteString o m FilePath
+ Conduit: sinkTempFile :: MonadResource m => FilePath -> String -> ConduitM ByteString o m FilePath
+ Conduit: sinkVector :: (Vector v a, PrimMonad m) => ConduitT a o m (v a)
+ Conduit: sinkVectorN :: (Vector v a, PrimMonad m) => Int -> ConduitT a o m (v a)
+ Conduit: slidingWindowC :: (Monad m, IsSequence seq, Element seq ~ a) => Int -> ConduitT a seq m ()
+ Conduit: sourceDirectory :: MonadResource m => FilePath -> ConduitT i FilePath m ()
+ Conduit: sourceDirectoryDeep :: MonadResource m => Bool -> FilePath -> ConduitT i FilePath m ()
+ Conduit: sourceFile :: MonadResource m => FilePath -> ConduitT i ByteString m ()
+ Conduit: sourceFileBS :: MonadResource m => FilePath -> ConduitT i ByteString m ()
+ Conduit: sourceHandle :: MonadIO m => Handle -> ConduitT i ByteString m ()
+ Conduit: sourceHandleUnsafe :: MonadIO m => Handle -> ConduitT i ByteString m ()
+ Conduit: sourceIOHandle :: MonadResource m => IO Handle -> ConduitT i ByteString m ()
+ Conduit: sourceLazy :: (Monad m, LazySequence lazy strict) => lazy -> ConduitT i strict m ()
+ Conduit: stderrC :: MonadIO m => ConduitT ByteString o m ()
+ Conduit: stdinC :: MonadIO m => ConduitT i ByteString m ()
+ Conduit: stdoutC :: MonadIO m => ConduitT ByteString o m ()
+ Conduit: sumC :: (Monad m, Num a) => ConduitT a o m a
+ Conduit: sumCE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)
+ Conduit: takeC :: Monad m => Int -> ConduitT a a m ()
+ Conduit: takeCE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq seq m ()
+ Conduit: takeExactlyC :: Monad m => Int -> ConduitT a b m r -> ConduitT a b m r
+ Conduit: takeExactlyCE :: (Monad m, IsSequence a) => Index a -> ConduitT a b m r -> ConduitT a b m r
+ Conduit: takeWhileC :: Monad m => (a -> Bool) -> ConduitT a a m ()
+ Conduit: takeWhileCE :: (Monad m, IsSequence seq) => (Element seq -> Bool) -> ConduitT seq seq m ()
+ Conduit: throwM :: (MonadThrow m, Exception e) => e -> m a
+ Conduit: type BufferAllocStrategy = (IO Buffer, Int -> Buffer -> IO (IO Buffer))
+ Conduit: type family PrimState (m :: * -> *) :: *;
+ Conduit: unfoldC :: Monad m => (b -> Maybe (a, b)) -> b -> ConduitT i a m ()
+ Conduit: unlinesAsciiC :: (Monad m, IsSequence seq, Element seq ~ Word8) => ConduitT seq seq m ()
+ Conduit: unlinesC :: (Monad m, IsSequence seq, Element seq ~ Char) => ConduitT seq seq m ()
+ Conduit: unsafeBuilderToByteString :: PrimMonad m => ConduitT Builder ByteString m ()
+ Conduit: vectorBuilderC :: (PrimMonad m, Vector v e, PrimMonad n, PrimState m ~ PrimState n) => Int -> ((e -> n ()) -> ConduitT i Void m r) -> ConduitT i (v e) m r
+ Conduit: withRunInIO :: MonadUnliftIO m => ((forall a. () => m a -> IO a) -> IO b) -> m b
+ Conduit: withSinkFile :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM ByteString o n () -> m a) -> m a
+ Conduit: withSinkFileBuilder :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM Builder o n () -> m a) -> m a
+ Conduit: withSinkFileCautious :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM ByteString o n () -> m a) -> m a
+ Conduit: withSourceFile :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM i ByteString n () -> m a) -> m a
+ Conduit: yieldMany :: (Monad m, MonoFoldable mono) => mono -> ConduitT i (Element mono) m ()
+ Conduit: }
+ Data.Conduit: data ConduitT i o m r
+ Data.Conduit: data SealedConduitT i o m r
+ Data.Conduit: data Void :: *
+ Data.Conduit: sealConduitT :: ConduitT i o m r -> SealedConduitT i o m r
+ Data.Conduit: type ConduitM = ConduitT
+ Data.Conduit: unsealConduitT :: Monad m => SealedConduitT i o m r -> ConduitT i o m r
+ Data.Conduit.Combinators: all :: Monad m => (a -> Bool) -> ConduitT a o m Bool
+ Data.Conduit.Combinators: allE :: (Monad m, MonoFoldable mono) => (Element mono -> Bool) -> ConduitT mono o m Bool
+ Data.Conduit.Combinators: allNewBuffersStrategy :: Int -> BufferAllocStrategy
+ Data.Conduit.Combinators: and :: Monad m => ConduitT Bool o m Bool
+ Data.Conduit.Combinators: andE :: (Monad m, MonoFoldable mono, Element mono ~ Bool) => ConduitT mono o m Bool
+ Data.Conduit.Combinators: any :: Monad m => (a -> Bool) -> ConduitT a o m Bool
+ Data.Conduit.Combinators: anyE :: (Monad m, MonoFoldable mono) => (Element mono -> Bool) -> ConduitT mono o m Bool
+ Data.Conduit.Combinators: asum :: (Monad m, Alternative f) => ConduitT (f a) o m (f a)
+ Data.Conduit.Combinators: awaitNonNull :: (Monad m, MonoFoldable a) => ConduitT a o m (Maybe (NonNull a))
+ Data.Conduit.Combinators: builderToByteString :: PrimMonad m => ConduitT Builder ByteString m ()
+ Data.Conduit.Combinators: builderToByteStringFlush :: PrimMonad m => ConduitT (Flush Builder) (Flush ByteString) m ()
+ Data.Conduit.Combinators: builderToByteStringWith :: PrimMonad m => BufferAllocStrategy -> ConduitT Builder ByteString m ()
+ Data.Conduit.Combinators: builderToByteStringWithFlush :: PrimMonad m => BufferAllocStrategy -> ConduitT (Flush Builder) (Flush ByteString) m ()
+ Data.Conduit.Combinators: chunksOfE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq seq m ()
+ Data.Conduit.Combinators: chunksOfExactlyE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq seq m ()
+ Data.Conduit.Combinators: concat :: (Monad m, MonoFoldable mono) => ConduitT mono (Element mono) m ()
+ Data.Conduit.Combinators: concatMap :: (Monad m, MonoFoldable mono) => (a -> mono) -> ConduitT a (Element mono) m ()
+ Data.Conduit.Combinators: concatMapAccum :: Monad m => (a -> accum -> (accum, [b])) -> accum -> ConduitT a b m ()
+ Data.Conduit.Combinators: concatMapAccumM :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> ConduitT a b m ()
+ Data.Conduit.Combinators: concatMapE :: (Monad m, MonoFoldable mono, Monoid w) => (Element mono -> w) -> ConduitT mono w m ()
+ Data.Conduit.Combinators: concatMapM :: (Monad m, MonoFoldable mono) => (a -> m mono) -> ConduitT a (Element mono) m ()
+ Data.Conduit.Combinators: conduitVector :: (Vector v a, PrimMonad m) => Int -> ConduitT a (v a) m ()
+ Data.Conduit.Combinators: decodeUtf8 :: MonadThrow m => ConduitT ByteString Text m ()
+ Data.Conduit.Combinators: decodeUtf8Lenient :: Monad m => ConduitT ByteString Text m ()
+ Data.Conduit.Combinators: drop :: Monad m => Int -> ConduitT a o m ()
+ Data.Conduit.Combinators: dropE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq o m ()
+ Data.Conduit.Combinators: dropWhile :: Monad m => (a -> Bool) -> ConduitT a o m ()
+ Data.Conduit.Combinators: dropWhileE :: (Monad m, IsSequence seq) => (Element seq -> Bool) -> ConduitT seq o m ()
+ Data.Conduit.Combinators: elem :: (Monad m, Eq a) => a -> ConduitT a o m Bool
+ Data.Conduit.Combinators: elemE :: (Monad m, IsSequence seq, Eq (Element seq)) => Element seq -> ConduitT seq o m Bool
+ Data.Conduit.Combinators: encodeUtf8 :: (Monad m, Utf8 text binary) => ConduitT text binary m ()
+ Data.Conduit.Combinators: enumFromTo :: (Monad m, Enum a, Ord a) => a -> a -> ConduitT i a m ()
+ Data.Conduit.Combinators: filter :: Monad m => (a -> Bool) -> ConduitT a a m ()
+ Data.Conduit.Combinators: filterE :: (IsSequence seq, Monad m) => (Element seq -> Bool) -> ConduitT seq seq m ()
+ Data.Conduit.Combinators: filterM :: Monad m => (a -> m Bool) -> ConduitT a a m ()
+ Data.Conduit.Combinators: filterME :: (Monad m, IsSequence seq) => (Element seq -> m Bool) -> ConduitT seq seq m ()
+ Data.Conduit.Combinators: find :: Monad m => (a -> Bool) -> ConduitT a o m (Maybe a)
+ Data.Conduit.Combinators: fold :: (Monad m, Monoid a) => ConduitT a o m a
+ Data.Conduit.Combinators: foldE :: (Monad m, MonoFoldable mono, Monoid (Element mono)) => ConduitT mono o m (Element mono)
+ Data.Conduit.Combinators: foldM :: Monad m => (a -> b -> m a) -> a -> ConduitT b o m a
+ Data.Conduit.Combinators: foldME :: (Monad m, MonoFoldable mono) => (a -> Element mono -> m a) -> a -> ConduitT mono o m a
+ Data.Conduit.Combinators: foldMap :: (Monad m, Monoid b) => (a -> b) -> ConduitT a o m b
+ Data.Conduit.Combinators: foldMapE :: (Monad m, MonoFoldable mono, Monoid w) => (Element mono -> w) -> ConduitT mono o m w
+ Data.Conduit.Combinators: foldMapM :: (Monad m, Monoid w) => (a -> m w) -> ConduitT a o m w
+ Data.Conduit.Combinators: foldMapME :: (Monad m, MonoFoldable mono, Monoid w) => (Element mono -> m w) -> ConduitT mono o m w
+ Data.Conduit.Combinators: foldl :: Monad m => (a -> b -> a) -> a -> ConduitT b o m a
+ Data.Conduit.Combinators: foldl1 :: Monad m => (a -> a -> a) -> ConduitT a o m (Maybe a)
+ Data.Conduit.Combinators: foldlE :: (Monad m, MonoFoldable mono) => (a -> Element mono -> a) -> a -> ConduitT mono o m a
+ Data.Conduit.Combinators: head :: Monad m => ConduitT a o m (Maybe a)
+ Data.Conduit.Combinators: headDef :: Monad m => a -> ConduitT a o m a
+ Data.Conduit.Combinators: headE :: (Monad m, IsSequence seq) => ConduitT seq o m (Maybe (Element seq))
+ Data.Conduit.Combinators: intersperse :: Monad m => a -> ConduitT a a m ()
+ Data.Conduit.Combinators: iterM :: Monad m => (a -> m ()) -> ConduitT a a m ()
+ Data.Conduit.Combinators: iterate :: Monad m => (a -> a) -> a -> ConduitT i a m ()
+ Data.Conduit.Combinators: last :: Monad m => ConduitT a o m (Maybe a)
+ Data.Conduit.Combinators: lastDef :: Monad m => a -> ConduitT a o m a
+ Data.Conduit.Combinators: lastE :: (Monad m, IsSequence seq) => ConduitT seq o m (Maybe (Element seq))
+ Data.Conduit.Combinators: length :: (Monad m, Num len) => ConduitT a o m len
+ Data.Conduit.Combinators: lengthE :: (Monad m, Num len, MonoFoldable mono) => ConduitT mono o m len
+ Data.Conduit.Combinators: lengthIf :: (Monad m, Num len) => (a -> Bool) -> ConduitT a o m len
+ Data.Conduit.Combinators: lengthIfE :: (Monad m, Num len, MonoFoldable mono) => (Element mono -> Bool) -> ConduitT mono o m len
+ Data.Conduit.Combinators: line :: (Monad m, IsSequence seq, Element seq ~ Char) => ConduitT seq o m r -> ConduitT seq o m r
+ Data.Conduit.Combinators: lineAscii :: (Monad m, IsSequence seq, Element seq ~ Word8) => ConduitT seq o m r -> ConduitT seq o m r
+ Data.Conduit.Combinators: linesUnbounded :: (Monad m, IsSequence seq, Element seq ~ Char) => ConduitT seq seq m ()
+ Data.Conduit.Combinators: linesUnboundedAscii :: (Monad m, IsSequence seq, Element seq ~ Word8) => ConduitT seq seq m ()
+ Data.Conduit.Combinators: map :: Monad m => (a -> b) -> ConduitT a b m ()
+ Data.Conduit.Combinators: mapAccumS :: Monad m => (a -> s -> ConduitT b Void m s) -> s -> ConduitT () b m () -> ConduitT a Void m s
+ Data.Conduit.Combinators: mapAccumWhile :: Monad m => (a -> s -> Either s (s, b)) -> s -> ConduitT a b m s
+ Data.Conduit.Combinators: mapAccumWhileM :: Monad m => (a -> s -> m (Either s (s, b))) -> s -> ConduitT a b m s
+ Data.Conduit.Combinators: mapE :: (Monad m, Functor f) => (a -> b) -> ConduitT (f a) (f b) m ()
+ Data.Conduit.Combinators: mapM :: Monad m => (a -> m b) -> ConduitT a b m ()
+ Data.Conduit.Combinators: mapME :: (Monad m, Traversable f) => (a -> m b) -> ConduitT (f a) (f b) m ()
+ Data.Conduit.Combinators: mapM_ :: Monad m => (a -> m ()) -> ConduitT a o m ()
+ Data.Conduit.Combinators: mapM_E :: (Monad m, MonoFoldable mono) => (Element mono -> m ()) -> ConduitT mono o m ()
+ Data.Conduit.Combinators: mapWhile :: Monad m => (a -> Maybe b) -> ConduitT a b m ()
+ Data.Conduit.Combinators: maximum :: (Monad m, Ord a) => ConduitT a o m (Maybe a)
+ Data.Conduit.Combinators: maximumE :: (Monad m, IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))
+ Data.Conduit.Combinators: minimum :: (Monad m, Ord a) => ConduitT a o m (Maybe a)
+ Data.Conduit.Combinators: minimumE :: (Monad m, IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))
+ Data.Conduit.Combinators: notElem :: (Monad m, Eq a) => a -> ConduitT a o m Bool
+ Data.Conduit.Combinators: notElemE :: (Monad m, IsSequence seq, Eq (Element seq)) => Element seq -> ConduitT seq o m Bool
+ Data.Conduit.Combinators: null :: Monad m => ConduitT a o m Bool
+ Data.Conduit.Combinators: nullE :: (Monad m, MonoFoldable mono) => ConduitT mono o m Bool
+ Data.Conduit.Combinators: omapE :: (Monad m, MonoFunctor mono) => (Element mono -> Element mono) -> ConduitT mono mono m ()
+ Data.Conduit.Combinators: omapME :: (Monad m, MonoTraversable mono) => (Element mono -> m (Element mono)) -> ConduitT mono mono m ()
+ Data.Conduit.Combinators: or :: Monad m => ConduitT Bool o m Bool
+ Data.Conduit.Combinators: orE :: (Monad m, MonoFoldable mono, Element mono ~ Bool) => ConduitT mono o m Bool
+ Data.Conduit.Combinators: peek :: Monad m => ConduitT a o m (Maybe a)
+ Data.Conduit.Combinators: peekE :: (Monad m, MonoFoldable mono) => ConduitT mono o m (Maybe (Element mono))
+ Data.Conduit.Combinators: peekForever :: Monad m => ConduitT i o m () -> ConduitT i o m ()
+ Data.Conduit.Combinators: peekForeverE :: (Monad m, MonoFoldable i) => ConduitT i o m () -> ConduitT i o m ()
+ Data.Conduit.Combinators: print :: (Show a, MonadIO m) => ConduitT a o m ()
+ Data.Conduit.Combinators: product :: (Monad m, Num a) => ConduitT a o m a
+ Data.Conduit.Combinators: productE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)
+ Data.Conduit.Combinators: repeat :: Monad m => a -> ConduitT i a m ()
+ Data.Conduit.Combinators: repeatM :: Monad m => m a -> ConduitT i a m ()
+ Data.Conduit.Combinators: repeatWhileM :: Monad m => m a -> (a -> Bool) -> ConduitT i a m ()
+ Data.Conduit.Combinators: replicate :: Monad m => Int -> a -> ConduitT i a m ()
+ Data.Conduit.Combinators: replicateM :: Monad m => Int -> m a -> ConduitT i a m ()
+ Data.Conduit.Combinators: reuseBufferStrategy :: IO Buffer -> BufferAllocStrategy
+ Data.Conduit.Combinators: scanl :: Monad m => (a -> b -> a) -> a -> ConduitT b a m ()
+ Data.Conduit.Combinators: scanlM :: Monad m => (a -> b -> m a) -> a -> ConduitT b a m ()
+ Data.Conduit.Combinators: sinkFile :: MonadResource m => FilePath -> ConduitT ByteString o m ()
+ Data.Conduit.Combinators: sinkFileBS :: MonadResource m => FilePath -> ConduitT ByteString o m ()
+ Data.Conduit.Combinators: sinkFileCautious :: MonadResource m => FilePath -> ConduitM ByteString o m ()
+ Data.Conduit.Combinators: sinkHandle :: MonadIO m => Handle -> ConduitT ByteString o m ()
+ Data.Conduit.Combinators: sinkHandleBuilder :: MonadIO m => Handle -> ConduitM Builder o m ()
+ Data.Conduit.Combinators: sinkHandleFlush :: MonadIO m => Handle -> ConduitM (Flush ByteString) o m ()
+ Data.Conduit.Combinators: sinkIOHandle :: MonadResource m => IO Handle -> ConduitT ByteString o m ()
+ Data.Conduit.Combinators: sinkLazy :: (Monad m, LazySequence lazy strict) => ConduitT strict o m lazy
+ Data.Conduit.Combinators: sinkLazyBuilder :: Monad m => ConduitT Builder o m ByteString
+ Data.Conduit.Combinators: sinkList :: Monad m => ConduitT a o m [a]
+ Data.Conduit.Combinators: sinkNull :: Monad m => ConduitT a o m ()
+ Data.Conduit.Combinators: sinkSystemTempFile :: MonadResource m => String -> ConduitM ByteString o m FilePath
+ Data.Conduit.Combinators: sinkTempFile :: MonadResource m => FilePath -> String -> ConduitM ByteString o m FilePath
+ Data.Conduit.Combinators: sinkVector :: (Vector v a, PrimMonad m) => ConduitT a o m (v a)
+ Data.Conduit.Combinators: sinkVectorN :: (Vector v a, PrimMonad m) => Int -> ConduitT a o m (v a)
+ Data.Conduit.Combinators: slidingWindow :: (Monad m, IsSequence seq, Element seq ~ a) => Int -> ConduitT a seq m ()
+ Data.Conduit.Combinators: sourceDirectory :: MonadResource m => FilePath -> ConduitT i FilePath m ()
+ Data.Conduit.Combinators: sourceDirectoryDeep :: MonadResource m => Bool -> FilePath -> ConduitT i FilePath m ()
+ Data.Conduit.Combinators: sourceFile :: MonadResource m => FilePath -> ConduitT i ByteString m ()
+ Data.Conduit.Combinators: sourceFileBS :: MonadResource m => FilePath -> ConduitT i ByteString m ()
+ Data.Conduit.Combinators: sourceHandle :: MonadIO m => Handle -> ConduitT i ByteString m ()
+ Data.Conduit.Combinators: sourceHandleUnsafe :: MonadIO m => Handle -> ConduitT i ByteString m ()
+ Data.Conduit.Combinators: sourceIOHandle :: MonadResource m => IO Handle -> ConduitT i ByteString m ()
+ Data.Conduit.Combinators: sourceLazy :: (Monad m, LazySequence lazy strict) => lazy -> ConduitT i strict m ()
+ Data.Conduit.Combinators: splitOnUnboundedE :: (Monad m, IsSequence seq) => (Element seq -> Bool) -> ConduitT seq seq m ()
+ Data.Conduit.Combinators: stderr :: MonadIO m => ConduitT ByteString o m ()
+ Data.Conduit.Combinators: stdin :: MonadIO m => ConduitT i ByteString m ()
+ Data.Conduit.Combinators: stdout :: MonadIO m => ConduitT ByteString o m ()
+ Data.Conduit.Combinators: sum :: (Monad m, Num a) => ConduitT a o m a
+ Data.Conduit.Combinators: sumE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)
+ Data.Conduit.Combinators: take :: Monad m => Int -> ConduitT a a m ()
+ Data.Conduit.Combinators: takeE :: (Monad m, IsSequence seq) => Index seq -> ConduitT seq seq m ()
+ Data.Conduit.Combinators: takeExactly :: Monad m => Int -> ConduitT a b m r -> ConduitT a b m r
+ Data.Conduit.Combinators: takeExactlyE :: (Monad m, IsSequence a) => Index a -> ConduitT a b m r -> ConduitT a b m r
+ Data.Conduit.Combinators: takeExactlyUntilE :: (Monad m, IsSequence seq) => (Element seq -> Bool) -> ConduitT seq o m r -> ConduitT seq o m r
+ Data.Conduit.Combinators: takeWhile :: Monad m => (a -> Bool) -> ConduitT a a m ()
+ Data.Conduit.Combinators: takeWhileE :: (Monad m, IsSequence seq) => (Element seq -> Bool) -> ConduitT seq seq m ()
+ Data.Conduit.Combinators: type BufferAllocStrategy = (IO Buffer, Int -> Buffer -> IO (IO Buffer))
+ Data.Conduit.Combinators: unfold :: Monad m => (b -> Maybe (a, b)) -> b -> ConduitT i a m ()
+ Data.Conduit.Combinators: unlines :: (Monad m, IsSequence seq, Element seq ~ Char) => ConduitT seq seq m ()
+ Data.Conduit.Combinators: unlinesAscii :: (Monad m, IsSequence seq, Element seq ~ Word8) => ConduitT seq seq m ()
+ Data.Conduit.Combinators: unsafeBuilderToByteString :: PrimMonad m => ConduitT Builder ByteString m ()
+ Data.Conduit.Combinators: vectorBuilder :: (PrimMonad m, PrimMonad n, Vector v e, PrimState m ~ PrimState n) => Int -> ((e -> n ()) -> ConduitT i Void m r) -> ConduitT i (v e) m r
+ Data.Conduit.Combinators: withSinkFile :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM ByteString o n () -> m a) -> m a
+ Data.Conduit.Combinators: withSinkFileBuilder :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM Builder o n () -> m a) -> m a
+ Data.Conduit.Combinators: withSinkFileCautious :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM ByteString o n () -> m a) -> m a
+ Data.Conduit.Combinators: withSourceFile :: (MonadUnliftIO m, MonadIO n) => FilePath -> (ConduitM i ByteString n () -> m a) -> m a
+ Data.Conduit.Combinators: yieldMany :: (Monad m, MonoFoldable mono) => mono -> ConduitT i (Element mono) m ()
+ Data.Conduit.Combinators.Stream: allS :: Monad m => (a -> Bool) -> StreamConsumer a m Bool
+ Data.Conduit.Combinators.Stream: anyS :: Monad m => (a -> Bool) -> StreamConsumer a m Bool
+ Data.Conduit.Combinators.Stream: concatMapMS :: (Monad m, MonoFoldable mono) => (a -> m mono) -> StreamConduit a m (Element mono)
+ Data.Conduit.Combinators.Stream: concatMapS :: (Monad m, MonoFoldable mono) => (a -> mono) -> StreamConduit a m (Element mono)
+ Data.Conduit.Combinators.Stream: concatS :: (Monad m, MonoFoldable mono) => StreamConduit mono m (Element mono)
+ Data.Conduit.Combinators.Stream: filterMS :: Monad m => (a -> m Bool) -> StreamConduit a m a
+ Data.Conduit.Combinators.Stream: findS :: Monad m => (a -> Bool) -> StreamConsumer a m (Maybe a)
+ Data.Conduit.Combinators.Stream: foldl1S :: Monad m => (a -> a -> a) -> StreamConsumer a m (Maybe a)
+ Data.Conduit.Combinators.Stream: initRepeatS :: Monad m => m seed -> (seed -> m a) -> StreamProducer m a
+ Data.Conduit.Combinators.Stream: initReplicateS :: Monad m => m seed -> (seed -> m a) -> Int -> StreamProducer m a
+ Data.Conduit.Combinators.Stream: intersperseS :: Monad m => a -> StreamConduit a m a
+ Data.Conduit.Combinators.Stream: lastES :: (Monad m, IsSequence seq) => StreamConsumer seq m (Maybe (Element seq))
+ Data.Conduit.Combinators.Stream: lastS :: Monad m => StreamConsumer a m (Maybe a)
+ Data.Conduit.Combinators.Stream: mapAccumWhileMS :: Monad m => (a -> s -> m (Either s (s, b))) -> s -> StreamConduitT a b m s
+ Data.Conduit.Combinators.Stream: mapAccumWhileS :: Monad m => (a -> s -> Either s (s, b)) -> s -> StreamConduitT a b m s
+ Data.Conduit.Combinators.Stream: repeatMS :: Monad m => m a -> StreamProducer m a
+ Data.Conduit.Combinators.Stream: repeatWhileMS :: Monad m => m a -> (a -> Bool) -> StreamProducer m a
+ Data.Conduit.Combinators.Stream: scanlMS :: Monad m => (a -> b -> m a) -> a -> StreamConduit b m a
+ Data.Conduit.Combinators.Stream: scanlS :: Monad m => (a -> b -> a) -> a -> StreamConduit b m a
+ Data.Conduit.Combinators.Stream: sinkLazyBuilderS :: Monad m => StreamConsumer Builder m ByteString
+ Data.Conduit.Combinators.Stream: sinkLazyS :: (Monad m, LazySequence lazy strict) => StreamConsumer strict m lazy
+ Data.Conduit.Combinators.Stream: sinkVectorNS :: (Vector v a, PrimMonad m) => Int -> StreamConsumer a m (v a)
+ Data.Conduit.Combinators.Stream: sinkVectorS :: (Vector v a, PrimMonad m) => StreamConsumer a m (v a)
+ Data.Conduit.Combinators.Stream: slidingWindowS :: (Monad m, IsSequence seq, Element seq ~ a) => Int -> StreamConduit a m seq
+ Data.Conduit.Combinators.Stream: splitOnUnboundedES :: (Monad m, IsSequence seq) => (Element seq -> Bool) -> StreamConduit seq m seq
+ Data.Conduit.Combinators.Stream: yieldManyS :: (Monad m, MonoFoldable mono) => mono -> StreamProducer m (Element mono)
+ Data.Conduit.Internal: (.|) :: Monad m => ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit.Internal: ConduitT :: (forall b. (r -> Pipe i i o () m b) -> Pipe i i o () m b) -> ConduitT i o m r
+ Data.Conduit.Internal: SealedConduitT :: (Pipe i i o () m r) -> SealedConduitT i o m r
+ Data.Conduit.Internal: [unConduitT] :: ConduitT i o m r -> forall b. (r -> Pipe i i o () m b) -> Pipe i i o () m b
+ Data.Conduit.Internal: connect :: Monad m => ConduitT () a m () -> ConduitT a Void m r -> m r
+ Data.Conduit.Internal: fuse :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit.Internal: newtype ConduitT i o m r
+ Data.Conduit.Internal: newtype SealedConduitT i o m r
+ Data.Conduit.Internal: sealConduitT :: ConduitT i o m r -> SealedConduitT i o m r
+ Data.Conduit.Internal: type ConduitM = ConduitT
+ Data.Conduit.Internal: unsealConduitT :: Monad m => SealedConduitT i o m r -> ConduitT i o m r
+ Data.Conduit.Internal.Fusion: type StreamConduitT i o m r = Stream m i () -> Stream m o r
- Data.Conduit: ($$+) :: Monad m => Source m a -> Sink a m b -> m (ResumableSource m a, b)
+ Data.Conduit: ($$+) :: Monad m => Source m a -> Sink a m b -> m (SealedConduitT () a m (), b)
- Data.Conduit: ($$++) :: Monad m => ResumableSource m a -> Sink a m b -> m (ResumableSource m a, b)
+ Data.Conduit: ($$++) :: Monad m => SealedConduitT () a m () -> Sink a m b -> m (SealedConduitT () a m (), b)
- Data.Conduit: ($$+-) :: Monad m => ResumableSource m a -> Sink a m b -> m b
+ Data.Conduit: ($$+-) :: Monad m => SealedConduitT () a m () -> Sink a m b -> m b
- Data.Conduit: ($=) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit: ($=) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit: ($=+) :: Monad m => ResumableSource m a -> Conduit a m b -> ResumableSource m b
+ Data.Conduit: ($=+) :: Monad m => SealedConduitT () a m () -> Conduit a m b -> SealedConduitT () b m ()
- Data.Conduit: (=$$+) :: Monad m => Conduit a m b -> Sink b m r -> Sink a m (ResumableConduit a m b, r)
+ Data.Conduit: (=$$+) :: Monad m => ConduitT a b m () -> ConduitT b Void m r -> ConduitT a Void m (SealedConduitT a b m (), r)
- Data.Conduit: (=$$++) :: Monad m => ResumableConduit i m o -> Sink o m r -> Sink i m (ResumableConduit i m o, r)
+ Data.Conduit: (=$$++) :: Monad m => SealedConduitT i o m () -> ConduitT o Void m r -> ConduitT i Void m (SealedConduitT i o m (), r)
- Data.Conduit: (=$$+-) :: Monad m => ResumableConduit i m o -> Sink o m r -> Sink i m r
+ Data.Conduit: (=$$+-) :: Monad m => SealedConduitT i o m () -> ConduitT o Void m r -> ConduitT i Void m r
- Data.Conduit: (=$) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit: (=$) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit: (=$=) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit: (=$=) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit: ZipConduit :: ConduitM i o m r -> ZipConduit i o m r
+ Data.Conduit: ZipConduit :: ConduitT i o m r -> ZipConduit i o m r
- Data.Conduit: [getZipConduit] :: ZipConduit i o m r -> ConduitM i o m r
+ Data.Conduit: [getZipConduit] :: ZipConduit i o m r -> ConduitT i o m r
- Data.Conduit: awaitForever :: Monad m => (i -> ConduitM i o m r) -> ConduitM i o m ()
+ Data.Conduit: awaitForever :: Monad m => (i -> ConduitT i o m r) -> ConduitT i o m ()
- Data.Conduit: bracketP :: MonadResource m => IO a -> (a -> IO ()) -> (a -> ConduitM i o m r) -> ConduitM i o m r
+ Data.Conduit: bracketP :: MonadResource m => IO a -> (a -> IO ()) -> (a -> ConduitT i o m r) -> ConduitT i o m r
- Data.Conduit: catchC :: (MonadBaseControl IO m, Exception e) => ConduitM i o m r -> (e -> ConduitM i o m r) -> ConduitM i o m r
+ Data.Conduit: catchC :: (MonadUnliftIO m, Exception e) => ConduitT i o m r -> (e -> ConduitT i o m r) -> ConduitT i o m r
- Data.Conduit: connect :: Monad m => Source m a -> Sink a m b -> m b
+ Data.Conduit: connect :: Monad m => ConduitT () a m () -> ConduitT a Void m r -> m r
- Data.Conduit: fuseBoth :: Monad m => ConduitM a b m r1 -> ConduitM b c m r2 -> ConduitM a c m (r1, r2)
+ Data.Conduit: fuseBoth :: Monad m => ConduitT a b m r1 -> ConduitT b c m r2 -> ConduitT a c m (r1, r2)
- Data.Conduit: fuseBothMaybe :: Monad m => ConduitM a b m r1 -> ConduitM b c m r2 -> ConduitM a c m (Maybe r1, r2)
+ Data.Conduit: fuseBothMaybe :: Monad m => ConduitT a b m r1 -> ConduitT b c m r2 -> ConduitT a c m (Maybe r1, r2)
- Data.Conduit: fuseLeftovers :: Monad m => ([b] -> [a]) -> ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit: fuseLeftovers :: Monad m => ([b] -> [a]) -> ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit: fuseReturnLeftovers :: Monad m => ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m (r, [b])
+ Data.Conduit: fuseReturnLeftovers :: Monad m => ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m (r, [b])
- Data.Conduit: fuseUpstream :: Monad m => ConduitM a b m r -> Conduit b m c -> ConduitM a c m r
+ Data.Conduit: fuseUpstream :: Monad m => ConduitT a b m r -> Conduit b m c -> ConduitT a c m r
- Data.Conduit: handleC :: (MonadBaseControl IO m, Exception e) => (e -> ConduitM i o m r) -> ConduitM i o m r -> ConduitM i o m r
+ Data.Conduit: handleC :: (MonadUnliftIO m, Exception e) => (e -> ConduitT i o m r) -> ConduitT i o m r -> ConduitT i o m r
- Data.Conduit: leftover :: i -> ConduitM i o m ()
+ Data.Conduit: leftover :: i -> ConduitT i o m ()
- Data.Conduit: mapInput :: Monad m => (i1 -> i2) -> (i2 -> Maybe i1) -> ConduitM i2 o m r -> ConduitM i1 o m r
+ Data.Conduit: mapInput :: Monad m => (i1 -> i2) -> (i2 -> Maybe i1) -> ConduitT i2 o m r -> ConduitT i1 o m r
- Data.Conduit: mapOutput :: Monad m => (o1 -> o2) -> ConduitM i o1 m r -> ConduitM i o2 m r
+ Data.Conduit: mapOutput :: Monad m => (o1 -> o2) -> ConduitT i o1 m r -> ConduitT i o2 m r
- Data.Conduit: mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> ConduitM i o1 m r -> ConduitM i o2 m r
+ Data.Conduit: mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> ConduitT i o1 m r -> ConduitT i o2 m r
- Data.Conduit: runConduit :: Monad m => ConduitM () Void m r -> m r
+ Data.Conduit: runConduit :: Monad m => ConduitT () Void m r -> m r
- Data.Conduit: runConduitPure :: ConduitM () Void Identity r -> r
+ Data.Conduit: runConduitPure :: ConduitT () Void Identity r -> r
- Data.Conduit: runConduitRes :: MonadBaseControl IO m => ConduitM () Void (ResourceT m) r -> m r
+ Data.Conduit: runConduitRes :: MonadUnliftIO m => ConduitT () Void (ResourceT m) r -> m r
- Data.Conduit: sequenceConduits :: (Traversable f, Monad m) => f (ConduitM i o m r) -> ConduitM i o m (f r)
+ Data.Conduit: sequenceConduits :: (Traversable f, Monad m) => f (ConduitT i o m r) -> ConduitT i o m (f r)
- Data.Conduit: transPipe :: Monad m => (forall a. m a -> n a) -> ConduitM i o m r -> ConduitM i o n r
+ Data.Conduit: transPipe :: Monad m => (forall a. m a -> n a) -> ConduitT i o m r -> ConduitT i o n r
- Data.Conduit: tryC :: (MonadBaseControl IO m, Exception e) => ConduitM i o m r -> ConduitM i o m (Either e r)
+ Data.Conduit: tryC :: (MonadUnliftIO m, Exception e) => ConduitT i o m r -> ConduitT i o m (Either e r)
- Data.Conduit: type Conduit i m o = ConduitM i o m ()
+ Data.Conduit: type Conduit i m o = ConduitT i o m ()
- Data.Conduit: type Consumer i m r = forall o. ConduitM i o m r
+ Data.Conduit: type Consumer i m r = forall o. ConduitT i o m r
- Data.Conduit: type Producer m o = forall i. ConduitM i o m ()
+ Data.Conduit: type Producer m o = forall i. ConduitT i o m ()
- Data.Conduit: type Sink i = ConduitM i Void
+ Data.Conduit: type Sink i = ConduitT i Void
- Data.Conduit: type Source m o = ConduitM () o m ()
+ Data.Conduit: type Source m o = ConduitT () o m ()
- Data.Conduit: yield :: Monad m => o -> ConduitM i o m ()
+ Data.Conduit: yield :: Monad m => o -> ConduitT i o m ()
- Data.Conduit: yieldM :: Monad m => m o -> ConduitM i o m ()
+ Data.Conduit: yieldM :: Monad m => m o -> ConduitT i o m ()
- Data.Conduit.Internal: ($$+) :: Monad m => Source m a -> Sink a m b -> m (ResumableSource m a, b)
+ Data.Conduit.Internal: ($$+) :: Monad m => Source m a -> Sink a m b -> m (SealedConduitT () a m (), b)
- Data.Conduit.Internal: ($$++) :: Monad m => ResumableSource m a -> Sink a m b -> m (ResumableSource m a, b)
+ Data.Conduit.Internal: ($$++) :: Monad m => SealedConduitT () a m () -> Sink a m b -> m (SealedConduitT () a m (), b)
- Data.Conduit.Internal: ($$+-) :: Monad m => ResumableSource m a -> Sink a m b -> m b
+ Data.Conduit.Internal: ($$+-) :: Monad m => SealedConduitT () a m () -> Sink a m b -> m b
- Data.Conduit.Internal: ($=) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit.Internal: ($=) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit.Internal: ($=+) :: Monad m => ResumableSource m a -> Conduit a m b -> ResumableSource m b
+ Data.Conduit.Internal: ($=+) :: Monad m => SealedConduitT () a m () -> Conduit a m b -> SealedConduitT () b m ()
- Data.Conduit.Internal: (=$$+) :: Monad m => Conduit a m b -> Sink b m r -> Sink a m (ResumableConduit a m b, r)
+ Data.Conduit.Internal: (=$$+) :: Monad m => ConduitT a b m () -> ConduitT b Void m r -> ConduitT a Void m (SealedConduitT a b m (), r)
- Data.Conduit.Internal: (=$$++) :: Monad m => ResumableConduit i m o -> Sink o m r -> Sink i m (ResumableConduit i m o, r)
+ Data.Conduit.Internal: (=$$++) :: Monad m => SealedConduitT i o m () -> ConduitT o Void m r -> ConduitT i Void m (SealedConduitT i o m (), r)
- Data.Conduit.Internal: (=$$+-) :: Monad m => ResumableConduit i m o -> Sink o m r -> Sink i m r
+ Data.Conduit.Internal: (=$$+-) :: Monad m => SealedConduitT i o m () -> ConduitT o Void m r -> ConduitT i Void m r
- Data.Conduit.Internal: (=$) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit.Internal: (=$) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit.Internal: (=$=) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit.Internal: (=$=) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit.Internal: HaveOutput :: (Pipe l i o u m r) -> (m ()) -> o -> Pipe l i o u m r
+ Data.Conduit.Internal: HaveOutput :: (Pipe l i o u m r) -> o -> Pipe l i o u m r
- Data.Conduit.Internal: ZipConduit :: ConduitM i o m r -> ZipConduit i o m r
+ Data.Conduit.Internal: ZipConduit :: ConduitT i o m r -> ZipConduit i o m r
- Data.Conduit.Internal: [getZipConduit] :: ZipConduit i o m r -> ConduitM i o m r
+ Data.Conduit.Internal: [getZipConduit] :: ZipConduit i o m r -> ConduitT i o m r
- Data.Conduit.Internal: awaitForever :: Monad m => (i -> ConduitM i o m r) -> ConduitM i o m ()
+ Data.Conduit.Internal: awaitForever :: Monad m => (i -> ConduitT i o m r) -> ConduitT i o m ()
- Data.Conduit.Internal: bracketP :: MonadResource m => IO a -> (a -> IO ()) -> (a -> ConduitM i o m r) -> ConduitM i o m r
+ Data.Conduit.Internal: bracketP :: MonadResource m => IO a -> (a -> IO ()) -> (a -> ConduitT i o m r) -> ConduitT i o m r
- Data.Conduit.Internal: catchC :: (MonadBaseControl IO m, Exception e) => ConduitM i o m r -> (e -> ConduitM i o m r) -> ConduitM i o m r
+ Data.Conduit.Internal: catchC :: (MonadUnliftIO m, Exception e) => ConduitT i o m r -> (e -> ConduitT i o m r) -> ConduitT i o m r
- Data.Conduit.Internal: catchP :: (MonadBaseControl IO m, Exception e) => Pipe l i o u m r -> (e -> Pipe l i o u m r) -> Pipe l i o u m r
+ Data.Conduit.Internal: catchP :: (MonadUnliftIO m, Exception e) => Pipe l i o u m r -> (e -> Pipe l i o u m r) -> Pipe l i o u m r
- Data.Conduit.Internal: connectResume :: Monad m => ResumableSource m o -> Sink o m r -> m (ResumableSource m o, r)
+ Data.Conduit.Internal: connectResume :: Monad m => SealedConduitT () a m () -> ConduitT a Void m r -> m (SealedConduitT () a m (), r)
- Data.Conduit.Internal: connectResumeConduit :: Monad m => ResumableConduit i m o -> Sink o m r -> Sink i m (ResumableConduit i m o, r)
+ Data.Conduit.Internal: connectResumeConduit :: Monad m => SealedConduitT i o m () -> ConduitT o Void m r -> ConduitT i Void m (SealedConduitT i o m (), r)
- Data.Conduit.Internal: fuseBoth :: Monad m => ConduitM a b m r1 -> ConduitM b c m r2 -> ConduitM a c m (r1, r2)
+ Data.Conduit.Internal: fuseBoth :: Monad m => ConduitT a b m r1 -> ConduitT b c m r2 -> ConduitT a c m (r1, r2)
- Data.Conduit.Internal: fuseBothMaybe :: Monad m => ConduitM a b m r1 -> ConduitM b c m r2 -> ConduitM a c m (Maybe r1, r2)
+ Data.Conduit.Internal: fuseBothMaybe :: Monad m => ConduitT a b m r1 -> ConduitT b c m r2 -> ConduitT a c m (Maybe r1, r2)
- Data.Conduit.Internal: fuseLeftovers :: Monad m => ([b] -> [a]) -> ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
+ Data.Conduit.Internal: fuseLeftovers :: Monad m => ([b] -> [a]) -> ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
- Data.Conduit.Internal: fuseReturnLeftovers :: Monad m => ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m (r, [b])
+ Data.Conduit.Internal: fuseReturnLeftovers :: Monad m => ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m (r, [b])
- Data.Conduit.Internal: fuseUpstream :: Monad m => ConduitM a b m r -> Conduit b m c -> ConduitM a c m r
+ Data.Conduit.Internal: fuseUpstream :: Monad m => ConduitT a b m r -> Conduit b m c -> ConduitT a c m r
- Data.Conduit.Internal: handleC :: (MonadBaseControl IO m, Exception e) => (e -> ConduitM i o m r) -> ConduitM i o m r -> ConduitM i o m r
+ Data.Conduit.Internal: handleC :: (MonadUnliftIO m, Exception e) => (e -> ConduitT i o m r) -> ConduitT i o m r -> ConduitT i o m r
- Data.Conduit.Internal: handleP :: (MonadBaseControl IO m, Exception e) => (e -> Pipe l i o u m r) -> Pipe l i o u m r -> Pipe l i o u m r
+ Data.Conduit.Internal: handleP :: (MonadUnliftIO m, Exception e) => (e -> Pipe l i o u m r) -> Pipe l i o u m r -> Pipe l i o u m r
- Data.Conduit.Internal: infixr 2 =$=
+ Data.Conduit.Internal: infixr 2 .|
- Data.Conduit.Internal: leftover :: i -> ConduitM i o m ()
+ Data.Conduit.Internal: leftover :: i -> ConduitT i o m ()
- Data.Conduit.Internal: mapInput :: Monad m => (i1 -> i2) -> (i2 -> Maybe i1) -> ConduitM i2 o m r -> ConduitM i1 o m r
+ Data.Conduit.Internal: mapInput :: Monad m => (i1 -> i2) -> (i2 -> Maybe i1) -> ConduitT i2 o m r -> ConduitT i1 o m r
- Data.Conduit.Internal: mapOutput :: Monad m => (o1 -> o2) -> ConduitM i o1 m r -> ConduitM i o2 m r
+ Data.Conduit.Internal: mapOutput :: Monad m => (o1 -> o2) -> ConduitT i o1 m r -> ConduitT i o2 m r
- Data.Conduit.Internal: mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> ConduitM i o1 m r -> ConduitM i o2 m r
+ Data.Conduit.Internal: mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> ConduitT i o1 m r -> ConduitT i o2 m r
- Data.Conduit.Internal: runConduit :: Monad m => ConduitM () Void m r -> m r
+ Data.Conduit.Internal: runConduit :: Monad m => ConduitT () Void m r -> m r
- Data.Conduit.Internal: sequenceConduits :: (Traversable f, Monad m) => f (ConduitM i o m r) -> ConduitM i o m (f r)
+ Data.Conduit.Internal: sequenceConduits :: (Traversable f, Monad m) => f (ConduitT i o m r) -> ConduitT i o m (f r)
- Data.Conduit.Internal: transPipe :: Monad m => (forall a. m a -> n a) -> ConduitM i o m r -> ConduitM i o n r
+ Data.Conduit.Internal: transPipe :: Monad m => (forall a. m a -> n a) -> ConduitT i o m r -> ConduitT i o n r
- Data.Conduit.Internal: tryC :: (MonadBaseControl IO m, Exception e) => ConduitM i o m r -> ConduitM i o m (Either e r)
+ Data.Conduit.Internal: tryC :: (MonadUnliftIO m, Exception e) => ConduitT i o m r -> ConduitT i o m (Either e r)
- Data.Conduit.Internal: tryP :: (MonadBaseControl IO m, Exception e) => Pipe l i o u m r -> Pipe l i o u m (Either e r)
+ Data.Conduit.Internal: tryP :: (MonadUnliftIO m, Exception e) => Pipe l i o u m r -> Pipe l i o u m (Either e r)
- Data.Conduit.Internal: type Conduit i m o = ConduitM i o m ()
+ Data.Conduit.Internal: type Conduit i m o = ConduitT i o m ()
- Data.Conduit.Internal: type Consumer i m r = forall o. ConduitM i o m r
+ Data.Conduit.Internal: type Consumer i m r = forall o. ConduitT i o m r
- Data.Conduit.Internal: type Producer m o = forall i. ConduitM i o m ()
+ Data.Conduit.Internal: type Producer m o = forall i. ConduitT i o m ()
- Data.Conduit.Internal: type Sink i = ConduitM i Void
+ Data.Conduit.Internal: type Sink i = ConduitT i Void
- Data.Conduit.Internal: type Source m o = ConduitM () o m ()
+ Data.Conduit.Internal: type Source m o = ConduitT () o m ()
- Data.Conduit.Internal: yield :: Monad m => o -> ConduitM i o m ()
+ Data.Conduit.Internal: yield :: Monad m => o -> ConduitT i o m ()
- Data.Conduit.Internal: yieldM :: Monad m => m o -> ConduitM i o m ()
+ Data.Conduit.Internal: yieldM :: Monad m => m o -> ConduitT i o m ()
- Data.Conduit.Internal: zipConduitApp :: Monad m => ConduitM i o m (x -> y) -> ConduitM i o m x -> ConduitM i o m y
+ Data.Conduit.Internal: zipConduitApp :: Monad m => ConduitT i o m (x -> y) -> ConduitT i o m x -> ConduitT i o m y
- Data.Conduit.Internal.Fusion: streamConduit :: ConduitM i o m r -> (Stream m i () -> Stream m o r) -> ConduitWithStream i o m r
+ Data.Conduit.Internal.Fusion: streamConduit :: ConduitT i o m r -> (Stream m i () -> Stream m o r) -> ConduitWithStream i o m r
- Data.Conduit.Internal.Fusion: type StreamConduit i m o = StreamConduitM i o m ()
+ Data.Conduit.Internal.Fusion: type StreamConduit i m o = StreamConduitT i o m ()
- Data.Conduit.Internal.Fusion: type StreamConsumer i m r = forall o. StreamConduitM i o m r
+ Data.Conduit.Internal.Fusion: type StreamConsumer i m r = forall o. StreamConduitT i o m r
- Data.Conduit.Internal.Fusion: type StreamProducer m o = forall i. StreamConduitM i o m ()
+ Data.Conduit.Internal.Fusion: type StreamProducer m o = forall i. StreamConduitT i o m ()
- Data.Conduit.Internal.Fusion: type StreamSink i m r = StreamConduitM i Void m r
+ Data.Conduit.Internal.Fusion: type StreamSink i m r = StreamConduitT i Void m r
- Data.Conduit.Internal.Fusion: type StreamSource m o = StreamConduitM () o m ()
+ Data.Conduit.Internal.Fusion: type StreamSource m o = StreamConduitT () o m ()
- Data.Conduit.Internal.Fusion: unstream :: ConduitWithStream i o m r -> ConduitM i o m r
+ Data.Conduit.Internal.Fusion: unstream :: ConduitWithStream i o m r -> ConduitT i o m r
- Data.Conduit.Internal.List.Stream: mapAccumMS :: Monad m => (a -> s -> m (s, b)) -> s -> StreamConduitM a b m s
+ Data.Conduit.Internal.List.Stream: mapAccumMS :: Monad m => (a -> s -> m (s, b)) -> s -> StreamConduitT a b m s
- Data.Conduit.Internal.List.Stream: mapAccumS :: Monad m => (a -> s -> (s, b)) -> s -> StreamConduitM a b m s
+ Data.Conduit.Internal.List.Stream: mapAccumS :: Monad m => (a -> s -> (s, b)) -> s -> StreamConduitT a b m s
- Data.Conduit.Internal.List.Stream: unfoldEitherMS :: Monad m => (b -> m (Either r (a, b))) -> b -> StreamConduitM i a m r
+ Data.Conduit.Internal.List.Stream: unfoldEitherMS :: Monad m => (b -> m (Either r (a, b))) -> b -> StreamConduitT i a m r
- Data.Conduit.Internal.List.Stream: unfoldEitherS :: Monad m => (b -> Either r (a, b)) -> b -> StreamConduitM i a m r
+ Data.Conduit.Internal.List.Stream: unfoldEitherS :: Monad m => (b -> Either r (a, b)) -> b -> StreamConduitT i a m r
- Data.Conduit.Lift: catchCatchC :: Monad m => ConduitM i o (CatchT m) r -> (SomeException -> ConduitM i o (CatchT m) r) -> ConduitM i o (CatchT m) r
+ Data.Conduit.Lift: catchCatchC :: Monad m => ConduitT i o (CatchT m) r -> (SomeException -> ConduitT i o (CatchT m) r) -> ConduitT i o (CatchT m) r
- Data.Conduit.Lift: catchExceptC :: Monad m => ConduitM i o (ExceptT e m) r -> (e -> ConduitM i o (ExceptT e m) r) -> ConduitM i o (ExceptT e m) r
+ Data.Conduit.Lift: catchExceptC :: Monad m => ConduitT i o (ExceptT e m) r -> (e -> ConduitT i o (ExceptT e m) r) -> ConduitT i o (ExceptT e m) r
- Data.Conduit.Lift: evalRWSC :: (Monad m, Monoid w) => r -> s -> ConduitM i o (RWST r w s m) res -> ConduitM i o m (res, w)
+ Data.Conduit.Lift: evalRWSC :: (Monad m, Monoid w) => r -> s -> ConduitT i o (RWST r w s m) res -> ConduitT i o m (res, w)
- Data.Conduit.Lift: evalRWSLC :: (Monad m, Monoid w) => r -> s -> ConduitM i o (RWST r w s m) res -> ConduitM i o m (res, w)
+ Data.Conduit.Lift: evalRWSLC :: (Monad m, Monoid w) => r -> s -> ConduitT i o (RWST r w s m) res -> ConduitT i o m (res, w)
- Data.Conduit.Lift: evalStateC :: Monad m => s -> ConduitM i o (StateT s m) r -> ConduitM i o m r
+ Data.Conduit.Lift: evalStateC :: Monad m => s -> ConduitT i o (StateT s m) r -> ConduitT i o m r
- Data.Conduit.Lift: evalStateLC :: Monad m => s -> ConduitM i o (StateT s m) r -> ConduitM i o m r
+ Data.Conduit.Lift: evalStateLC :: Monad m => s -> ConduitT i o (StateT s m) r -> ConduitT i o m r
- Data.Conduit.Lift: exceptC :: (Monad m, Monad (t (ExceptT e m)), MonadTrans t, MFunctor t) => t m (Either e b) -> t (ExceptT e m) b
+ Data.Conduit.Lift: exceptC :: Monad m => ConduitT i o m (Either e a) -> ConduitT i o (ExceptT e m) a
- Data.Conduit.Lift: execRWSC :: (Monad m, Monoid w) => r -> s -> ConduitM i o (RWST r w s m) res -> ConduitM i o m (s, w)
+ Data.Conduit.Lift: execRWSC :: (Monad m, Monoid w) => r -> s -> ConduitT i o (RWST r w s m) res -> ConduitT i o m (s, w)
- Data.Conduit.Lift: execRWSLC :: (Monad m, Monoid w) => r -> s -> ConduitM i o (RWST r w s m) res -> ConduitM i o m (s, w)
+ Data.Conduit.Lift: execRWSLC :: (Monad m, Monoid w) => r -> s -> ConduitT i o (RWST r w s m) res -> ConduitT i o m (s, w)
- Data.Conduit.Lift: execStateC :: Monad m => s -> ConduitM i o (StateT s m) r -> ConduitM i o m s
+ Data.Conduit.Lift: execStateC :: Monad m => s -> ConduitT i o (StateT s m) r -> ConduitT i o m s
- Data.Conduit.Lift: execStateLC :: Monad m => s -> ConduitM i o (StateT s m) r -> ConduitM i o m s
+ Data.Conduit.Lift: execStateLC :: Monad m => s -> ConduitT i o (StateT s m) r -> ConduitT i o m s
- Data.Conduit.Lift: execWriterC :: (Monad m, Monoid w) => ConduitM i o (WriterT w m) r -> ConduitM i o m w
+ Data.Conduit.Lift: execWriterC :: (Monad m, Monoid w) => ConduitT i o (WriterT w m) r -> ConduitT i o m w
- Data.Conduit.Lift: execWriterLC :: (Monad m, Monoid w) => ConduitM i o (WriterT w m) r -> ConduitM i o m w
+ Data.Conduit.Lift: execWriterLC :: (Monad m, Monoid w) => ConduitT i o (WriterT w m) r -> ConduitT i o m w
- Data.Conduit.Lift: maybeC :: (Monad m, Monad (t (MaybeT m)), MonadTrans t, MFunctor t) => t m (Maybe b) -> t (MaybeT m) b
+ Data.Conduit.Lift: maybeC :: Monad m => ConduitT i o m (Maybe a) -> ConduitT i o (MaybeT m) a
- Data.Conduit.Lift: readerC :: (Monad m, Monad (t1 (ReaderT t m)), MonadTrans t1, MFunctor t1) => (t -> t1 m b) -> t1 (ReaderT t m) b
+ Data.Conduit.Lift: readerC :: Monad m => (r -> ConduitT i o m a) -> ConduitT i o (ReaderT r m) a
- Data.Conduit.Lift: runCatchC :: Monad m => ConduitM i o (CatchT m) r -> ConduitM i o m (Either SomeException r)
+ Data.Conduit.Lift: runCatchC :: Monad m => ConduitT i o (CatchT m) r -> ConduitT i o m (Either SomeException r)
- Data.Conduit.Lift: runExceptC :: Monad m => ConduitM i o (ExceptT e m) r -> ConduitM i o m (Either e r)
+ Data.Conduit.Lift: runExceptC :: Monad m => ConduitT i o (ExceptT e m) r -> ConduitT i o m (Either e r)
- Data.Conduit.Lift: runMaybeC :: Monad m => ConduitM i o (MaybeT m) r -> ConduitM i o m (Maybe r)
+ Data.Conduit.Lift: runMaybeC :: Monad m => ConduitT i o (MaybeT m) r -> ConduitT i o m (Maybe r)
- Data.Conduit.Lift: runRWSC :: (Monad m, Monoid w) => r -> s -> ConduitM i o (RWST r w s m) res -> ConduitM i o m (res, s, w)
+ Data.Conduit.Lift: runRWSC :: (Monad m, Monoid w) => r -> s -> ConduitT i o (RWST r w s m) res -> ConduitT i o m (res, s, w)
- Data.Conduit.Lift: runRWSLC :: (Monad m, Monoid w) => r -> s -> ConduitM i o (RWST r w s m) res -> ConduitM i o m (res, s, w)
+ Data.Conduit.Lift: runRWSLC :: (Monad m, Monoid w) => r -> s -> ConduitT i o (RWST r w s m) res -> ConduitT i o m (res, s, w)
- Data.Conduit.Lift: runReaderC :: Monad m => r -> ConduitM i o (ReaderT r m) res -> ConduitM i o m res
+ Data.Conduit.Lift: runReaderC :: Monad m => r -> ConduitT i o (ReaderT r m) res -> ConduitT i o m res
- Data.Conduit.Lift: runStateC :: Monad m => s -> ConduitM i o (StateT s m) r -> ConduitM i o m (r, s)
+ Data.Conduit.Lift: runStateC :: Monad m => s -> ConduitT i o (StateT s m) r -> ConduitT i o m (r, s)
- Data.Conduit.Lift: runStateLC :: Monad m => s -> ConduitM i o (StateT s m) r -> ConduitM i o m (r, s)
+ Data.Conduit.Lift: runStateLC :: Monad m => s -> ConduitT i o (StateT s m) r -> ConduitT i o m (r, s)
- Data.Conduit.Lift: runWriterC :: (Monad m, Monoid w) => ConduitM i o (WriterT w m) r -> ConduitM i o m (r, w)
+ Data.Conduit.Lift: runWriterC :: (Monad m, Monoid w) => ConduitT i o (WriterT w m) r -> ConduitT i o m (r, w)
- Data.Conduit.Lift: runWriterLC :: (Monad m, Monoid w) => ConduitM i o (WriterT w m) r -> ConduitM i o m (r, w)
+ Data.Conduit.Lift: runWriterLC :: (Monad m, Monoid w) => ConduitT i o (WriterT w m) r -> ConduitT i o m (r, w)
- Data.Conduit.Lift: rwsC :: (Monad m, Monad (t1 (RWST t w t2 m)), MonadTrans t1, Monoid w, MFunctor t1) => (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWST t w t2 m) b
+ Data.Conduit.Lift: rwsC :: (Monad m, Monoid w) => (r -> s -> ConduitT i o m (a, s, w)) -> ConduitT i o (RWST r w s m) a
- Data.Conduit.Lift: rwsLC :: (Monad m, Monad (t1 (RWST t w t2 m)), MonadTrans t1, Monoid w, MFunctor t1) => (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWST t w t2 m) b
+ Data.Conduit.Lift: rwsLC :: (Monad m, Monoid w) => (r -> s -> ConduitT i o m (a, s, w)) -> ConduitT i o (RWST r w s m) a
- Data.Conduit.Lift: stateC :: (Monad m, Monad (t1 (StateT t m)), MonadTrans t1, MFunctor t1) => (t -> t1 m (b, t)) -> t1 (StateT t m) b
+ Data.Conduit.Lift: stateC :: Monad m => (s -> ConduitT i o m (a, s)) -> ConduitT i o (StateT s m) a
- Data.Conduit.Lift: stateLC :: (Monad m, Monad (t1 (StateT t m)), MonadTrans t1, MFunctor t1) => (t -> t1 m (b, t)) -> t1 (StateT t m) b
+ Data.Conduit.Lift: stateLC :: Monad m => (s -> ConduitT i o m (a, s)) -> ConduitT i o (StateT s m) a
- Data.Conduit.Lift: writerC :: (Monad m, Monad (t (WriterT w m)), MonadTrans t, Monoid w, MFunctor t) => t m (b, w) -> t (WriterT w m) b
+ Data.Conduit.Lift: writerC :: (Monad m, Monoid w) => ConduitT i o m (b, w) -> ConduitT i o (WriterT w m) b
- Data.Conduit.Lift: writerLC :: (Monad m, Monad (t (WriterT w m)), MonadTrans t, Monoid w, MFunctor t) => t m (b, w) -> t (WriterT w m) b
+ Data.Conduit.Lift: writerLC :: (Monad m, Monoid w) => ConduitT i o m (b, w) -> ConduitT i o (WriterT w m) b
- Data.Conduit.List: catMaybes :: Monad m => Conduit (Maybe a) m a
+ Data.Conduit.List: catMaybes :: Monad m => ConduitT (Maybe a) a m ()
- Data.Conduit.List: chunksOf :: Monad m => Int -> Conduit a m [a]
+ Data.Conduit.List: chunksOf :: Monad m => Int -> ConduitT a [a] m ()
- Data.Conduit.List: concat :: (Monad m, Foldable f) => Conduit (f a) m a
+ Data.Conduit.List: concat :: (Monad m, Foldable f) => ConduitT (f a) a m ()
- Data.Conduit.List: concatMap :: Monad m => (a -> [b]) -> Conduit a m b
+ Data.Conduit.List: concatMap :: Monad m => (a -> [b]) -> ConduitT a b m ()
- Data.Conduit.List: concatMapAccum :: Monad m => (a -> accum -> (accum, [b])) -> accum -> Conduit a m b
+ Data.Conduit.List: concatMapAccum :: Monad m => (a -> accum -> (accum, [b])) -> accum -> ConduitT a b m ()
- Data.Conduit.List: concatMapAccumM :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> Conduit a m b
+ Data.Conduit.List: concatMapAccumM :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> ConduitT a b m ()
- Data.Conduit.List: concatMapM :: Monad m => (a -> m [b]) -> Conduit a m b
+ Data.Conduit.List: concatMapM :: Monad m => (a -> m [b]) -> ConduitT a b m ()
- Data.Conduit.List: consume :: Monad m => Consumer a m [a]
+ Data.Conduit.List: consume :: Monad m => ConduitT a o m [a]
- Data.Conduit.List: drop :: Monad m => Int -> Consumer a m ()
+ Data.Conduit.List: drop :: Monad m => Int -> ConduitT a o m ()
- Data.Conduit.List: enumFromTo :: (Enum a, Ord a, Monad m) => a -> a -> Producer m a
+ Data.Conduit.List: enumFromTo :: (Enum a, Ord a, Monad m) => a -> a -> ConduitT i a m ()
- Data.Conduit.List: filter :: Monad m => (a -> Bool) -> Conduit a m a
+ Data.Conduit.List: filter :: Monad m => (a -> Bool) -> ConduitT a a m ()
- Data.Conduit.List: fold :: Monad m => (b -> a -> b) -> b -> Consumer a m b
+ Data.Conduit.List: fold :: Monad m => (b -> a -> b) -> b -> ConduitT a o m b
- Data.Conduit.List: foldM :: Monad m => (b -> a -> m b) -> b -> Consumer a m b
+ Data.Conduit.List: foldM :: Monad m => (b -> a -> m b) -> b -> ConduitT a o m b
- Data.Conduit.List: foldMap :: (Monad m, Monoid b) => (a -> b) -> Consumer a m b
+ Data.Conduit.List: foldMap :: (Monad m, Monoid b) => (a -> b) -> ConduitT a o m b
- Data.Conduit.List: foldMapM :: (Monad m, Monoid b) => (a -> m b) -> Consumer a m b
+ Data.Conduit.List: foldMapM :: (Monad m, Monoid b) => (a -> m b) -> ConduitT a o m b
- Data.Conduit.List: groupBy :: Monad m => (a -> a -> Bool) -> Conduit a m [a]
+ Data.Conduit.List: groupBy :: Monad m => (a -> a -> Bool) -> ConduitT a [a] m ()
- Data.Conduit.List: groupOn1 :: (Monad m, Eq b) => (a -> b) -> Conduit a m (a, [a])
+ Data.Conduit.List: groupOn1 :: (Monad m, Eq b) => (a -> b) -> ConduitT a (a, [a]) m ()
- Data.Conduit.List: head :: Monad m => Consumer a m (Maybe a)
+ Data.Conduit.List: head :: Monad m => ConduitT a o m (Maybe a)
- Data.Conduit.List: isolate :: Monad m => Int -> Conduit a m a
+ Data.Conduit.List: isolate :: Monad m => Int -> ConduitT a a m ()
- Data.Conduit.List: iterM :: Monad m => (a -> m ()) -> Conduit a m a
+ Data.Conduit.List: iterM :: Monad m => (a -> m ()) -> ConduitT a a m ()
- Data.Conduit.List: iterate :: Monad m => (a -> a) -> a -> Producer m a
+ Data.Conduit.List: iterate :: Monad m => (a -> a) -> a -> ConduitT i a m ()
- Data.Conduit.List: map :: Monad m => (a -> b) -> Conduit a m b
+ Data.Conduit.List: map :: Monad m => (a -> b) -> ConduitT a b m ()
- Data.Conduit.List: mapAccum :: Monad m => (a -> s -> (s, b)) -> s -> ConduitM a b m s
+ Data.Conduit.List: mapAccum :: Monad m => (a -> s -> (s, b)) -> s -> ConduitT a b m s
- Data.Conduit.List: mapAccumM :: Monad m => (a -> s -> m (s, b)) -> s -> ConduitM a b m s
+ Data.Conduit.List: mapAccumM :: Monad m => (a -> s -> m (s, b)) -> s -> ConduitT a b m s
- Data.Conduit.List: mapFoldable :: (Monad m, Foldable f) => (a -> f b) -> Conduit a m b
+ Data.Conduit.List: mapFoldable :: (Monad m, Foldable f) => (a -> f b) -> ConduitT a b m ()
- Data.Conduit.List: mapFoldableM :: (Monad m, Foldable f) => (a -> m (f b)) -> Conduit a m b
+ Data.Conduit.List: mapFoldableM :: (Monad m, Foldable f) => (a -> m (f b)) -> ConduitT a b m ()
- Data.Conduit.List: mapM :: Monad m => (a -> m b) -> Conduit a m b
+ Data.Conduit.List: mapM :: Monad m => (a -> m b) -> ConduitT a b m ()
- Data.Conduit.List: mapM_ :: Monad m => (a -> m ()) -> Consumer a m ()
+ Data.Conduit.List: mapM_ :: Monad m => (a -> m ()) -> ConduitT a o m ()
- Data.Conduit.List: mapMaybe :: Monad m => (a -> Maybe b) -> Conduit a m b
+ Data.Conduit.List: mapMaybe :: Monad m => (a -> Maybe b) -> ConduitT a b m ()
- Data.Conduit.List: mapMaybeM :: Monad m => (a -> m (Maybe b)) -> Conduit a m b
+ Data.Conduit.List: mapMaybeM :: Monad m => (a -> m (Maybe b)) -> ConduitT a b m ()
- Data.Conduit.List: peek :: Monad m => Consumer a m (Maybe a)
+ Data.Conduit.List: peek :: Monad m => ConduitT a o m (Maybe a)
- Data.Conduit.List: replicate :: Monad m => Int -> a -> Producer m a
+ Data.Conduit.List: replicate :: Monad m => Int -> a -> ConduitT i a m ()
- Data.Conduit.List: replicateM :: Monad m => Int -> m a -> Producer m a
+ Data.Conduit.List: replicateM :: Monad m => Int -> m a -> ConduitT i a m ()
- Data.Conduit.List: scan :: Monad m => (a -> b -> b) -> b -> ConduitM a b m b
+ Data.Conduit.List: scan :: Monad m => (a -> b -> b) -> b -> ConduitT a b m b
- Data.Conduit.List: scanM :: Monad m => (a -> b -> m b) -> b -> ConduitM a b m b
+ Data.Conduit.List: scanM :: Monad m => (a -> b -> m b) -> b -> ConduitT a b m b
- Data.Conduit.List: scanl :: Monad m => (a -> s -> (s, b)) -> s -> Conduit a m b
+ Data.Conduit.List: scanl :: Monad m => (a -> s -> (s, b)) -> s -> ConduitT a b m ()
- Data.Conduit.List: scanlM :: Monad m => (a -> s -> m (s, b)) -> s -> Conduit a m b
+ Data.Conduit.List: scanlM :: Monad m => (a -> s -> m (s, b)) -> s -> ConduitT a b m ()
- Data.Conduit.List: sequence :: Monad m => Consumer i m o -> Conduit i m o
+ Data.Conduit.List: sequence :: Monad m => ConduitT i o m o -> ConduitT i o m ()
- Data.Conduit.List: sinkNull :: Monad m => Consumer a m ()
+ Data.Conduit.List: sinkNull :: Monad m => ConduitT i o m ()
- Data.Conduit.List: sourceList :: Monad m => [a] -> Producer m a
+ Data.Conduit.List: sourceList :: Monad m => [a] -> ConduitT i a m ()
- Data.Conduit.List: sourceNull :: Monad m => Producer m a
+ Data.Conduit.List: sourceNull :: Monad m => ConduitT i o m ()
- Data.Conduit.List: take :: Monad m => Int -> Consumer a m [a]
+ Data.Conduit.List: take :: Monad m => Int -> ConduitT a o m [a]
- Data.Conduit.List: unfold :: Monad m => (b -> Maybe (a, b)) -> b -> Producer m a
+ Data.Conduit.List: unfold :: Monad m => (b -> Maybe (a, b)) -> b -> ConduitT i a m ()
- Data.Conduit.List: unfoldEither :: Monad m => (b -> Either r (a, b)) -> b -> ConduitM i a m r
+ Data.Conduit.List: unfoldEither :: Monad m => (b -> Either r (a, b)) -> b -> ConduitT i a m r
- Data.Conduit.List: unfoldEitherM :: Monad m => (b -> m (Either r (a, b))) -> b -> ConduitM i a m r
+ Data.Conduit.List: unfoldEitherM :: Monad m => (b -> m (Either r (a, b))) -> b -> ConduitT i a m r
- Data.Conduit.List: unfoldM :: Monad m => (b -> m (Maybe (a, b))) -> b -> Producer m a
+ Data.Conduit.List: unfoldM :: Monad m => (b -> m (Maybe (a, b))) -> b -> ConduitT i a m ()
Files
- ChangeLog.md +11/−2
- Data/Conduit.hs +0/−154
- Data/Conduit/Internal.hs +0/−17
- Data/Conduit/Internal/Conduit.hs +0/−1325
- Data/Conduit/Internal/Fusion.hs +0/−213
- Data/Conduit/Internal/List/Stream.hs +0/−502
- Data/Conduit/Internal/Pipe.hs +0/−648
- Data/Conduit/Lift.hs +0/−630
- Data/Conduit/List.hs +0/−837
- benchmarks/optimize-201408.hs +25/−41
- benchmarks/unfused.hs +30/−33
- conduit.cabal +43/−21
- src/Conduit.hs +43/−0
- src/Data/Conduit.hs +126/−0
- src/Data/Conduit/Combinators.hs +2542/−0
- src/Data/Conduit/Combinators/Stream.hs +474/−0
- src/Data/Conduit/Combinators/Unqualified.hs +1206/−0
- src/Data/Conduit/Internal.hs +18/−0
- src/Data/Conduit/Internal/Conduit.hs +1232/−0
- src/Data/Conduit/Internal/Fusion.hs +220/−0
- src/Data/Conduit/Internal/List/Stream.hs +502/−0
- src/Data/Conduit/Internal/Pipe.hs +589/−0
- src/Data/Conduit/Lift.hs +518/−0
- src/Data/Conduit/List.hs +844/−0
- src/Data/Streaming/FileRead.hs +37/−0
- src/Data/Streaming/Filesystem.hs +100/−0
- src/System/Win32File.hsc +100/−0
- test/Data/Conduit/Extra/ZipConduitSpec.hs +3/−3
- test/Data/Conduit/StreamSpec.hs +45/−45
- test/Spec.hs +679/−0
- test/StreamSpec.hs +509/−0
- test/doctests.hs +6/−0
- test/main.hs +179/−451
- test/subdir/dummyfile.txt +0/−0
ChangeLog.md view
@@ -1,6 +1,15 @@-## 1.2.13.1+## 1.3.0 -* Remove the `Safe` language pragma [#353](https://github.com/snoyberg/conduit/issues/353)+* Drop monad-control and exceptions in favor of unliftio+* Drop mmorph dependency+* Deprecate old type synonyms and operators+* Drop finalizers from the library entirely+ * Much simpler+ * Less guarantees about prompt finalization+ * No more `yieldOr`, `addCleanup`+ * Replace the `Resumable` types with `SealedConduitT`+* Add the `Conduit` and `Data.Conduit.Combinators` modules, stolen from+ `conduit-combinators` ## 1.2.13
− Data/Conduit.hs
@@ -1,154 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleContexts #-}--- | If this is your first time with conduit, you should probably start with--- the tutorial:--- <https://github.com/snoyberg/conduit#readme>.-module Data.Conduit- ( -- * Core interface- -- ** Types- Source- , Conduit- , Sink- , ConduitM- -- ** Connect/fuse operators- , (.|)- , ($$)- , ($=)- , (=$)- , (=$=)- , connect- , fuse-- -- *** Fuse with upstream results- , fuseBoth- , fuseBothMaybe- , fuseUpstream-- -- ** Primitives- , await- , yield- , yieldM- , leftover- , runConduit- , runConduitPure- , runConduitRes-- -- ** Finalization- , bracketP- , addCleanup- , yieldOr-- -- ** Exception handling- , catchC- , handleC- , tryC-- -- * Generalized conduit types- , Producer- , Consumer- , toProducer- , toConsumer-- -- * Utility functions- , awaitForever- , transPipe- , mapOutput- , mapOutputMaybe- , mapInput- , mergeSource- , passthroughSink- , sourceToList-- -- * Connect-and-resume- , ResumableSource- , newResumableSource- , ($$+)- , ($$++)- , ($$+-)- , ($=+)- , unwrapResumable- , closeResumableSource-- -- ** For @Conduit@s- , ResumableConduit- , newResumableConduit- , (=$$+)- , (=$$++)- , (=$$+-)- , unwrapResumableConduit-- -- * Fusion with leftovers- , fuseLeftovers- , fuseReturnLeftovers-- -- * Flushing- , Flush (..)-- -- * Newtype wrappers- -- ** ZipSource- , ZipSource (..)- , sequenceSources-- -- ** ZipSink- , ZipSink (..)- , sequenceSinks-- -- ** ZipConduit- , ZipConduit (..)- , sequenceConduits- ) where--import Data.Conduit.Internal.Conduit-import Data.Void (Void)-import Data.Functor.Identity (Identity, runIdentity)-import Control.Monad.Trans.Resource (ResourceT, runResourceT)-import Control.Monad.Trans.Control (MonadBaseControl)---- | Named function synonym for '$$'.------ Since 1.2.3-connect :: Monad m => Source m a -> Sink a m b -> m b-connect = ($$)---- | Named function synonym for '=$='.------ Since 1.2.3-fuse :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r-fuse = (=$=)--infixr 2 .|--- | Combine two @Conduit@s together into a new @Conduit@ (aka 'fuse').------ Output from the upstream (left) conduit will be fed into the--- downstream (right) conduit. Processing will terminate when--- downstream (right) returns. Leftover data returned from the right--- @Conduit@ will be discarded.------ @since 1.2.8-(.|) :: Monad m- => ConduitM a b m () -- ^ upstream- -> ConduitM b c m r -- ^ downstream- -> ConduitM a c m r-(.|) = fuse-{-# INLINE (.|) #-}---- | Run a pure pipeline until processing completes, i.e. a pipeline--- with @Identity@ as the base monad. This is equivalient to--- @runIdentity . runConduit@.------ @since 1.2.8-runConduitPure :: ConduitM () Void Identity r -> r-runConduitPure = runIdentity . runConduit-{-# INLINE runConduitPure #-}---- | Run a pipeline which acquires resources with @ResourceT@, and--- then run the @ResourceT@ transformer. This is equivalent to--- @runResourceT . runConduit@.------ @since 1.2.8-runConduitRes :: MonadBaseControl IO m- => ConduitM () Void (ResourceT m) r- -> m r-runConduitRes = runResourceT . runConduit-{-# INLINE runConduitRes #-}
− Data/Conduit/Internal.hs
@@ -1,17 +0,0 @@-{-# OPTIONS_HADDOCK not-home #-}-module Data.Conduit.Internal- ( -- * Pipe- module Data.Conduit.Internal.Pipe- -- * Conduit- , module Data.Conduit.Internal.Conduit- -- * Fusion (highly experimental!!!)- , module Data.Conduit.Internal.Fusion- ) where--import Data.Conduit.Internal.Conduit hiding (addCleanup, await,- awaitForever, bracketP,- leftover, mapInput, mapOutput,- mapOutputMaybe, transPipe,- yield, yieldM, yieldOr)-import Data.Conduit.Internal.Pipe-import Data.Conduit.Internal.Fusion
− Data/Conduit/Internal/Conduit.hs
@@ -1,1325 +0,0 @@-{-# OPTIONS_HADDOCK not-home #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE Trustworthy #-}-{-# LANGUAGE TypeFamilies #-}-module Data.Conduit.Internal.Conduit- ( -- ** Types- ConduitM (..)- , Source- , Producer- , Sink- , Consumer- , Conduit- , ResumableSource (..)- , ResumableConduit (..)- , Flush (..)- -- *** Newtype wrappers- , ZipSource (..)- , ZipSink (..)- , ZipConduit (..)- -- ** Primitives- , await- , awaitForever- , yield- , yieldM- , yieldOr- , leftover- , runConduit- -- ** Composition- , connectResume- , connectResumeConduit- , fuseLeftovers- , fuseReturnLeftovers- , ($$+)- , ($$++)- , ($$+-)- , ($=+)- , (=$$+)- , (=$$++)- , (=$$+-)- , ($$)- , ($=)- , (=$)- , (=$=)- -- ** Generalizing- , sourceToPipe- , sinkToPipe- , conduitToPipe- , toProducer- , toConsumer- -- ** Cleanup- , bracketP- , addCleanup- -- ** Exceptions- , catchC- , handleC- , tryC- -- ** Utilities- , Data.Conduit.Internal.Conduit.transPipe- , Data.Conduit.Internal.Conduit.mapOutput- , Data.Conduit.Internal.Conduit.mapOutputMaybe- , Data.Conduit.Internal.Conduit.mapInput- , Data.Conduit.Internal.Conduit.closeResumableSource- , unwrapResumable- , unwrapResumableConduit- , newResumableSource- , newResumableConduit- , zipSinks- , zipSources- , zipSourcesApp- , zipConduitApp- , mergeSource- , passthroughSink- , sourceToList- , fuseBoth- , fuseBothMaybe- , fuseUpstream- , sequenceSources- , sequenceSinks- , sequenceConduits- ) where--import Prelude hiding (catch)-import Control.Applicative (Applicative (..))-import Control.Exception.Lifted as E (Exception)-import qualified Control.Exception.Lifted as E (catch)-import Control.Monad (liftM, when, liftM2, ap)-import Control.Monad.Error.Class(MonadError(..))-import Control.Monad.Reader.Class(MonadReader(..))-import Control.Monad.RWS.Class(MonadRWS())-import Control.Monad.Writer.Class(MonadWriter(..), censor)-import Control.Monad.State.Class(MonadState(..))-import Control.Monad.Trans.Class (MonadTrans (lift))-import Control.Monad.IO.Class (MonadIO (liftIO))-import Control.Monad.Base (MonadBase (liftBase))-import Control.Monad.Primitive (PrimMonad, PrimState, primitive)-import Data.Void (Void, absurd)-import Data.Monoid (Monoid (mappend, mempty))-import Data.Semigroup (Semigroup ((<>)))-import Control.Monad.Trans.Resource-import qualified Data.IORef as I-import Control.Monad.Morph (MFunctor (..))-import Data.Conduit.Internal.Pipe hiding (yield, mapOutput, leftover, yieldM, yieldOr, await, awaitForever, addCleanup, bracketP)-import qualified Data.Conduit.Internal.Pipe as CI-import Control.Monad (forever)-import Data.Traversable (Traversable (..))-import Control.Monad.Catch (MonadCatch, catch)---- | 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 :: forall b.- (r -> Pipe i i o () m b) -> Pipe i i o () m b- }--instance Functor (ConduitM i o m) where- fmap f (ConduitM c) = ConduitM $ \rest -> c (rest . f)--instance Applicative (ConduitM i o m) where- pure x = ConduitM ($ x)- {-# INLINE pure #-}- (<*>) = ap- {-# INLINE (<*>) #-}--instance Monad (ConduitM i o m) where- return = pure- ConduitM f >>= g = ConduitM $ \h -> f $ \a -> unConduitM (g a) h--instance MonadThrow m => MonadThrow (ConduitM i o m) where- throwM = lift . throwM--instance MFunctor (ConduitM i o) where- hoist f (ConduitM c0) = ConduitM $ \rest -> let- go (HaveOutput p c o) = HaveOutput (go p) (f c) o- go (NeedInput p c) = NeedInput (go . p) (go . c)- go (Done r) = rest r- go (PipeM mp) =- PipeM (f $ liftM go $ collapse mp)- where- -- Combine a series of monadic actions into a single action. Since we- -- throw away side effects between different actions, an arbitrary break- -- between actions will lead to a violation of the monad transformer laws.- -- Example available at:- --- -- http://hpaste.org/75520- collapse mpipe = do- pipe' <- mpipe- case pipe' of- PipeM mpipe' -> collapse mpipe'- _ -> return pipe'- go (Leftover p i) = Leftover (go p) i- in go (c0 Done)--instance MonadCatch m => MonadCatch (ConduitM i o m) where- catch (ConduitM p0) onErr = ConduitM $ \rest -> let- go (Done r) = rest r- go (PipeM mp) = PipeM $ catch (liftM go mp) (return . flip unConduitM rest . onErr)- go (Leftover p i) = Leftover (go p) i- go (NeedInput x y) = NeedInput (go . x) (go . y)- go (HaveOutput p c o) = HaveOutput (go p) c o- in go (p0 Done)--instance MonadIO m => MonadIO (ConduitM i o m) where- liftIO = lift . liftIO- {-# INLINE liftIO #-}--instance MonadReader r m => MonadReader r (ConduitM i o m) where- ask = lift ask- {-# INLINE ask #-}-- local f (ConduitM c0) = ConduitM $ \rest ->- let go (HaveOutput p c o) = HaveOutput (go p) c o- go (NeedInput p c) = NeedInput (\i -> go (p i)) (\u -> go (c u))- go (Done x) = rest x- go (PipeM mp) = PipeM (liftM go $ local f mp)- go (Leftover p i) = Leftover (go p) i- in go (c0 Done)--#ifndef MIN_VERSION_mtl-#define MIN_VERSION_mtl(x, y, z) 0-#endif--instance MonadWriter w m => MonadWriter w (ConduitM i o m) where-#if MIN_VERSION_mtl(2, 1, 0)- writer = lift . writer-#endif- tell = lift . tell-- listen (ConduitM c0) = ConduitM $ \rest ->- let go front (HaveOutput p c o) = HaveOutput (go front p) c o- go front (NeedInput p c) = NeedInput (\i -> go front (p i)) (\u -> go front (c u))- go front (Done x) = rest (x, front)- go front (PipeM mp) = PipeM $ do- (p,w) <- listen mp- return $ go (front `mappend` w) p- go front (Leftover p i) = Leftover (go front p) i- in go mempty (c0 Done)-- pass (ConduitM c0) = ConduitM $ \rest ->- let go front (HaveOutput p c o) = HaveOutput (go front p) c o- go front (NeedInput p c) = NeedInput (\i -> go front (p i)) (\u -> go front (c u))- go front (PipeM mp) = PipeM $ do- (p,w) <- censor (const mempty) (listen mp)- return $ go (front `mappend` w) p- go front (Done (x,f)) = PipeM $ do- tell (f front)- return $ rest x- go front (Leftover p i) = Leftover (go front p) i- in go mempty (c0 Done)--instance MonadState s m => MonadState s (ConduitM i o m) where- get = lift get- put = lift . put-#if MIN_VERSION_mtl(2, 1, 0)- state = lift . state-#endif--instance MonadRWS r w s m => MonadRWS r w s (ConduitM i o m)--instance MonadError e m => MonadError e (ConduitM i o m) where- throwError = lift . throwError- catchError (ConduitM c0) f = ConduitM $ \rest ->- let go (HaveOutput p c o) = HaveOutput (go p) c o- go (NeedInput p c) = NeedInput (\i -> go (p i)) (\u -> go (c u))- go (Done x) = rest x- go (PipeM mp) =- PipeM $ catchError (liftM go mp) $ \e -> do- return $ unConduitM (f e) rest- go (Leftover p i) = Leftover (go p) i- in go (c0 Done)--instance MonadBase base m => MonadBase base (ConduitM i o m) where- liftBase = lift . liftBase- {-# INLINE liftBase #-}--instance MonadTrans (ConduitM i o) where- lift mr = ConduitM $ \rest -> PipeM (liftM rest mr)- {-# INLINE [1] lift #-}--instance MonadResource m => MonadResource (ConduitM i o m) where- liftResourceT = lift . liftResourceT- {-# INLINE liftResourceT #-}--instance Monad m => Semigroup (ConduitM i o m ()) where- (<>) = (>>)- {-# INLINE (<>) #-}--instance Monad m => Monoid (ConduitM i o m ()) where- mempty = return ()- {-# INLINE mempty #-}-#if !(MIN_VERSION_base(4,11,0))- mappend = (<>)- {-# INLINE mappend #-}-#endif--instance PrimMonad m => PrimMonad (ConduitM i o m) where- type PrimState (ConduitM i o m) = PrimState m- primitive = lift . primitive---- | Provides a stream of output values, without consuming any input or--- producing a final result.------ Since 0.5.0-type Source m o = ConduitM () o m ()---- | 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 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--- producing any output.------ > type Sink i m r = ConduitM i Void m r------ Since 0.5.0-type Sink i = ConduitM i Void---- | 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 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,--- without producing a final result.------ Since 0.5.0-type Conduit i m o = ConduitM i o m ()---- | A @Source@ which has been started, but has not yet completed.------ This type contains both the current state of the @Source@, and the finalizer--- to be run to close it.------ Since 0.5.0-data ResumableSource m o = ResumableSource (Pipe () () o () m ()) (m ())---- | Since 1.0.13-instance MFunctor ResumableSource where- hoist nat (ResumableSource src m) = ResumableSource (hoist nat src) (nat m)---- | Connect a @Source@ to a @Sink@ until the latter closes. Returns both the--- most recent state of the @Source@ and the result of the @Sink@.------ We use a @ResumableSource@ to keep track of the most recent finalizer--- provided by the @Source@.------ Since 0.5.0-connectResume :: Monad m- => ResumableSource m o- -> Sink o m r- -> m (ResumableSource m o, r)-connectResume (ResumableSource left0 leftFinal0) (ConduitM right0) =- goRight leftFinal0 left0 (right0 Done)- where- goRight leftFinal left right =- case right of- HaveOutput _ _ o -> absurd o- NeedInput rp rc -> goLeft rp rc leftFinal left- Done r2 -> return (ResumableSource left leftFinal, r2)- PipeM mp -> mp >>= goRight leftFinal left- Leftover p i -> goRight leftFinal (HaveOutput left leftFinal i) p-- goLeft rp rc leftFinal left =- case left of- HaveOutput left' leftFinal' o -> goRight leftFinal' left' (rp o)- NeedInput _ lc -> recurse (lc ())- Done () -> goRight (return ()) (Done ()) (rc ())- PipeM mp -> mp >>= recurse- Leftover p () -> recurse p- where- recurse = goLeft rp rc leftFinal--sourceToPipe :: Monad m => Source m o -> Pipe l i o u m ()-sourceToPipe =- go . flip unConduitM Done- where- go (HaveOutput p c o) = HaveOutput (go p) c o- go (NeedInput _ c) = go $ c ()- go (Done ()) = Done ()- go (PipeM mp) = PipeM (liftM go mp)- go (Leftover p ()) = go p--sinkToPipe :: Monad m => Sink i m r -> Pipe l i o u m r-sinkToPipe =- go . injectLeftovers . flip unConduitM Done- where- go (HaveOutput _ _ o) = absurd o- go (NeedInput p c) = NeedInput (go . p) (const $ go $ c ())- go (Done r) = Done r- go (PipeM mp) = PipeM (liftM go mp)- go (Leftover _ l) = absurd l--conduitToPipe :: Monad m => Conduit i m o -> Pipe l i o u m ()-conduitToPipe =- go . injectLeftovers . flip unConduitM Done- where- go (HaveOutput p c o) = HaveOutput (go p) c o- go (NeedInput p c) = NeedInput (go . p) (const $ go $ c ())- go (Done ()) = Done ()- go (PipeM mp) = PipeM (liftM go mp)- go (Leftover _ l) = absurd l---- | Unwraps a @ResumableSource@ into a @Source@ and a finalizer.------ A @ResumableSource@ represents a @Source@ which has already been run, and--- therefore has a finalizer registered. As a result, if we want to turn it--- into a regular @Source@, we need to ensure that the finalizer will be run--- 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--- above two conditions hold. Once you call that finalizer, the @Source@ is--- invalidated and cannot be used.------ Since 0.5.2-unwrapResumable :: MonadIO m => ResumableSource m o -> m (Source m o, m ())-unwrapResumable (ResumableSource src final) = do- ref <- liftIO $ I.newIORef True- let final' = do- x <- liftIO $ I.readIORef ref- when x final- return (liftIO (I.writeIORef ref False) >> (ConduitM (src >>=)), final')---- | Turn a @Source@ into a @ResumableSource@ with no attached finalizer.------ Since 1.1.4-newResumableSource :: Monad m => Source m o -> ResumableSource m o-newResumableSource (ConduitM s) = ResumableSource (s Done) (return ())---- | Generalize a 'Source' to a 'Producer'.------ Since 1.0.0-toProducer :: Monad m => Source m a -> Producer m a-toProducer (ConduitM c0) = ConduitM $ \rest -> let- go (HaveOutput p c o) = HaveOutput (go p) c o- go (NeedInput _ c) = go (c ())- go (Done r) = rest r- go (PipeM mp) = PipeM (liftM go mp)- go (Leftover p ()) = go p- in go (c0 Done)---- | Generalize a 'Sink' to a 'Consumer'.------ Since 1.0.0-toConsumer :: Monad m => Sink a m b -> Consumer a m b-toConsumer (ConduitM c0) = ConduitM $ \rest -> let- go (HaveOutput _ _ o) = absurd o- go (NeedInput p c) = NeedInput (go . p) (go . c)- go (Done r) = rest r- go (PipeM mp) = PipeM (liftM go mp)- go (Leftover p l) = Leftover (go p) l- in go (c0 Done)---- | Catch all exceptions thrown by the current component of the pipeline.------ Note: this will /not/ catch exceptions thrown by other components! For--- example, if an exception is thrown in a @Source@ feeding to a @Sink@, and--- the @Sink@ uses @catchC@, the exception will /not/ be caught.------ Due to this behavior (as well as lack of async exception safety), you--- should not try to implement combinators such as @onException@ in terms of this--- primitive function.------ Note also that the exception handling will /not/ be applied to any--- finalizers generated by this conduit.------ Since 1.0.11-catchC :: (MonadBaseControl IO m, Exception e)- => ConduitM i o m r- -> (e -> ConduitM i o m r)- -> ConduitM i o m r-catchC (ConduitM p0) onErr = ConduitM $ \rest -> let- go (Done r) = rest r- go (PipeM mp) = PipeM $ E.catch (liftM go mp)- (return . flip unConduitM rest . onErr)- go (Leftover p i) = Leftover (go p) i- go (NeedInput x y) = NeedInput (go . x) (go . y)- go (HaveOutput p c o) = HaveOutput (go p) c o- in go (p0 Done)-{-# INLINE catchC #-}---- | The same as @flip catchC@.------ Since 1.0.11-handleC :: (MonadBaseControl IO m, Exception e)- => (e -> ConduitM i o m r)- -> ConduitM i o m r- -> ConduitM i o m r-handleC = flip catchC-{-# INLINE handleC #-}---- | A version of @try@ for use within a pipeline. See the comments in @catchC@--- for more details.------ Since 1.0.11-tryC :: (MonadBaseControl IO m, Exception e)- => ConduitM i o m r- -> ConduitM i o m (Either e r)-tryC (ConduitM c0) = ConduitM $ \rest -> let- go (Done r) = rest (Right r)- go (PipeM mp) = PipeM $ E.catch (liftM go mp) (return . rest . Left)- go (Leftover p i) = Leftover (go p) i- go (NeedInput x y) = NeedInput (go . x) (go . y)- go (HaveOutput p c o) = HaveOutput (go p) c o- in go (c0 Done)-{-# INLINE tryC #-}---- | Combines two sinks. The new sink will complete when both input sinks have--- completed.------ Any leftovers are discarded.------ Since 0.4.1-zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')-zipSinks (ConduitM x0) (ConduitM y0) = ConduitM $ \rest -> let- Leftover _ i >< _ = absurd i- _ >< Leftover _ i = absurd i- HaveOutput _ _ o >< _ = absurd o- _ >< HaveOutput _ _ o = absurd o-- PipeM mx >< y = PipeM (liftM (>< y) mx)- x >< PipeM my = PipeM (liftM (x ><) my)- Done x >< Done y = rest (x, y)- 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)- in injectLeftovers (x0 Done) >< injectLeftovers (y0 Done)---- | Combines two sources. The new source will stop producing once either--- source has been exhausted.------ Since 1.0.13-zipSources :: Monad m => Source m a -> Source m b -> Source m (a, b)-zipSources (ConduitM left0) (ConduitM right0) = ConduitM $ \rest -> let- go (Leftover left ()) right = go left right- go left (Leftover right ()) = go left right- go (Done ()) (Done ()) = rest ()- go (Done ()) (HaveOutput _ close _) = PipeM (close >> return (rest ()))- go (HaveOutput _ close _) (Done ()) = PipeM (close >> return (rest ()))- go (Done ()) (PipeM _) = rest ()- go (PipeM _) (Done ()) = rest ()- go (PipeM mx) (PipeM my) = PipeM (liftM2 go mx my)- go (PipeM mx) y@HaveOutput{} = PipeM (liftM (\x -> go x y) mx)- go x@HaveOutput{} (PipeM my) = PipeM (liftM (go x) my)- go (HaveOutput srcx closex x) (HaveOutput srcy closey y) = HaveOutput (go srcx srcy) (closex >> closey) (x, y)- go (NeedInput _ c) right = go (c ()) right- go left (NeedInput _ c) = go left (c ())- in go (left0 Done) (right0 Done)---- | Combines two sources. The new source will stop producing once either--- source has been exhausted.------ Since 1.0.13-zipSourcesApp :: Monad m => Source m (a -> b) -> Source m a -> Source m b-zipSourcesApp (ConduitM left0) (ConduitM right0) = ConduitM $ \rest -> let- go (Leftover left ()) right = go left right- go left (Leftover right ()) = go left right- go (Done ()) (Done ()) = rest ()- go (Done ()) (HaveOutput _ close _) = PipeM (close >> return (rest ()))- go (HaveOutput _ close _) (Done ()) = PipeM (close >> return (rest ()))- go (Done ()) (PipeM _) = rest ()- go (PipeM _) (Done ()) = rest ()- go (PipeM mx) (PipeM my) = PipeM (liftM2 go mx my)- go (PipeM mx) y@HaveOutput{} = PipeM (liftM (\x -> go x y) mx)- go x@HaveOutput{} (PipeM my) = PipeM (liftM (go x) my)- go (HaveOutput srcx closex x) (HaveOutput srcy closey y) = HaveOutput (go srcx srcy) (closex >> closey) (x y)- go (NeedInput _ c) right = go (c ()) right- go left (NeedInput _ c) = go left (c ())- in go (left0 Done) (right0 Done)---- |------ Since 1.0.17-zipConduitApp- :: Monad m- => ConduitM i o m (x -> y)- -> ConduitM i o m x- -> ConduitM i o m y-zipConduitApp (ConduitM left0) (ConduitM right0) = ConduitM $ \rest -> let- go _ _ (Done f) (Done x) = rest (f x)- go finalX finalY (PipeM mx) y = PipeM (flip (go finalX finalY) y `liftM` mx)- go finalX finalY x (PipeM my) = PipeM (go finalX finalY x `liftM` my)- go _ finalY (HaveOutput x finalX o) y = HaveOutput- (go finalX finalY x y)- (finalX >> finalY)- o- go finalX _ x (HaveOutput y finalY o) = HaveOutput- (go finalX finalY x y)- (finalX >> finalY)- o- go _ _ (Leftover _ i) _ = absurd i- go _ _ _ (Leftover _ i) = absurd i- go finalX finalY (NeedInput px cx) (NeedInput py cy) = NeedInput- (\i -> go finalX finalY (px i) (py i))- (\u -> go finalX finalY (cx u) (cy u))- go finalX finalY (NeedInput px cx) (Done y) = NeedInput- (\i -> go finalX finalY (px i) (Done y))- (\u -> go finalX finalY (cx u) (Done y))- go finalX finalY (Done x) (NeedInput py cy) = NeedInput- (\i -> go finalX finalY (Done x) (py i))- (\u -> go finalX finalY (Done x) (cy u))- in go (return ()) (return ()) (injectLeftovers $ left0 Done) (injectLeftovers $ right0 Done)---- | Same as normal fusion (e.g. @=$=@), except instead of discarding leftovers--- from the downstream component, return them.------ Since 1.0.17-fuseReturnLeftovers :: Monad m- => ConduitM a b m ()- -> ConduitM b c m r- -> ConduitM a c m (r, [b])-fuseReturnLeftovers (ConduitM left0) (ConduitM right0) = ConduitM $ \rest -> let- goRight final bs left right =- case right of- HaveOutput p c o -> HaveOutput (recurse p) (c >> final) o- NeedInput rp rc ->- case bs of- [] -> goLeft rp rc final left- b:bs' -> goRight final bs' left (rp b)- Done r2 -> PipeM (final >> return (rest (r2, bs)))- PipeM mp -> PipeM (liftM recurse mp)- Leftover p b -> goRight final (b:bs) left p- where- recurse = goRight final bs left-- goLeft rp rc final left =- case left of- HaveOutput left' final' o -> goRight final' [] left' (rp o)- NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)- Done r1 -> goRight (return ()) [] (Done r1) (rc r1)- PipeM mp -> PipeM (liftM recurse mp)- Leftover left' i -> Leftover (recurse left') i- where- recurse = goLeft rp rc final- in goRight (return ()) [] (left0 Done) (right0 Done)---- | Similar to @fuseReturnLeftovers@, but use the provided function to convert--- downstream leftovers to upstream leftovers.------ Since 1.0.17-fuseLeftovers- :: Monad m- => ([b] -> [a])- -> ConduitM a b m ()- -> ConduitM b c m r- -> ConduitM a c m r-fuseLeftovers f left right = do- (r, bs) <- fuseReturnLeftovers left right- mapM_ leftover $ reverse $ f bs- return r---- | A generalization of 'ResumableSource'. Allows to resume an arbitrary--- conduit, keeping its state and using it later (or finalizing it).------ Since 1.0.17-data ResumableConduit i m o =- ResumableConduit (Pipe i i o () m ()) (m ())---- | Connect a 'ResumableConduit' to a sink and return the output of the sink--- together with a new 'ResumableConduit'.------ Since 1.0.17-connectResumeConduit- :: Monad m- => ResumableConduit i m o- -> Sink o m r- -> Sink i m (ResumableConduit i m o, r)-connectResumeConduit (ResumableConduit left0 leftFinal0) (ConduitM right0) = ConduitM $ \rest -> let- goRight leftFinal left right =- case right of- HaveOutput _ _ o -> absurd o- NeedInput rp rc -> goLeft rp rc leftFinal left- Done r2 -> rest (ResumableConduit left leftFinal, r2)- PipeM mp -> PipeM (liftM (goRight leftFinal left) mp)- Leftover p i -> goRight leftFinal (HaveOutput left leftFinal i) p-- goLeft rp rc leftFinal left =- case left of- HaveOutput left' leftFinal' o -> goRight leftFinal' left' (rp o)- NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)- Done () -> goRight (return ()) (Done ()) (rc ())- PipeM mp -> PipeM (liftM recurse mp)- Leftover left' i -> Leftover (recurse left') i -- recurse p- where- recurse = goLeft rp rc leftFinal- in goRight leftFinal0 left0 (right0 Done)---- | Unwraps a @ResumableConduit@ into a @Conduit@ and a finalizer.------ Since 'unwrapResumable' for more information.------ Since 1.0.17-unwrapResumableConduit :: MonadIO m => ResumableConduit i m o -> m (Conduit i m o, m ())-unwrapResumableConduit (ResumableConduit src final) = do- ref <- liftIO $ I.newIORef True- let final' = do- x <- liftIO $ I.readIORef ref- when x final- return (ConduitM ((liftIO (I.writeIORef ref False) >> src) >>=), final')---- | Turn a @Conduit@ into a @ResumableConduit@ with no attached finalizer.------ Since 1.1.4-newResumableConduit :: Monad m => Conduit i m o -> ResumableConduit i m o-newResumableConduit (ConduitM c) = ResumableConduit (c Done) (return ())----- | Merge a @Source@ into a @Conduit@.--- The new conduit will stop processing once either source or upstream have been exhausted.-mergeSource- :: Monad m- => Source m i- -> Conduit a m (i, a)-mergeSource = loop . newResumableSource- where- loop :: Monad m => ResumableSource m i -> Conduit a m (i, a)- loop src0 = await >>= maybe (lift $ closeResumableSource src0) go- where- go a = do- (src1, mi) <- lift $ src0 $$++ await- case mi of- Nothing -> lift $ closeResumableSource src1- Just i -> yield (i, a) >> loop src1----- | 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.1.0-passthroughSink :: Monad m- => Sink i m r- -> (r -> m ()) -- ^ finalizer- -> Conduit i m i-passthroughSink (ConduitM sink0) final = ConduitM $ \rest -> let- -- A bit of explanation is in order, this function is- -- non-obvious. The purpose of go is to keep track of the sink- -- we're passing values to, and then yield values downstream. The- -- third argument to go is the current state of that sink. That's- -- relatively straightforward.- --- -- The second value is the leftover buffer. These are values that- -- the sink itself has called leftover on, and must be provided- -- back to the sink the next time it awaits. _However_, these- -- values should _not_ be reyielded downstream: we have already- -- yielded them downstream ourself, and it is the responsibility- -- of the functions wrapping around passthroughSink to handle the- -- leftovers from downstream.- --- -- The trickiest bit is the first argument, which is a solution to- -- bug https://github.com/snoyberg/conduit/issues/304. The issue- -- is that, once we get a value, we need to provide it to both the- -- inner sink _and_ yield it downstream. The obvious thing to do- -- is yield first and then recursively call go. Unfortunately,- -- this doesn't work in all cases: if the downstream component- -- never calls await again, our yield call will never return, and- -- our sink will not get the last value. This results is confusing- -- behavior where the sink and downstream component receive a- -- different number of values.- --- -- Solution: keep a buffer of the next value to yield downstream,- -- and only yield it downstream in one of two cases: our sink is- -- asking for another value, or our sink is done. This way, we- -- ensure that, in all cases, we pass exactly the same number of- -- values to the inner sink as to downstream.-- go mbuf _ (Done r) = do- maybe (return ()) CI.yield mbuf- lift $ final r- unConduitM (awaitForever yield) rest- go mbuf is (Leftover sink i) = go mbuf (i:is) sink- go _ _ (HaveOutput _ _ o) = absurd o- go mbuf is (PipeM mx) = do- x <- lift mx- go mbuf is x- go mbuf (i:is) (NeedInput next _) = go mbuf is (next i)- go mbuf [] (NeedInput next done) = do- maybe (return ()) CI.yield mbuf- mx <- CI.await- case mx of- Nothing -> go Nothing [] (done ())- Just x -> go (Just x) [] (next x)- in go Nothing [] (sink0 Done)---- | Convert a @Source@ into a list. The basic functionality can be explained as:------ > sourceToList src = src $$ Data.Conduit.List.consume------ However, @sourceToList@ is able to produce its results lazily, which cannot--- be done when running a conduit pipeline in general. Unlike the--- @Data.Conduit.Lazy@ module (in conduit-extra), this function performs no--- unsafe I\/O operations, and therefore can only be as lazily as the--- underlying monad.------ Since 1.2.6-sourceToList :: Monad m => Source m a -> m [a]-sourceToList =- go . flip unConduitM Done- where- go (Done _) = return []- go (HaveOutput src _ x) = liftM (x:) (go src)- go (PipeM msrc) = msrc >>= go- go (NeedInput _ c) = go (c ())- go (Leftover p _) = go p---- Define fixity of all our operators-infixr 0 $$-infixl 1 $=-infixr 2 =$-infixr 2 =$=-infixr 0 $$+-infixr 0 $$++-infixr 0 $$+--infixl 1 $=+---- | The connect operator, which pulls data from a source and pushes to a sink.--- 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-($$) :: Monad m => Source m a -> Sink a m b -> m b-src $$ sink = do- (rsrc, res) <- src $$+ sink- rsrc $$+- return ()- return res-{-# INLINE [1] ($$) #-}---- | A synonym for '=$=' for backwards compatibility.------ Since 0.4.0-($=) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r-($=) = (=$=)-{-# INLINE [0] ($=) #-}-{-# RULES "conduit: $= is =$=" ($=) = (=$=) #-}---- | A synonym for '=$=' for backwards compatibility.------ Since 0.4.0-(=$) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r-(=$) = (=$=)-{-# INLINE [0] (=$) #-}-{-# RULES "conduit: =$ is =$=" (=$) = (=$=) #-}---- | Fusion operator, combining two @Conduit@s together into a new @Conduit@.------ Both @Conduit@s will be closed when the newly-created @Conduit@ is closed.------ Leftover data returned from the right @Conduit@ will be discarded.------ Since 0.4.0-(=$=) :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r-ConduitM left0 =$= ConduitM right0 = ConduitM $ \rest ->- let goRight final left right =- case right of- HaveOutput p c o -> HaveOutput (recurse p) (c >> final) o- NeedInput rp rc -> goLeft rp rc final left- Done r2 -> PipeM (final >> return (rest r2))- PipeM mp -> PipeM (liftM recurse mp)- Leftover right' i -> goRight final (HaveOutput left final i) right'- where- recurse = goRight final left-- goLeft rp rc final left =- case left of- HaveOutput left' final' o -> goRight final' left' (rp o)- NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)- Done r1 -> goRight (return ()) (Done r1) (rc r1)- PipeM mp -> PipeM (liftM recurse mp)- Leftover left' i -> Leftover (recurse left') i- where- recurse = goLeft rp rc final- in goRight (return ()) (left0 Done) (right0 Done)- where-{-# INLINE [1] (=$=) #-}---- | Wait for a single input value from upstream. If no data is available,--- returns @Nothing@. Once @await@ returns @Nothing@, subsequent calls will--- also return @Nothing@.------ Since 0.5.0-await :: Monad m => Consumer i m (Maybe i)-await = ConduitM $ \f -> NeedInput (f . Just) (const $ f Nothing)-{-# INLINE [0] await #-}--await' :: Monad m- => ConduitM i o m r- -> (i -> ConduitM i o m r)- -> ConduitM i o m r-await' f g = ConduitM $ \rest -> NeedInput- (\i -> unConduitM (g i) rest)- (const $ unConduitM f rest)-{-# INLINE await' #-}-{-# RULES "conduit: await >>= maybe" forall x y. await >>= maybe x y = await' x y #-}---- | 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 o = yieldOr o (return ())-{-# INLINE yield #-}---- | Send a monadic value downstream for the next component to consume.------ @since 1.2.7-yieldM :: Monad m => m o -> ConduitM i o m ()-yieldM mo = lift mo >>= yield-{-# INLINE yieldM #-}-- -- FIXME rule won't fire, see FIXME in .Pipe; "mapM_ yield" mapM_ yield = ConduitM . sourceList---- | 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 i = ConduitM $ \rest -> Leftover (rest ()) i-{-# INLINE leftover #-}---- | Run a pipeline until processing completes.------ Since 1.2.1-runConduit :: Monad m => ConduitM () Void m r -> m r-runConduit (ConduitM p) = runPipe $ injectLeftovers $ p Done-{-# INLINE [0] runConduit #-}---- | Bracket a conduit computation between allocation and release of a--- resource. 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- -- ^ computation to run first (\"acquire resource\")- -> (a -> IO ())- -- ^ computation to run last (\"release resource\")- -> (a -> ConduitM i o m r)- -- ^ computation to run in-between- -> ConduitM i o m r- -- returns the value from the in-between computation-bracketP alloc free inside = ConduitM $ \rest -> PipeM $ do- (key, seed) <- allocate alloc free- return $ unConduitM (addCleanup (const $ release key) (inside seed)) rest---- | 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 cleanup (ConduitM c0) = ConduitM $ \rest -> let- go (Done r) = PipeM (cleanup True >> return (rest r))- go (HaveOutput src close x) = HaveOutput- (go src)- (cleanup False >> close)- x- go (PipeM msrc) = PipeM (liftM (go) msrc)- go (NeedInput p c) = NeedInput- (go . p)- (go . c)- go (Leftover p i) = Leftover (go p) i- in go (c0 Done)---- | 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 $ \rest -> HaveOutput (rest ()) m o-{-# INLINE yieldOr #-}---- | Wait for input forever, calling the given inner component for each piece of--- new input.------ 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 $ \rest ->- let go = NeedInput (\i -> unConduitM (f i) (const go)) rest- in go---- | 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>------ This function is just a synonym for 'hoist'.------ Since 0.4.0-transPipe :: Monad m => (forall a. m a -> n a) -> ConduitM i o m r -> ConduitM i o n r-transPipe = hoist---- | 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 c0) = ConduitM $ \rest -> let- go (HaveOutput p c o) = HaveOutput (go p) c (f o)- go (NeedInput p c) = NeedInput (go . p) (go . c)- go (Done r) = rest r- go (PipeM mp) = PipeM (liftM (go) mp)- go (Leftover p i) = Leftover (go p) i- in go (c0 Done)---- | 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 c0) = ConduitM $ \rest -> let- go (HaveOutput p c o) = maybe id (\o' p' -> HaveOutput p' c o') (f o) (go p)- go (NeedInput p c) = NeedInput (go . p) (go . c)- go (Done r) = rest r- go (PipeM mp) = PipeM (liftM (go) mp)- go (Leftover p i) = Leftover (go p) i- in go (c0 Done)---- | 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 f' (ConduitM c0) = ConduitM $ \rest -> let- go (HaveOutput p c o) = HaveOutput (go p) c o- go (NeedInput p c) = NeedInput (go . p . f) (go . c)- go (Done r) = rest r- go (PipeM mp) = PipeM $ liftM go mp- go (Leftover p i) = maybe id (flip Leftover) (f' i) (go p)- in go (c0 Done)---- | 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--- in the @Sink@ monad.------ Mnemonic: connect + do more.------ Since 0.5.0-($$+) :: Monad m => Source m a -> Sink a m b -> m (ResumableSource m a, b)-ConduitM src $$+ sink =- connectResume (ResumableSource (src Done) (return ())) sink-{-# INLINE ($$+) #-}---- | Continue processing after usage of @$$+@.------ Since 0.5.0-($$++) :: Monad m => ResumableSource m a -> Sink a m b -> m (ResumableSource m a, b)-($$++) = connectResume-{-# INLINE ($$++) #-}---- | Complete processing of a @ResumableSource@. This will run the finalizer--- associated with the @ResumableSource@. In order to guarantee process resource--- finalization, you /must/ use this operator after using @$$+@ and @$$++@.------ Since 0.5.0-($$+-) :: Monad m => ResumableSource m a -> Sink a m b -> m b-rsrc $$+- sink = do- (ResumableSource _ final, res) <- connectResume rsrc sink- final- return res-{-# INLINE ($$+-) #-}---- | Left fusion for a resumable source.------ Since 1.0.16-($=+) :: Monad m => ResumableSource m a -> Conduit a m b -> ResumableSource m b-ResumableSource src final $=+ ConduitM sink =- ResumableSource (src `pipeL` sink Done) final---- | Execute the finalizer associated with a @ResumableSource@, rendering the--- @ResumableSource@ invalid for further use.------ This is just a more explicit version of @$$+- return ()@.------ Since 1.1.3-closeResumableSource :: Monad m => ResumableSource m a -> m ()-closeResumableSource = ($$+- return ())---- | Provide for a stream of data that can be flushed.------ A number of @Conduit@s (e.g., zlib compression) need the ability to flush--- the stream at some point. This provides a single wrapper datatype to be used--- in all such circumstances.------ Since 0.3.0-data Flush a = Chunk a | Flush- deriving (Show, Eq, Ord)-instance Functor Flush where- fmap _ Flush = Flush- fmap f (Chunk a) = Chunk (f a)---- | A wrapper for defining an 'Applicative' instance for 'Source's which allows--- to combine sources together, generalizing 'zipSources'. A combined source--- will take input yielded from each of its @Source@s until any of them stop--- producing output.------ Since 1.0.13-newtype ZipSource m o = ZipSource { getZipSource :: Source m o }--instance Monad m => Functor (ZipSource m) where- fmap f = ZipSource . mapOutput f . getZipSource-instance Monad m => Applicative (ZipSource m) where- pure = ZipSource . forever . yield- (ZipSource f) <*> (ZipSource x) = ZipSource $ zipSourcesApp f x---- | Coalesce all values yielded by all of the @Source@s.------ Implemented on top of @ZipSource@ and as such, it exhibits the same--- short-circuiting behavior as @ZipSource@. See that data type for more--- details. If you want to create a source that yields *all* values from--- multiple sources, use `sequence_`.------ Since 1.0.13-sequenceSources :: (Traversable f, Monad m) => f (Source m o) -> Source m (f o)-sequenceSources = getZipSource . sequenceA . fmap ZipSource---- | A wrapper for defining an 'Applicative' instance for 'Sink's which allows--- to combine sinks together, generalizing 'zipSinks'. A combined sink--- distributes the input to all its participants and when all finish, produces--- the result. This allows to define functions like------ @--- sequenceSinks :: (Monad m)--- => [Sink i m r] -> Sink i m [r]--- sequenceSinks = getZipSink . sequenceA . fmap ZipSink--- @------ Note that the standard 'Applicative' instance for conduits works--- differently. It feeds one sink with input until it finishes, then switches--- to another, etc., and at the end combines their results.------ This newtype is in fact a type constrained version of 'ZipConduit', and has--- the same behavior. It's presented as a separate type since (1) it--- historically predates @ZipConduit@, and (2) the type constraining can make--- your code clearer (and thereby make your error messages more easily--- understood).------ Since 1.0.13-newtype ZipSink i m r = ZipSink { getZipSink :: Sink i m r }--instance Monad m => Functor (ZipSink i m) where- fmap f (ZipSink x) = ZipSink (liftM f x)-instance Monad m => Applicative (ZipSink i m) where- pure = ZipSink . return- (ZipSink f) <*> (ZipSink x) =- ZipSink $ liftM (uncurry ($)) $ zipSinks f x---- | Send incoming values to all of the @Sink@ providing, and ultimately--- coalesce together all return values.------ Implemented on top of @ZipSink@, see that data type for more details.------ Since 1.0.13-sequenceSinks :: (Traversable f, Monad m) => f (Sink i m r) -> Sink i m (f r)-sequenceSinks = getZipSink . sequenceA . fmap ZipSink---- | The connect-and-resume operator. This does not close the @Conduit@, but--- instead returns it to be used again. This allows a @Conduit@ to be used--- incrementally in a large program, without forcing the entire program to live--- in the @Sink@ monad.------ Leftover data returned from the @Sink@ will be discarded.------ Mnemonic: connect + do more.------ Since 1.0.17-(=$$+) :: Monad m => Conduit a m b -> Sink b m r -> Sink a m (ResumableConduit a m b, r)-(=$$+) (ConduitM conduit) = connectResumeConduit (ResumableConduit (conduit Done) (return ()))-{-# INLINE (=$$+) #-}---- | Continue processing after usage of '=$$+'. Connect a 'ResumableConduit' to--- a sink and return the output of the sink together with a new--- 'ResumableConduit'.------ Since 1.0.17-(=$$++) :: Monad m => ResumableConduit i m o -> Sink o m r -> Sink i m (ResumableConduit i m o, r)-(=$$++) = connectResumeConduit-{-# INLINE (=$$++) #-}---- | Complete processing of a 'ResumableConduit'. This will run the finalizer--- associated with the @ResumableConduit@. In order to guarantee process--- resource finalization, you /must/ use this operator after using '=$$+' and--- '=$$++'.------ Since 1.0.17-(=$$+-) :: Monad m => ResumableConduit i m o -> Sink o m r -> Sink i m r-rsrc =$$+- sink = do- (ResumableConduit _ final, res) <- connectResumeConduit rsrc sink- lift final- return res-{-# INLINE (=$$+-) #-}---infixr 0 =$$+-infixr 0 =$$++-infixr 0 =$$+----- | Provides an alternative @Applicative@ instance for @ConduitM@. In this instance,--- every incoming value is provided to all @ConduitM@s, and output is coalesced together.--- Leftovers from individual @ConduitM@s will be used within that component, and then discarded--- at the end of their computation. Output and finalizers will both be handled in a left-biased manner.------ As an example, take the following program:------ @--- main :: IO ()--- main = do--- let src = mapM_ yield [1..3 :: Int]--- conduit1 = CL.map (+1)--- conduit2 = CL.concatMap (replicate 2)--- conduit = getZipConduit $ ZipConduit conduit1 <* ZipConduit conduit2--- sink = CL.mapM_ print--- src $$ conduit =$ sink--- @------ It will produce the output: 2, 1, 1, 3, 2, 2, 4, 3, 3------ Since 1.0.17-newtype ZipConduit i o m r = ZipConduit { getZipConduit :: ConduitM i o m r }- deriving Functor-instance Monad m => Applicative (ZipConduit i o m) where- pure = ZipConduit . pure- ZipConduit left <*> ZipConduit right = ZipConduit (zipConduitApp left right)---- | Provide identical input to all of the @Conduit@s and combine their outputs--- into a single stream.------ Implemented on top of @ZipConduit@, see that data type for more details.------ Since 1.0.17-sequenceConduits :: (Traversable f, Monad m) => f (ConduitM i o m r) -> ConduitM i o m (f r)-sequenceConduits = getZipConduit . sequenceA . fmap ZipConduit---- | Fuse two @ConduitM@s together, and provide the return value of both. Note--- that this will force the entire upstream @ConduitM@ to be run to produce the--- result value, even if the downstream terminates early.------ Since 1.1.5-fuseBoth :: Monad m => ConduitM a b m r1 -> ConduitM b c m r2 -> ConduitM a c m (r1, r2)-fuseBoth (ConduitM up) (ConduitM down) =- ConduitM (pipeL (up Done) (withUpstream $ generalizeUpstream $ down Done) >>=)-{-# INLINE fuseBoth #-}---- | Like 'fuseBoth', but does not force consumption of the @Producer@.--- In the case that the @Producer@ terminates, the result value is--- provided as a @Just@ value. If it does not terminate, then a--- @Nothing@ value is returned.------ One thing to note here is that "termination" here only occurs if the--- @Producer@ actually yields a @Nothing@ value. For example, with the--- @Producer@ @mapM_ yield [1..5]@, if five values are requested, the--- @Producer@ has not yet terminated. Termination only occurs when the--- sixth value is awaited for and the @Producer@ signals termination.------ Since 1.2.4-fuseBothMaybe- :: Monad m- => ConduitM a b m r1- -> ConduitM b c m r2- -> ConduitM a c m (Maybe r1, r2)-fuseBothMaybe (ConduitM up) (ConduitM down) =- ConduitM (pipeL (up Done) (go Nothing $ down Done) >>=)- where- go mup (Done r) = Done (mup, r)- go mup (PipeM mp) = PipeM $ liftM (go mup) mp- go mup (HaveOutput p c o) = HaveOutput (go mup p) c o- go _ (NeedInput p c) = NeedInput- (\i -> go Nothing (p i))- (\u -> go (Just u) (c ()))- go mup (Leftover p i) = Leftover (go mup p) i-{-# INLINABLE fuseBothMaybe #-}---- | Same as @fuseBoth@, but ignore the return value from the downstream--- @Conduit@. Same caveats of forced consumption apply.------ Since 1.1.5-fuseUpstream :: Monad m => ConduitM a b m r -> Conduit b m c -> ConduitM a c m r-fuseUpstream up down = fmap fst (fuseBoth up down)-{-# INLINE fuseUpstream #-}---- Rewrite rules--{- FIXME-{-# RULES "conduit: ConduitM: lift x >>= f" forall m f. lift m >>= f = ConduitM (PipeM (liftM (unConduitM . f) m)) #-}-{-# RULES "conduit: ConduitM: lift x >> f" forall m f. lift m >> f = ConduitM (PipeM (liftM (\_ -> unConduitM f) m)) #-}--{-# RULES "conduit: ConduitM: liftIO x >>= f" forall m (f :: MonadIO m => a -> ConduitM i o m r). liftIO m >>= f = ConduitM (PipeM (liftM (unConduitM . f) (liftIO m))) #-}-{-# RULES "conduit: ConduitM: liftIO x >> f" forall m (f :: MonadIO m => ConduitM i o m r). liftIO m >> f = ConduitM (PipeM (liftM (\_ -> unConduitM f) (liftIO m))) #-}--{-# RULES "conduit: ConduitM: liftBase x >>= f" forall m (f :: MonadBase b m => a -> ConduitM i o m r). liftBase m >>= f = ConduitM (PipeM (liftM (unConduitM . f) (liftBase m))) #-}-{-# RULES "conduit: ConduitM: liftBase x >> f" forall m (f :: MonadBase b m => ConduitM i o m r). liftBase m >> f = ConduitM (PipeM (liftM (\_ -> unConduitM f) (liftBase m))) #-}--{-# RULES- "yield o >> p" forall o (p :: ConduitM i o m r). yield o >> p = ConduitM (HaveOutput (unConduitM p) (return ()) o)- ; "yieldOr o c >> p" forall o c (p :: ConduitM i o m r). yieldOr o c >> p =- ConduitM (HaveOutput (unConduitM p) c o)- ; "when yield next" forall b o p. when b (yield o) >> p =- if b then ConduitM (HaveOutput (unConduitM p) (return ()) o) else p- ; "unless yield next" forall b o p. unless b (yield o) >> p =- if b then p else ConduitM (HaveOutput (unConduitM p) (return ()) o)- ; "lift m >>= yield" forall m. lift m >>= yield = yieldM m- #-}-{-# RULES "conduit: leftover l >> p" forall l (p :: ConduitM i o m r). leftover l >> p =- ConduitM (Leftover (unConduitM p) l) #-}- -}
− Data/Conduit/Internal/Fusion.hs
@@ -1,213 +0,0 @@-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE Trustworthy #-}-module Data.Conduit.Internal.Fusion- ( -- ** Types- Step (..)- , Stream (..)- , ConduitWithStream- , StreamConduitM- , StreamConduit- , StreamSource- , StreamProducer- , StreamSink- , StreamConsumer- -- ** Functions- , streamConduit- , streamSource- , streamSourcePure- , unstream- ) where--import Data.Conduit.Internal.Conduit-import Data.Conduit.Internal.Pipe (Pipe (..))-import Data.Functor.Identity (Identity (runIdentity))-import Data.Void (Void, absurd)---- | This is the same as stream fusion\'s Step. Constructors are renamed to--- avoid confusion with conduit names.-data Step s o r- = Emit s o- | Skip s- | Stop r- deriving Functor--data Stream m o r = forall s. Stream- (s -> m (Step s o r))- (m s)--data ConduitWithStream i o m r = ConduitWithStream- (ConduitM i o m r)- (StreamConduitM i o m r)--type StreamConduitM i o m r = Stream m i () -> Stream m o r--type StreamConduit i m o = StreamConduitM i o m ()--type StreamSource m o = StreamConduitM () o m ()--type StreamProducer m o = forall i. StreamConduitM i o m ()--type StreamSink i m r = StreamConduitM i Void m r--type StreamConsumer i m r = forall o. StreamConduitM i o m r--unstream :: ConduitWithStream i o m r -> ConduitM i o m r-unstream (ConduitWithStream c _) = c-{-# INLINE [0] unstream #-}--fuseStream :: Monad m- => ConduitWithStream a b m ()- -> ConduitWithStream b c m r- -> ConduitWithStream a c m r-fuseStream (ConduitWithStream a x) (ConduitWithStream b y) = ConduitWithStream (a =$= b) (y . x)-{-# INLINE fuseStream #-}--{-# RULES "conduit: fuseStream" forall left right.- unstream left =$= unstream right = unstream (fuseStream left right)- #-}--runStream :: Monad m- => ConduitWithStream () Void m r- -> m r-runStream (ConduitWithStream _ f) =- run $ f $ Stream emptyStep (return ())- where- emptyStep _ = return $ Stop ()- run (Stream step ms0) =- ms0 >>= loop- where- loop s = do- res <- step s- case res of- Stop r -> return r- Skip s' -> loop s'- Emit _ o -> absurd o-{-# INLINE runStream #-}--{-# RULES "conduit: runStream" forall stream.- runConduit (unstream stream) = runStream stream- #-}--connectStream :: Monad m- => ConduitWithStream () i m ()- -> ConduitWithStream i Void m r- -> m r-connectStream (ConduitWithStream _ stream) (ConduitWithStream _ f) =- run $ f $ stream $ Stream emptyStep (return ())- where- emptyStep _ = return $ Stop ()- run (Stream step ms0) =- ms0 >>= loop- where- loop s = do- res <- step s- case res of- Stop r -> return r- Skip s' -> loop s'- Emit _ o -> absurd o-{-# INLINE connectStream #-}--{-# RULES "conduit: connectStream" forall left right.- unstream left $$ unstream right = connectStream left right- #-}--connectStream1 :: Monad m- => ConduitWithStream () i m ()- -> ConduitM i Void m r- -> m r-connectStream1 (ConduitWithStream _ fstream) (ConduitM sink0) =- case fstream $ Stream (const $ return $ Stop ()) (return ()) of- Stream step ms0 ->- let loop _ (Done r) _ = return r- loop ls (PipeM mp) s = mp >>= flip (loop ls) s- loop ls (Leftover p l) s = loop (l:ls) p s- loop _ (HaveOutput _ _ o) _ = absurd o- loop (l:ls) (NeedInput p _) s = loop ls (p l) s- loop [] (NeedInput p c) s = do- res <- step s- case res of- Stop () -> loop [] (c ()) s- Skip s' -> loop [] (NeedInput p c) s'- Emit s' i -> loop [] (p i) s'- in ms0 >>= loop [] (sink0 Done)-{-# INLINE connectStream1 #-}--{-# RULES "conduit: connectStream1" forall left right.- unstream left $$ right = connectStream1 left right- #-}--{---Not only will this rule not fire reliably, but due to finalizers, it can change-behavior unless implemented very carefully. Odds are that the careful-implementation won't be any faster, so leaving this commented out for now.--connectStream2 :: Monad m- => ConduitM () i m ()- -> ConduitWithStream i Void m r- -> m r-connectStream2 (ConduitM src0) (ConduitWithStream _ fstream) =- run $ fstream $ Stream step' $ return (return (), src0 Done)- where- step' (_, Done ()) = return $ Stop ()- {-# INLINE step' #-}-- run (Stream step ms0) =- ms0 >>= loop- where- loop s = do- res <- step s- case res of- Stop r -> return r- Emit _ o -> absurd o- Skip s' -> loop s'-{-# INLINE connectStream2 #-}--{-# RULES "conduit: connectStream2" forall left right.- left $$ unstream right = connectStream2 left right- #-}--}--streamConduit :: ConduitM i o m r- -> (Stream m i () -> Stream m o r)- -> ConduitWithStream i o m r-streamConduit = ConduitWithStream-{-# INLINE CONLIKE streamConduit #-}--streamSource- :: Monad m- => Stream m o ()- -> ConduitWithStream i o m ()-streamSource str@(Stream step ms0) =- ConduitWithStream con (const str)- where- con = ConduitM $ \rest -> PipeM $ do- s0 <- ms0- let loop s = do- res <- step s- case res of- Stop () -> return $ rest ()- Emit s' o -> return $ HaveOutput (PipeM $ loop s') (return ()) o- Skip s' -> loop s'- loop s0-{-# INLINE streamSource #-}--streamSourcePure- :: Monad m- => Stream Identity o ()- -> ConduitWithStream i o m ()-streamSourcePure (Stream step ms0) =- ConduitWithStream con (const $ Stream (return . runIdentity . step) (return s0))- where- s0 = runIdentity ms0- con = ConduitM $ \rest ->- let loop s =- case runIdentity $ step s of- Stop () -> rest ()- Emit s' o -> HaveOutput (loop s') (return ()) o- Skip s' -> loop s'- in loop s0-{-# INLINE streamSourcePure #-}
− Data/Conduit/Internal/List/Stream.hs
@@ -1,502 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE Trustworthy #-}-module Data.Conduit.Internal.List.Stream where--import Control.Monad (liftM)-import Data.Conduit.Internal.Fusion-import qualified Data.Foldable as F----FIXME: Should streamSource / streamSourcePure be used for sources?--unfoldS :: Monad m- => (b -> Maybe (a, b))- -> b- -> StreamProducer m a-unfoldS f s0 _ =- Stream step (return s0)- where- step s = return $- case f s of- Nothing -> Stop ()- Just (x, s') -> Emit s' x-{-# INLINE unfoldS #-}--unfoldEitherS :: Monad m- => (b -> Either r (a, b))- -> b- -> StreamConduitM i a m r-unfoldEitherS f s0 _ =- Stream step (return s0)- where- step s = return $- case f s of- Left r -> Stop r- Right (x, s') -> Emit s' x-{-# INLINE unfoldEitherS #-}--unfoldMS :: Monad m- => (b -> m (Maybe (a, b)))- -> b- -> StreamProducer m a-unfoldMS f s0 _ =- Stream step (return s0)- where- step s = do- ms' <- f s- return $ case ms' of- Nothing -> Stop ()- Just (x, s') -> Emit s' x-{-# INLINE unfoldMS #-}--unfoldEitherMS :: Monad m- => (b -> m (Either r (a, b)))- -> b- -> StreamConduitM i a m r-unfoldEitherMS f s0 _ =- Stream step (return s0)- where- step s = do- ms' <- f s- return $ case ms' of- Left r -> Stop r- Right (x, s') -> Emit s' x-{-# INLINE unfoldEitherMS #-}-sourceListS :: Monad m => [a] -> StreamProducer m a-sourceListS xs0 _ =- Stream (return . step) (return xs0)- where- step [] = Stop ()- step (x:xs) = Emit xs x-{-# INLINE sourceListS #-}--enumFromToS :: (Enum a, Prelude.Ord a, Monad m)- => a- -> a- -> StreamProducer m a-enumFromToS x0 y _ =- Stream step (return x0)- where- step x = return $ if x Prelude.> y- then Stop ()- else Emit (Prelude.succ x) x-{-# INLINE [0] enumFromToS #-}--enumFromToS_int :: (Prelude.Integral a, Monad m)- => a- -> a- -> StreamProducer m a-enumFromToS_int x0 y _ = x0 `seq` y `seq` Stream step (return x0)- where- step x | x <= y = return $ Emit (x Prelude.+ 1) x- | otherwise = return $ Stop ()-{-# INLINE enumFromToS_int #-}--{-# RULES "conduit: enumFromTo<Int>" forall f t.- enumFromToS f t = enumFromToS_int f t :: Monad m => StreamProducer m Int- #-}--iterateS :: Monad m => (a -> a) -> a -> StreamProducer m a-iterateS f x0 _ =- Stream (return . step) (return x0)- where- step x = Emit x' x- where- x' = f x-{-# INLINE iterateS #-}--replicateS :: Monad m => Int -> a -> StreamProducer m a-replicateS cnt0 a _ =- Stream step (return cnt0)- where- step cnt- | cnt <= 0 = return $ Stop ()- | otherwise = return $ Emit (cnt - 1) a-{-# INLINE replicateS #-}--replicateMS :: Monad m => Int -> m a -> StreamProducer m a-replicateMS cnt0 ma _ =- Stream step (return cnt0)- where- step cnt- | cnt <= 0 = return $ Stop ()- | otherwise = Emit (cnt - 1) `liftM` ma-{-# INLINE replicateMS #-}--foldS :: Monad m => (b -> a -> b) -> b -> StreamConsumer a m b-foldS f b0 (Stream step ms0) =- Stream step' (liftM (b0, ) ms0)- where- step' (!b, s) = do- res <- step s- return $ case res of- Stop () -> Stop b- Skip s' -> Skip (b, s')- Emit s' a -> Skip (f b a, s')-{-# INLINE foldS #-}--foldMS :: Monad m => (b -> a -> m b) -> b -> StreamConsumer a m b-foldMS f b0 (Stream step ms0) =- Stream step' (liftM (b0, ) ms0)- where- step' (!b, s) = do- res <- step s- case res of- Stop () -> return $ Stop b- Skip s' -> return $ Skip (b, s')- Emit s' a -> do- b' <- f b a- return $ Skip (b', s')-{-# INLINE foldMS #-}--mapM_S :: Monad m- => (a -> m ())- -> StreamConsumer a m ()-mapM_S f (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- case res of- Stop () -> return $ Stop ()- Skip s' -> return $ Skip s'- Emit s' x -> f x >> return (Skip s')-{-# INLINE [1] mapM_S #-}--dropS :: Monad m- => Int- -> StreamConsumer a m ()-dropS n0 (Stream step ms0) =- Stream step' (liftM (, n0) ms0)- where- step' (_, n) | n <= 0 = return $ Stop ()- step' (s, n) = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip (s', n)- Emit s' _ -> Skip (s', n - 1)-{-# INLINE dropS #-}--takeS :: Monad m- => Int- -> StreamConsumer a m [a]-takeS n0 (Stream step s0) =- Stream step' (liftM (id, n0,) s0)- where- step' (output, n, _) | n <= 0 = return $ Stop (output [])- step' (output, n, s) = do- res <- step s- return $ case res of- Stop () -> Stop (output [])- Skip s' -> Skip (output, n, s')- Emit s' x -> Skip (output . (x:), n - 1, s')-{-# INLINE takeS #-}--headS :: Monad m => StreamConsumer a m (Maybe a)-headS (Stream step s0) =- Stream step' s0- where- step' s = do- res <- step s- return $ case res of- Stop () -> Stop Nothing- Skip s' -> Skip s'- Emit _ x -> Stop (Just x)-{-# INLINE headS #-}--mapS :: Monad m => (a -> b) -> StreamConduit a m b-mapS f (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- return $ case res of- Stop r -> Stop r- Emit s' a -> Emit s' (f a)- Skip s' -> Skip s'-{-# INLINE mapS #-}--mapMS :: Monad m => (a -> m b) -> StreamConduit a m b-mapMS f (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- case res of- Stop r -> return $ Stop r- Emit s' a -> Emit s' `liftM` f a- Skip s' -> return $ Skip s'-{-# INLINE mapMS #-}--iterMS :: Monad m => (a -> m ()) -> StreamConduit a m a-iterMS f (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- case res of- Stop () -> return $ Stop ()- Skip s' -> return $ Skip s'- Emit s' x -> f x >> return (Emit s' x)-{-# INLINE iterMS #-}--mapMaybeS :: Monad m => (a -> Maybe b) -> StreamConduit a m b-mapMaybeS f (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip s'- Emit s' x ->- case f x of- Just y -> Emit s' y- Nothing -> Skip s'-{-# INLINE mapMaybeS #-}--mapMaybeMS :: Monad m => (a -> m (Maybe b)) -> StreamConduit a m b-mapMaybeMS f (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- case res of- Stop () -> return $ Stop ()- Skip s' -> return $ Skip s'- Emit s' x -> do- my <- f x- case my of- Just y -> return $ Emit s' y- Nothing -> return $ Skip s'-{-# INLINE mapMaybeMS #-}--catMaybesS :: Monad m => StreamConduit (Maybe a) m a-catMaybesS (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip s'- Emit s' Nothing -> Skip s'- Emit s' (Just x) -> Emit s' x-{-# INLINE catMaybesS #-}--concatS :: (Monad m, F.Foldable f) => StreamConduit (f a) m a-concatS (Stream step ms0) =- Stream step' (liftM ([], ) ms0)- where- step' ([], s) = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip ([], s')- Emit s' x -> Skip (F.toList x, s')- step' ((x:xs), s) = return (Emit (xs, s) x)-{-# INLINE concatS #-}--concatMapS :: Monad m => (a -> [b]) -> StreamConduit a m b-concatMapS f (Stream step ms0) =- Stream step' (liftM ([], ) ms0)- where- step' ([], s) = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip ([], s')- Emit s' x -> Skip (f x, s')- step' ((x:xs), s) = return (Emit (xs, s) x)-{-# INLINE concatMapS #-}--concatMapMS :: Monad m => (a -> m [b]) -> StreamConduit a m b-concatMapMS f (Stream step ms0) =- Stream step' (liftM ([], ) ms0)- where- step' ([], s) = do- res <- step s- case res of- Stop () -> return $ Stop ()- Skip s' -> return $ Skip ([], s')- Emit s' x -> do- xs <- f x- return $ Skip (xs, s')- step' ((x:xs), s) = return (Emit (xs, s) x)-{-# INLINE concatMapMS #-}--concatMapAccumS :: Monad m => (a -> accum -> (accum, [b])) -> accum -> StreamConduit a m b-concatMapAccumS f initial (Stream step ms0) =- Stream step' (liftM (initial, [], ) ms0)- where- step' (accum, [], s) = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip (accum, [], s')- Emit s' x ->- let (accum', xs) = f x accum- in Skip (accum', xs, s')- step' (accum, (x:xs), s) = return (Emit (accum, xs, s) x)-{-# INLINE concatMapAccumS #-}--mapAccumS :: Monad m => (a -> s -> (s, b)) -> s -> StreamConduitM a b m s-mapAccumS f initial (Stream step ms0) =- Stream step' (liftM (initial, ) ms0)- where- step' (accum, s) = do- res <- step s- return $ case res of- Stop () -> Stop accum- Skip s' -> Skip (accum, s')- Emit s' x ->- let (accum', r) = f x accum- in Emit (accum', s') r-{-# INLINE mapAccumS #-}--mapAccumMS :: Monad m => (a -> s -> m (s, b)) -> s -> StreamConduitM a b m s-mapAccumMS f initial (Stream step ms0) =- Stream step' (liftM (initial, ) ms0)- where- step' (accum, s) = do- res <- step s- case res of- Stop () -> return $ Stop accum- Skip s' -> return $ Skip (accum, s')- Emit s' x -> do- (accum', r) <- f x accum- return $ Emit (accum', s') r-{-# INLINE mapAccumMS #-}--concatMapAccumMS :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> StreamConduit a m b-concatMapAccumMS f initial (Stream step ms0) =- Stream step' (liftM (initial, [], ) ms0)- where- step' (accum, [], s) = do- res <- step s- case res of- Stop () -> return $ Stop ()- Skip s' -> return $ Skip (accum, [], s')- Emit s' x -> do- (accum', xs) <- f x accum- return $ Skip (accum', xs, s')- step' (accum, (x:xs), s) = return (Emit (accum, xs, s) x)-{-# INLINE concatMapAccumMS #-}--mapFoldableS :: (Monad m, F.Foldable f) => (a -> f b) -> StreamConduit a m b-mapFoldableS f (Stream step ms0) =- Stream step' (liftM ([], ) ms0)- where- step' ([], s) = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip ([], s')- Emit s' x -> Skip (F.toList (f x), s')- step' ((x:xs), s) = return (Emit (xs, s) x)-{-# INLINE mapFoldableS #-}--mapFoldableMS :: (Monad m, F.Foldable f) => (a -> m (f b)) -> StreamConduit a m b-mapFoldableMS f (Stream step ms0) =- Stream step' (liftM ([], ) ms0)- where- step' ([], s) = do- res <- step s- case res of- Stop () -> return $ Stop ()- Skip s' -> return $ Skip ([], s')- Emit s' x -> do- y <- f x- return $ Skip (F.toList y, s')- step' ((x:xs), s) = return (Emit (xs, s) x)-{-# INLINE mapFoldableMS #-}--consumeS :: Monad m => StreamConsumer a m [a]-consumeS (Stream step ms0) =- Stream step' (liftM (id,) ms0)- where- step' (front, s) = do- res <- step s- return $ case res of- Stop () -> Stop (front [])- Skip s' -> Skip (front, s')- Emit s' a -> Skip (front . (a:), s')-{-# INLINE consumeS #-}--groupByS :: Monad m => (a -> a -> Bool) -> StreamConduit a m [a]-groupByS f = mapS (Prelude.uncurry (:)) . groupBy1S id f-{-# INLINE groupByS #-}--groupOn1S :: (Monad m, Eq b) => (a -> b) -> StreamConduit a m (a, [a])-groupOn1S f = groupBy1S f (==)-{-# INLINE groupOn1S #-}--data GroupByState a b s- = GBStart s- | GBLoop ([a] -> [a]) a b s- | GBDone--groupBy1S :: Monad m => (a -> b) -> (b -> b -> Bool) -> StreamConduit a m (a, [a])-groupBy1S f eq (Stream step ms0) =- Stream step' (liftM GBStart ms0)- where- step' (GBStart s) = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip (GBStart s')- Emit s' x0 -> Skip (GBLoop id x0 (f x0) s')- step' (GBLoop rest x0 fx0 s) = do- res <- step s- return $ case res of- Stop () -> Emit GBDone (x0, rest [])- Skip s' -> Skip (GBLoop rest x0 fx0 s')- Emit s' x- | fx0 `eq` f x -> Skip (GBLoop (rest . (x:)) x0 fx0 s')- | otherwise -> Emit (GBLoop id x (f x) s') (x0, rest [])- step' GBDone = return $ Stop ()-{-# INLINE groupBy1S #-}--isolateS :: Monad m => Int -> StreamConduit a m a-isolateS count (Stream step ms0) =- Stream step' (liftM (count,) ms0)- where- step' (n, _) | n <= 0 = return $ Stop ()- step' (n, s) = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip (n, s')- Emit s' x -> Emit (n - 1, s') x-{-# INLINE isolateS #-}--filterS :: Monad m => (a -> Bool) -> StreamConduit a m a-filterS f (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip s'- Emit s' x- | f x -> Emit s' x- | otherwise -> Skip s'--sinkNullS :: Monad m => StreamConsumer a m ()-sinkNullS (Stream step ms0) =- Stream step' ms0- where- step' s = do- res <- step s- return $ case res of- Stop () -> Stop ()- Skip s' -> Skip s'- Emit s' _ -> Skip s'-{-# INLINE sinkNullS #-}--sourceNullS :: Monad m => StreamProducer m a-sourceNullS _ = Stream (\_ -> return (Stop ())) (return ())-{-# INLINE sourceNullS #-}
− Data/Conduit/Internal/Pipe.hs
@@ -1,648 +0,0 @@-{-# OPTIONS_HADDOCK not-home #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE Trustworthy #-}-{-# LANGUAGE TypeFamilies #-}-module Data.Conduit.Internal.Pipe- ( -- ** Types- Pipe (..)- -- ** Primitives- , await- , awaitE- , awaitForever- , yield- , yieldM- , yieldOr- , leftover- -- ** Finalization- , bracketP- , addCleanup- -- ** Composition- , idP- , pipe- , pipeL- , runPipe- , injectLeftovers- , (>+>)- , (<+<)- -- ** Exceptions- , catchP- , handleP- , tryP- -- ** Utilities- , transPipe- , mapOutput- , mapOutputMaybe- , mapInput- , sourceList- , withUpstream- , Data.Conduit.Internal.Pipe.enumFromTo- , generalizeUpstream- ) where--import Control.Applicative (Applicative (..))-import Control.Exception.Lifted as E (Exception, catch)-import Control.Monad ((>=>), liftM, ap)-import Control.Monad.Error.Class(MonadError(..))-import Control.Monad.Reader.Class(MonadReader(..))-import Control.Monad.RWS.Class(MonadRWS())-import Control.Monad.Writer.Class(MonadWriter(..))-import Control.Monad.State.Class(MonadState(..))-import Control.Monad.Trans.Class (MonadTrans (lift))-import Control.Monad.IO.Class (MonadIO (liftIO))-import Control.Monad.Base (MonadBase (liftBase))-import Control.Monad.Primitive (PrimMonad, PrimState, primitive)-import Data.Void (Void, absurd)-import Data.Monoid (Monoid (mappend, mempty))-import Data.Semigroup (Semigroup ((<>)))-import Control.Monad.Trans.Resource-import qualified GHC.Exts-import Control.Monad.Morph (MFunctor (..))-import qualified Control.Monad.Catch as Catch---- | The underlying datatype for all the types in this package. In has six--- type parameters:------ * /l/ is the type of values that may be left over from this @Pipe@. A @Pipe@--- with no leftovers would use @Void@ here, and one with leftovers would use--- the same type as the /i/ parameter. Leftovers are automatically provided to--- the next @Pipe@ in the monadic chain.------ * /i/ is the type of values for this @Pipe@'s input stream.------ * /o/ is the type of values for this @Pipe@'s output stream.------ * /u/ is the result type from the upstream @Pipe@.------ * /m/ is the underlying monad.------ * /r/ is the result type.------ A basic intuition is that every @Pipe@ produces a stream of output values--- (/o/), and eventually indicates that this stream is terminated by sending a--- result (/r/). On the receiving end of a @Pipe@, these become the /i/ and /u/--- parameters.------ Since 0.5.0-data Pipe l i o u m r =- -- | Provide new output to be sent downstream. This constructor has three- -- fields: the next @Pipe@ to be used, a finalization function, and the- -- output value.- HaveOutput (Pipe l i o u m r) (m ()) o- -- | Request more input from upstream. The first field takes a new input- -- value and provides a new @Pipe@. The second takes an upstream result- -- value, which indicates that upstream is producing no more results.- | NeedInput (i -> Pipe l i o u m r) (u -> Pipe l i o u m r)- -- | Processing with this @Pipe@ is complete, providing the final result.- | Done r- -- | Require running of a monadic action to get the next @Pipe@.- | PipeM (m (Pipe l i o u m r))- -- | Return leftover input, which should be provided to future operations.- | Leftover (Pipe l i o u m r) l--instance Monad m => Functor (Pipe l i o u m) where- fmap = liftM- {-# INLINE fmap #-}--instance Monad m => Applicative (Pipe l i o u m) where- pure = Done- {-# INLINE pure #-}- (<*>) = ap- {-# INLINE (<*>) #-}--instance Monad m => Monad (Pipe l i o u m) where- return = pure- {-# INLINE return #-}-- HaveOutput p c o >>= fp = HaveOutput (p >>= fp) c o- NeedInput p c >>= fp = NeedInput (p >=> fp) (c >=> fp)- Done x >>= fp = fp x- PipeM mp >>= fp = PipeM ((>>= fp) `liftM` mp)- Leftover p i >>= fp = Leftover (p >>= fp) i--instance MonadBase base m => MonadBase base (Pipe l i o u m) where- liftBase = lift . liftBase- {-# INLINE liftBase #-}--instance MonadTrans (Pipe l i o u) where- lift mr = PipeM (Done `liftM` mr)- {-# INLINE [1] lift #-}--instance MonadIO m => MonadIO (Pipe l i o u m) where- liftIO = lift . liftIO- {-# INLINE liftIO #-}--instance MonadThrow m => MonadThrow (Pipe l i o u m) where- throwM = lift . throwM- {-# INLINE throwM #-}--instance Catch.MonadCatch m => Catch.MonadCatch (Pipe l i o u m) where- catch p0 onErr =- go p0- where- go (Done r) = Done r- go (PipeM mp) = PipeM $ Catch.catch (liftM go mp) (return . onErr)- go (Leftover p i) = Leftover (go p) i- go (NeedInput x y) = NeedInput (go . x) (go . y)- go (HaveOutput p c o) = HaveOutput (go p) c o- {-# INLINE catch #-}--instance Monad m => Semigroup (Pipe l i o u m ()) where- (<>) = (>>)- {-# INLINE (<>) #-}--instance Monad m => Monoid (Pipe l i o u m ()) where- mempty = return ()- {-# INLINE mempty #-}-#if !(MIN_VERSION_base(4,11,0))- mappend = (<>)- {-# INLINE mappend #-}-#endif--instance PrimMonad m => PrimMonad (Pipe l i o u m) where- type PrimState (Pipe l i o u m) = PrimState m- primitive = lift . primitive--instance MonadResource m => MonadResource (Pipe l i o u m) where- liftResourceT = lift . liftResourceT- {-# INLINE liftResourceT #-}--instance MonadReader r m => MonadReader r (Pipe l i o u m) where- ask = lift ask- {-# INLINE ask #-}- local f (HaveOutput p c o) = HaveOutput (local f p) c o- local f (NeedInput p c) = NeedInput (\i -> local f (p i)) (\u -> local f (c u))- local _ (Done x) = Done x- local f (PipeM mp) = PipeM (liftM (local f) $ local f mp)- local f (Leftover p i) = Leftover (local f p) i---- Provided for doctest-#ifndef MIN_VERSION_mtl-#define MIN_VERSION_mtl(x, y, z) 0-#endif--instance MonadWriter w m => MonadWriter w (Pipe l i o u m) where-#if MIN_VERSION_mtl(2, 1, 0)- writer = lift . writer-#endif-- tell = lift . tell-- listen (HaveOutput p c o) = HaveOutput (listen p) c o- listen (NeedInput p c) = NeedInput (\i -> listen (p i)) (\u -> listen (c u))- listen (Done x) = Done (x,mempty)- listen (PipeM mp) =- PipeM $- do (p,w) <- listen mp- return $ do (x,w') <- listen p- return (x, w `mappend` w')- listen (Leftover p i) = Leftover (listen p) i-- pass (HaveOutput p c o) = HaveOutput (pass p) c o- pass (NeedInput p c) = NeedInput (\i -> pass (p i)) (\u -> pass (c u))- pass (PipeM mp) = PipeM $ mp >>= (return . pass)- pass (Done (x,_)) = Done x- pass (Leftover p i) = Leftover (pass p) i--instance MonadState s m => MonadState s (Pipe l i o u m) where- get = lift get- put = lift . put-#if MIN_VERSION_mtl(2, 1, 0)- state = lift . state-#endif--instance MonadRWS r w s m => MonadRWS r w s (Pipe l i o u m)--instance MonadError e m => MonadError e (Pipe l i o u m) where- throwError = lift . throwError- catchError (HaveOutput p c o) f = HaveOutput (catchError p f) c o- catchError (NeedInput p c) f = NeedInput (\i -> catchError (p i) f) (\u -> catchError (c u) f)- catchError (Done x) _ = Done x- catchError (PipeM mp) f =- PipeM $ catchError (liftM (flip catchError f) mp) (\e -> return (f e))- catchError (Leftover p i) f = Leftover (catchError p f) i---- | Wait for a single input value from upstream.------ Since 0.5.0-await :: Pipe l i o u m (Maybe i)-await = NeedInput (Done . Just) (\_ -> Done Nothing)-{-# RULES "conduit: CI.await >>= maybe" forall x y. await >>= maybe x y = NeedInput y (const x) #-}-{-# INLINE [1] await #-}---- | This is similar to @await@, but will return the upstream result value as--- @Left@ if available.------ Since 0.5.0-awaitE :: Pipe l i o u m (Either u i)-awaitE = NeedInput (Done . Right) (Done . Left)-{-# RULES "conduit: awaitE >>= either" forall x y. awaitE >>= either x y = NeedInput y x #-}-{-# INLINE [1] awaitE #-}---- | Wait for input forever, calling the given inner @Pipe@ for each piece of--- new input. Returns the upstream result type.------ Since 0.5.0-awaitForever :: Monad m => (i -> Pipe l i o r m r') -> Pipe l i o r m r-awaitForever inner =- self- where- self = awaitE >>= either return (\i -> inner i >> self)-{-# INLINE [1] awaitForever #-}---- | Send a single output value downstream. If the downstream @Pipe@--- terminates, this @Pipe@ will terminate as well.------ Since 0.5.0-yield :: Monad m- => o -- ^ output value- -> Pipe l i o u m ()-yield = HaveOutput (Done ()) (return ())-{-# INLINE [1] yield #-}--yieldM :: Monad m => m o -> Pipe l i o u m ()-yieldM = PipeM . liftM (HaveOutput (Done ()) (return ()))-{-# INLINE [1] yieldM #-}---- | Similar to @yield@, but additionally takes a finalizer to be run if the--- downstream @Pipe@ terminates.------ Since 0.5.0-yieldOr :: Monad m- => o- -> m () -- ^ finalizer- -> Pipe l i o u m ()-yieldOr o f = HaveOutput (Done ()) f o-{-# INLINE [1] yieldOr #-}--{-# RULES- "CI.yield o >> p" forall o (p :: Pipe l i o u m r). yield o >> p = HaveOutput p (return ()) o- ; "CI.yieldOr o c >> p" forall o c (p :: Pipe l i o u m r). yieldOr o c >> p = HaveOutput p c o- ; "lift m >>= CI.yield" forall m. lift m >>= yield = yieldM m- #-}- -- FIXME: Too much inlining on mapM_, can't enforce; "mapM_ CI.yield" mapM_ yield = sourceList- -- Maybe we can get a rewrite rule on foldr instead? Need a benchmark to back this up.---- | Provide a single piece of leftover input to be consumed by the next pipe--- 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 :: l -> Pipe l i o u m ()-leftover = Leftover (Done ())-{-# INLINE [1] leftover #-}-{-# RULES "conduit: leftover l >> p" forall l (p :: Pipe l i o u m r). leftover l >> p = Leftover p l #-}---- | Bracket a pipe computation between allocation and release of a--- resource. 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- -- ^ computation to run first (\"acquire resource\")- -> (a -> IO ())- -- ^ computation to run last (\"release resource\")- -> (a -> Pipe l i o u m r)- -- ^ computation to run in-between- -> Pipe l i o u m r- -- returns the value from the in-between computation-bracketP alloc free inside =- PipeM start- where- start = do- (key, seed) <- allocate alloc free- return $ addCleanup (const $ release key) (inside seed)---- | Add some code to be run when the given @Pipe@ cleans up.------ Since 0.4.1-addCleanup :: Monad m- => (Bool -> m ()) -- ^ @True@ if @Pipe@ ran to completion, @False@ for early termination.- -> Pipe l i o u m r- -> Pipe l i o u m r-addCleanup cleanup (Done r) = PipeM (cleanup True >> return (Done r))-addCleanup cleanup (HaveOutput src close x) = HaveOutput- (addCleanup cleanup src)- (cleanup False >> close)- x-addCleanup cleanup (PipeM msrc) = PipeM (liftM (addCleanup cleanup) msrc)-addCleanup cleanup (NeedInput p c) = NeedInput- (addCleanup cleanup . p)- (addCleanup cleanup . c)-addCleanup cleanup (Leftover p i) = Leftover (addCleanup cleanup p) i---- | The identity @Pipe@.------ Since 0.5.0-idP :: Monad m => Pipe l a a r m r-idP = NeedInput (HaveOutput idP (return ())) Done---- | Compose a left and right pipe together into a complete pipe. The left pipe--- will be automatically closed when the right pipe finishes.------ Since 0.5.0-pipe :: Monad m => Pipe l a b r0 m r1 -> Pipe Void b c r1 m r2 -> Pipe l a c r0 m r2-pipe =- goRight (return ())- where- goRight final left right =- case right of- HaveOutput p c o -> HaveOutput (recurse p) (c >> final) o- NeedInput rp rc -> goLeft rp rc final left- Done r2 -> PipeM (final >> return (Done r2))- PipeM mp -> PipeM (liftM recurse mp)- Leftover _ i -> absurd i- where- recurse = goRight final left-- goLeft rp rc final left =- case left of- HaveOutput left' final' o -> goRight final' left' (rp o)- NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)- Done r1 -> goRight (return ()) (Done r1) (rc r1)- PipeM mp -> PipeM (liftM recurse mp)- Leftover left' i -> Leftover (recurse left') i- where- recurse = goLeft rp rc final---- | Same as 'pipe', but automatically applies 'injectLeftovers' to the right @Pipe@.------ Since 0.5.0-pipeL :: Monad m => Pipe l a b r0 m r1 -> Pipe b b c r1 m r2 -> Pipe l a c r0 m r2--- Note: The following should be equivalent to the simpler:------ pipeL l r = l `pipe` injectLeftovers r------ However, this version tested as being significantly more efficient.-pipeL =- goRight (return ())- where- goRight final left right =- case right of- HaveOutput p c o -> HaveOutput (recurse p) (c >> final) o- NeedInput rp rc -> goLeft rp rc final left- Done r2 -> PipeM (final >> return (Done r2))- PipeM mp -> PipeM (liftM recurse mp)- Leftover right' i -> goRight final (HaveOutput left final i) right'- where- recurse = goRight final left-- goLeft rp rc final left =- case left of- HaveOutput left' final' o -> goRight final' left' (rp o)- NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)- Done r1 -> goRight (return ()) (Done r1) (rc r1)- PipeM mp -> PipeM (liftM recurse mp)- Leftover left' i -> Leftover (recurse left') i- where- recurse = goLeft rp rc final---- | Run a pipeline until processing completes.------ Since 0.5.0-runPipe :: Monad m => Pipe Void () Void () m r -> m r-runPipe (HaveOutput _ _ o) = absurd o-runPipe (NeedInput _ c) = runPipe (c ())-runPipe (Done r) = return r-runPipe (PipeM mp) = mp >>= runPipe-runPipe (Leftover _ i) = absurd i---- | Transforms a @Pipe@ that provides leftovers to one which does not,--- allowing it to be composed.------ This function will provide any leftover values within this @Pipe@ to any--- calls to @await@. If there are more leftover values than are demanded, the--- remainder are discarded.------ Since 0.5.0-injectLeftovers :: Monad m => Pipe i i o u m r -> Pipe l i o u m r-injectLeftovers =- go []- where- go ls (HaveOutput p c o) = HaveOutput (go ls p) c o- go (l:ls) (NeedInput p _) = go ls $ p l- go [] (NeedInput p c) = NeedInput (go [] . p) (go [] . c)- go _ (Done r) = Done r- go ls (PipeM mp) = PipeM (liftM (go ls) mp)- go ls (Leftover p l) = go (l:ls) p---- | Transform the monad that a @Pipe@ 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>------ This function is just a synonym for 'hoist'.------ Since 0.4.0-transPipe :: Monad m => (forall a. m a -> n a) -> Pipe l i o u m r -> Pipe l i o u n r-transPipe f (HaveOutput p c o) = HaveOutput (transPipe f p) (f c) o-transPipe f (NeedInput p c) = NeedInput (transPipe f . p) (transPipe f . c)-transPipe _ (Done r) = Done r-transPipe f (PipeM mp) =- PipeM (f $ liftM (transPipe f) $ collapse mp)- where- -- Combine a series of monadic actions into a single action. Since we- -- throw away side effects between different actions, an arbitrary break- -- between actions will lead to a violation of the monad transformer laws.- -- Example available at:- --- -- http://hpaste.org/75520- collapse mpipe = do- pipe' <- mpipe- case pipe' of- PipeM mpipe' -> collapse mpipe'- _ -> return pipe'-transPipe f (Leftover p i) = Leftover (transPipe f p) i---- | Apply a function to all the output values of a @Pipe@.------ This mimics the behavior of `fmap` for a `Source` and `Conduit` in pre-0.4--- days.------ Since 0.4.1-mapOutput :: Monad m => (o1 -> o2) -> Pipe l i o1 u m r -> Pipe l i o2 u m r-mapOutput f =- go- where- go (HaveOutput p c o) = HaveOutput (go p) c (f o)- go (NeedInput p c) = NeedInput (go . p) (go . c)- go (Done r) = Done r- go (PipeM mp) = PipeM (liftM (go) mp)- go (Leftover p i) = Leftover (go p) i-{-# INLINE mapOutput #-}---- | Same as 'mapOutput', but use a function that returns @Maybe@ values.------ Since 0.5.0-mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> Pipe l i o1 u m r -> Pipe l i o2 u m r-mapOutputMaybe f =- go- where- go (HaveOutput p c o) = maybe id (\o' p' -> HaveOutput p' c o') (f o) (go p)- go (NeedInput p c) = NeedInput (go . p) (go . c)- go (Done r) = Done r- go (PipeM mp) = PipeM (liftM (go) mp)- go (Leftover p i) = Leftover (go p) i-{-# INLINE mapOutputMaybe #-}---- | Apply a function to all the input values of a @Pipe@.------ Since 0.5.0-mapInput :: Monad m- => (i1 -> i2) -- ^ map initial input to new input- -> (l2 -> Maybe l1) -- ^ map new leftovers to initial leftovers- -> Pipe l2 i2 o u m r- -> Pipe l1 i1 o u m r-mapInput f f' (HaveOutput p c o) = HaveOutput (mapInput f f' p) c o-mapInput f f' (NeedInput p c) = NeedInput (mapInput f f' . p . f) (mapInput f f' . c)-mapInput _ _ (Done r) = Done r-mapInput f f' (PipeM mp) = PipeM (liftM (mapInput f f') mp)-mapInput f f' (Leftover p i) = maybe id (flip Leftover) (f' i) $ mapInput f f' p--enumFromTo :: (Enum o, Eq o, Monad m)- => o- -> o- -> Pipe l i o u m ()-enumFromTo start stop =- loop start- where- loop i- | i == stop = HaveOutput (Done ()) (return ()) i- | otherwise = HaveOutput (loop (succ i)) (return ()) i-{-# INLINE enumFromTo #-}---- | Convert a list into a source.------ Since 0.3.0-sourceList :: Monad m => [a] -> Pipe l i a u m ()-sourceList =- go- where- go [] = Done ()- go (o:os) = HaveOutput (go os) (return ()) o-{-# INLINE [1] sourceList #-}---- | The equivalent of @GHC.Exts.build@ for @Pipe@.------ Since 0.4.2-build :: Monad m => (forall b. (o -> b -> b) -> b -> b) -> Pipe l i o u m ()-build g = g (\o p -> HaveOutput p (return ()) o) (return ())--{-# RULES- "sourceList/build" forall (f :: (forall b. (a -> b -> b) -> b -> b)). sourceList (GHC.Exts.build f) = build f #-}---- | Returns a tuple of the upstream and downstream results. Note that this--- will force consumption of the entire input stream.------ Since 0.5.0-withUpstream :: Monad m- => Pipe l i o u m r- -> Pipe l i o u m (u, r)-withUpstream down =- down >>= go- where- go r =- loop- where- loop = awaitE >>= either (\u -> return (u, r)) (\_ -> loop)--infixr 9 <+<-infixl 9 >+>---- | Fuse together two @Pipe@s, connecting the output from the left to the--- input of the right.------ Notice that the /leftover/ parameter for the @Pipe@s must be @Void@. This--- ensures that there is no accidental data loss of leftovers during fusion. If--- you have a @Pipe@ with leftovers, you must first call 'injectLeftovers'.------ Since 0.5.0-(>+>) :: Monad m => Pipe l a b r0 m r1 -> Pipe Void b c r1 m r2 -> Pipe l a c r0 m r2-(>+>) = pipe-{-# INLINE (>+>) #-}---- | Same as '>+>', but reverse the order of the arguments.------ Since 0.5.0-(<+<) :: Monad m => Pipe Void b c r1 m r2 -> Pipe l a b r0 m r1 -> Pipe l a c r0 m r2-(<+<) = flip pipe-{-# INLINE (<+<) #-}---- | Since 1.0.4-instance MFunctor (Pipe l i o u) where- hoist = transPipe---- | See 'catchC' for more details.------ Since 1.0.11-catchP :: (MonadBaseControl IO m, Exception e)- => Pipe l i o u m r- -> (e -> Pipe l i o u m r)- -> Pipe l i o u m r-catchP p0 onErr =- go p0- where- go (Done r) = Done r- go (PipeM mp) = PipeM $ E.catch (liftM go mp) (return . onErr)- go (Leftover p i) = Leftover (go p) i- go (NeedInput x y) = NeedInput (go . x) (go . y)- go (HaveOutput p c o) = HaveOutput (go p) c o-{-# INLINABLE catchP #-}---- | The same as @flip catchP@.------ Since 1.0.11-handleP :: (MonadBaseControl IO m, Exception e)- => (e -> Pipe l i o u m r)- -> Pipe l i o u m r- -> Pipe l i o u m r-handleP = flip catchP-{-# INLINE handleP #-}---- | See 'tryC' for more details.------ Since 1.0.11-tryP :: (MonadBaseControl IO m, Exception e)- => Pipe l i o u m r- -> Pipe l i o u m (Either e r)-tryP =- go- where- go (Done r) = Done (Right r)- go (PipeM mp) = PipeM $ E.catch (liftM go mp) (return . Done . Left)- go (Leftover p i) = Leftover (go p) i- go (NeedInput x y) = NeedInput (go . x) (go . y)- go (HaveOutput p c o) = HaveOutput (go p) c o-{-# INLINABLE tryP #-}---- | Generalize the upstream return value for a @Pipe@ from unit to any type.------ Since 1.1.5-generalizeUpstream :: Monad m => Pipe l i o () m r -> Pipe l i o u m r-generalizeUpstream =- go- where- go (HaveOutput p f o) = HaveOutput (go p) f o- go (NeedInput x y) = NeedInput (go . x) (\_ -> go (y ()))- go (Done r) = Done r- go (PipeM mp) = PipeM (liftM go mp)- go (Leftover p l) = Leftover (go p) l-{-# INLINE generalizeUpstream #-}--{-# RULES "conduit: Pipe: lift x >>= f" forall m f. lift m >>= f = PipeM (liftM f m) #-}-{-# RULES "conduit: Pipe: lift x >> f" forall m f. lift m >> f = PipeM (liftM (\_ -> f) m) #-}
− Data/Conduit/Lift.hs
@@ -1,630 +0,0 @@-{-# LANGUAGE RankNTypes #-}--- | Allow monad transformers to be run\/eval\/exec in a section of conduit--- rather then needing to run across the whole conduit. The circumvents many--- of the problems with breaking the monad transformer laws. For more--- information, see the announcement blog post:--- <http://www.yesodweb.com/blog/2014/01/conduit-transformer-exception>------ This module was added in conduit 1.0.11.-module Data.Conduit.Lift (- -- * ExceptT- exceptC,- runExceptC,- catchExceptC,-- -- * ErrorT- errorC,- runErrorC,- catchErrorC,--- liftCatchError,-- -- * CatchT- runCatchC,- catchCatchC,-- -- * MaybeT- maybeC,- runMaybeC,-- -- * ReaderT- readerC,- runReaderC,-- -- * StateT, lazy- stateLC,- runStateLC,- evalStateLC,- execStateLC,-- -- ** Strict- stateC,- runStateC,- evalStateC,- execStateC,-- -- * WriterT, lazy- writerLC,- runWriterLC,- execWriterLC,-- -- ** Strict- writerC,- runWriterC,- execWriterC,-- -- * RWST, lazy- rwsLC,- runRWSLC,- evalRWSLC,- execRWSLC,-- -- ** Strict- rwsC,- runRWSC,- evalRWSC,- execRWSC,-- -- * Utilities-- distribute- ) where--import Data.Conduit-import Data.Conduit.Internal (ConduitM (..), Pipe (..))--import Control.Monad.Morph (hoist, lift, MFunctor(..), )-import Control.Monad.Trans.Class (MonadTrans(..))-import Control.Exception (SomeException)--import Data.Monoid (Monoid(..))---import qualified Control.Monad.Trans.Except as Ex-import qualified Control.Monad.Trans.Error as E-import qualified Control.Monad.Trans.Maybe as M-import qualified Control.Monad.Trans.Reader as R--import qualified Control.Monad.Trans.State.Strict as SS-import qualified Control.Monad.Trans.Writer.Strict as WS-import qualified Control.Monad.Trans.RWS.Strict as RWSS--import qualified Control.Monad.Trans.State.Lazy as SL-import qualified Control.Monad.Trans.Writer.Lazy as WL-import qualified Control.Monad.Trans.RWS.Lazy as RWSL-import Control.Monad.Catch.Pure (CatchT (runCatchT))---catAwaitLifted- :: (Monad (t (ConduitM o1 o m)), Monad m, MonadTrans t) =>- ConduitM i o1 (t (ConduitM o1 o m)) ()-catAwaitLifted = go- where- go = do- x <- lift . lift $ await- case x of- Nothing -> return ()- Just x2 -> do- yield x2- go--catYieldLifted- :: (Monad (t (ConduitM i o1 m)), Monad m, MonadTrans t) =>- ConduitM o1 o (t (ConduitM i o1 m)) ()-catYieldLifted = go- where- go = do- x <- await- case x of- Nothing -> return ()- Just x2 -> do- lift . lift $ yield x2- go---distribute- :: (Monad (t (ConduitM b o m)), Monad m, Monad (t m), MonadTrans t,- MFunctor t) =>- ConduitM b o (t m) () -> t (ConduitM b o m) ()-distribute p = catAwaitLifted =$= hoist (hoist lift) p $$ catYieldLifted---- | Wrap the base monad in 'Ex.ExceptT'------ Since 1.2.12-exceptC- :: (Monad m, Monad (t (Ex.ExceptT e m)), MonadTrans t, MFunctor t) =>- t m (Either e b) -> t (Ex.ExceptT e m) b-exceptC p = do- x <- hoist lift p- lift $ Ex.ExceptT (return x)---- | Run 'Ex.ExceptT' in the base monad------ Since 1.2.12-runExceptC- :: Monad m =>- ConduitM i o (Ex.ExceptT e m) r -> ConduitM i o m (Either e r)-runExceptC (ConduitM c0) =- ConduitM $ \rest ->- let go (Done r) = rest (Right r)- go (PipeM mp) = PipeM $ do- eres <- Ex.runExceptT mp- return $ case eres of- Left e -> rest $ Left e- Right p -> go p- go (Leftover p i) = Leftover (go p) i- go (HaveOutput p f o) = HaveOutput (go p) (Ex.runExceptT f >> return ()) o- go (NeedInput x y) = NeedInput (go . x) (go . y)- in go (c0 Done)-{-# INLINABLE runExceptC #-}---- | Catch an error in the base monad------ Since 1.2.12-catchExceptC- :: Monad m =>- ConduitM i o (Ex.ExceptT e m) r- -> (e -> ConduitM i o (Ex.ExceptT e m) r)- -> ConduitM i o (Ex.ExceptT e m) r-catchExceptC c0 h =- ConduitM $ \rest ->- let go (Done r) = rest r- go (PipeM mp) = PipeM $ do- eres <- lift $ Ex.runExceptT mp- return $ case eres of- Left e -> unConduitM (h e) rest- Right p -> go p- go (Leftover p i) = Leftover (go p) i- go (HaveOutput p f o) = HaveOutput (go p) f o- go (NeedInput x y) = NeedInput (go . x) (go . y)- in go $ unConduitM c0 Done- where-{-# INLINABLE catchExceptC #-}---- | Wrap the base monad in 'E.ErrorT'------ Since 1.0.11-errorC- :: (Monad m, Monad (t (E.ErrorT e m)), MonadTrans t, E.Error e,- MFunctor t) =>- t m (Either e b) -> t (E.ErrorT e m) b-errorC p = do- x <- hoist lift p- lift $ E.ErrorT (return x)---- | Run 'E.ErrorT' in the base monad------ Since 1.0.11-runErrorC- :: (Monad m, E.Error e) =>- ConduitM i o (E.ErrorT e m) r -> ConduitM i o m (Either e r)-runErrorC (ConduitM c0) =- ConduitM $ \rest ->- let go (Done r) = rest (Right r)- go (PipeM mp) = PipeM $ do- eres <- E.runErrorT mp- return $ case eres of- Left e -> rest $ Left e- Right p -> go p- go (Leftover p i) = Leftover (go p) i- go (HaveOutput p f o) = HaveOutput (go p) (E.runErrorT f >> return ()) o- go (NeedInput x y) = NeedInput (go . x) (go . y)- in go (c0 Done)-{-# INLINABLE runErrorC #-}---- | Catch an error in the base monad------ Since 1.0.11-catchErrorC- :: (Monad m, E.Error e) =>- ConduitM i o (E.ErrorT e m) r- -> (e -> ConduitM i o (E.ErrorT e m) r)- -> ConduitM i o (E.ErrorT e m) r-catchErrorC c0 h =- ConduitM $ \rest ->- let go (Done r) = rest r- go (PipeM mp) = PipeM $ do- eres <- lift $ E.runErrorT mp- return $ case eres of- Left e -> unConduitM (h e) rest- Right p -> go p- go (Leftover p i) = Leftover (go p) i- go (HaveOutput p f o) = HaveOutput (go p) f o- go (NeedInput x y) = NeedInput (go . x) (go . y)- in go $ unConduitM c0 Done- where-{-# INLINABLE catchErrorC #-}---- | Run 'CatchT' in the base monad------ Since 1.1.0-runCatchC- :: Monad m =>- ConduitM i o (CatchT m) r -> ConduitM i o m (Either SomeException r)-runCatchC c0 =- ConduitM $ \rest ->- let go (Done r) = rest (Right r)- go (PipeM mp) = PipeM $ do- eres <- runCatchT mp- return $ case eres of- Left e -> rest $ Left e- Right p -> go p- go (Leftover p i) = Leftover (go p) i- go (HaveOutput p f o) = HaveOutput (go p) (runCatchT f >> return ()) o- go (NeedInput x y) = NeedInput (go . x) (go . y)- in go $ unConduitM c0 Done-{-# INLINABLE runCatchC #-}---- | Catch an exception in the base monad------ Since 1.1.0-catchCatchC- :: Monad m =>- ConduitM i o (CatchT m) r- -> (SomeException -> ConduitM i o (CatchT m) r)- -> ConduitM i o (CatchT m) r-catchCatchC (ConduitM c0) h =- ConduitM $ \rest ->- let go (Done r) = rest r- go (PipeM mp) = PipeM $ do- eres <- lift $ runCatchT mp- return $ case eres of- Left e -> unConduitM (h e) rest- Right p -> go p- go (Leftover p i) = Leftover (go p) i- go (HaveOutput p f o) = HaveOutput (go p) f o- go (NeedInput x y) = NeedInput (go . x) (go . y)- in go (c0 Done)-{-# INLINABLE catchCatchC #-}---- | Wrap the base monad in 'M.MaybeT'------ Since 1.0.11-maybeC- :: (Monad m, Monad (t (M.MaybeT m)),- MonadTrans t,- MFunctor t) =>- t m (Maybe b) -> t (M.MaybeT m) b-maybeC p = do- x <- hoist lift p- lift $ M.MaybeT (return x)-{-# INLINABLE maybeC #-}---- | Run 'M.MaybeT' in the base monad------ Since 1.0.11-runMaybeC- :: Monad m =>- ConduitM i o (M.MaybeT m) r -> ConduitM i o m (Maybe r)-runMaybeC (ConduitM c0) =- ConduitM $ \rest ->- let go (Done r) = rest (Just r)- go (PipeM mp) = PipeM $ do- mres <- M.runMaybeT mp- return $ case mres of- Nothing -> rest Nothing- Just p -> go p- go (Leftover p i) = Leftover (go p) i- go (HaveOutput p c o) = HaveOutput (go p) (M.runMaybeT c >> return ()) o- go (NeedInput x y) = NeedInput (go . x) (go . y)- in go (c0 Done)-{-# INLINABLE runMaybeC #-}---- | Wrap the base monad in 'R.ReaderT'------ Since 1.0.11-readerC- :: (Monad m, Monad (t1 (R.ReaderT t m)),- MonadTrans t1,- MFunctor t1) =>- (t -> t1 m b) -> t1 (R.ReaderT t m) b-readerC k = do- i <- lift R.ask- hoist lift (k i)-{-# INLINABLE readerC #-}---- | Run 'R.ReaderT' in the base monad------ Since 1.0.11-runReaderC- :: Monad m =>- r -> ConduitM i o (R.ReaderT r m) res -> ConduitM i o m res-runReaderC r = hoist (`R.runReaderT` r)-{-# INLINABLE runReaderC #-}----- | Wrap the base monad in 'SL.StateT'------ Since 1.0.11-stateLC- :: (Monad m, Monad (t1 (SL.StateT t m)),- MonadTrans t1,- MFunctor t1) =>- (t -> t1 m (b, t)) -> t1 (SL.StateT t m) b-stateLC k = do- s <- lift SL.get- (r, s') <- hoist lift (k s)- lift (SL.put s')- return r-{-# INLINABLE stateLC #-}--thread :: Monad m- => (r -> s -> res)- -> (forall a. t m a -> s -> m (a, s))- -> s- -> ConduitM i o (t m) r- -> ConduitM i o m res-thread toRes runM s0 (ConduitM c0) =- ConduitM $ \rest ->- let go s (Done r) = rest (toRes r s)- go s (PipeM mp) = PipeM $ do- (p, s') <- runM mp s- return $ go s' p- go s (Leftover p i) = Leftover (go s p) i- go s (NeedInput x y) = NeedInput (go s . x) (go s . y)- go s (HaveOutput p f o) = HaveOutput (go s p) (runM f s >> return ()) o- in go s0 (c0 Done)-{-# INLINABLE thread #-}---- | Run 'SL.StateT' in the base monad------ Since 1.0.11-runStateLC- :: Monad m =>- s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m (r, s)-runStateLC = thread (,) SL.runStateT-{-# INLINABLE runStateLC #-}---- | Evaluate 'SL.StateT' in the base monad------ Since 1.0.11-evalStateLC- :: Monad m =>- s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m r-evalStateLC s p = fmap fst $ runStateLC s p-{-# INLINABLE evalStateLC #-}---- | Execute 'SL.StateT' in the base monad------ Since 1.0.11-execStateLC- :: Monad m =>- s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m s-execStateLC s p = fmap snd $ runStateLC s p-{-# INLINABLE execStateLC #-}----- | Wrap the base monad in 'SS.StateT'------ Since 1.0.11-stateC- :: (Monad m, Monad (t1 (SS.StateT t m)),- MonadTrans t1,- MFunctor t1) =>- (t -> t1 m (b, t)) -> t1 (SS.StateT t m) b-stateC k = do- s <- lift SS.get- (r, s') <- hoist lift (k s)- lift (SS.put s')- return r-{-# INLINABLE stateC #-}---- | Run 'SS.StateT' in the base monad------ Since 1.0.11-runStateC- :: Monad m =>- s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m (r, s)-runStateC = thread (,) SS.runStateT-{-# INLINABLE runStateC #-}---- | Evaluate 'SS.StateT' in the base monad------ Since 1.0.11-evalStateC- :: Monad m =>- s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m r-evalStateC s p = fmap fst $ runStateC s p-{-# INLINABLE evalStateC #-}---- | Execute 'SS.StateT' in the base monad------ Since 1.0.11-execStateC- :: Monad m =>- s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m s-execStateC s p = fmap snd $ runStateC s p-{-# INLINABLE execStateC #-}----- | Wrap the base monad in 'WL.WriterT'------ Since 1.0.11-writerLC- :: (Monad m, Monad (t (WL.WriterT w m)), MonadTrans t, Monoid w,- MFunctor t) =>- t m (b, w) -> t (WL.WriterT w m) b-writerLC p = do- (r, w) <- hoist lift p- lift $ WL.tell w- return r-{-# INLINABLE writerLC #-}---- | Run 'WL.WriterT' in the base monad------ Since 1.0.11-runWriterLC- :: (Monad m, Monoid w) =>- ConduitM i o (WL.WriterT w m) r -> ConduitM i o m (r, w)-runWriterLC = thread (,) run mempty- where- run m w = do- (a, w') <- WL.runWriterT m- return (a, w `mappend` w')-{-# INLINABLE runWriterLC #-}---- | Execute 'WL.WriterT' in the base monad------ Since 1.0.11-execWriterLC- :: (Monad m, Monoid w) =>- ConduitM i o (WL.WriterT w m) r -> ConduitM i o m w-execWriterLC p = fmap snd $ runWriterLC p-{-# INLINABLE execWriterLC #-}----- | Wrap the base monad in 'WS.WriterT'------ Since 1.0.11-writerC- :: (Monad m, Monad (t (WS.WriterT w m)), MonadTrans t, Monoid w,- MFunctor t) =>- t m (b, w) -> t (WS.WriterT w m) b-writerC p = do- (r, w) <- hoist lift p- lift $ WS.tell w- return r-{-# INLINABLE writerC #-}---- | Run 'WS.WriterT' in the base monad------ Since 1.0.11-runWriterC- :: (Monad m, Monoid w) =>- ConduitM i o (WS.WriterT w m) r -> ConduitM i o m (r, w)-runWriterC = thread (,) run mempty- where- run m w = do- (a, w') <- WS.runWriterT m- return (a, w `mappend` w')-{-# INLINABLE runWriterC #-}---- | Execute 'WS.WriterT' in the base monad------ Since 1.0.11-execWriterC- :: (Monad m, Monoid w) =>- ConduitM i o (WS.WriterT w m) r -> ConduitM i o m w-execWriterC p = fmap snd $ runWriterC p-{-# INLINABLE execWriterC #-}----- | Wrap the base monad in 'RWSL.RWST'------ Since 1.0.11-rwsLC- :: (Monad m, Monad (t1 (RWSL.RWST t w t2 m)), MonadTrans t1,- Monoid w, MFunctor t1) =>- (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWSL.RWST t w t2 m) b-rwsLC k = do- i <- lift RWSL.ask- s <- lift RWSL.get- (r, s', w) <- hoist lift (k i s)- lift $ do- RWSL.put s'- RWSL.tell w- return r-{-# INLINABLE rwsLC #-}---- | Run 'RWSL.RWST' in the base monad------ Since 1.0.11-runRWSLC- :: (Monad m, Monoid w) =>- r- -> s- -> ConduitM i o (RWSL.RWST r w s m) res- -> ConduitM i o m (res, s, w)-runRWSLC r s0 = thread toRes run (s0, mempty)- where- toRes a (s, w) = (a, s, w)- run m (s, w) = do- (res, s', w') <- RWSL.runRWST m r s- return (res, (s', w `mappend` w'))-{-# INLINABLE runRWSLC #-}---- | Evaluate 'RWSL.RWST' in the base monad------ Since 1.0.11-evalRWSLC- :: (Monad m, Monoid w) =>- r- -> s- -> ConduitM i o (RWSL.RWST r w s m) res- -> ConduitM i o m (res, w)-evalRWSLC i s p = fmap f $ runRWSLC i s p- where f x = let (r, _, w) = x in (r, w)-{-# INLINABLE evalRWSLC #-}---- | Execute 'RWSL.RWST' in the base monad------ Since 1.0.11-execRWSLC- :: (Monad m, Monoid w) =>- r- -> s- -> ConduitM i o (RWSL.RWST r w s m) res- -> ConduitM i o m (s, w)-execRWSLC i s p = fmap f $ runRWSLC i s p- where f x = let (_, s2, w2) = x in (s2, w2)-{-# INLINABLE execRWSLC #-}----- | Wrap the base monad in 'RWSS.RWST'------ Since 1.0.11-rwsC- :: (Monad m, Monad (t1 (RWSS.RWST t w t2 m)), MonadTrans t1,- Monoid w, MFunctor t1) =>- (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWSS.RWST t w t2 m) b-rwsC k = do- i <- lift RWSS.ask- s <- lift RWSS.get- (r, s', w) <- hoist lift (k i s)- lift $ do- RWSS.put s'- RWSS.tell w- return r-{-# INLINABLE rwsC #-}---- | Run 'RWSS.RWST' in the base monad------ Since 1.0.11-runRWSC- :: (Monad m, Monoid w) =>- r- -> s- -> ConduitM i o (RWSS.RWST r w s m) res- -> ConduitM i o m (res, s, w)-runRWSC r s0 = thread toRes run (s0, mempty)- where- toRes a (s, w) = (a, s, w)- run m (s, w) = do- (res, s', w') <- RWSS.runRWST m r s- return (res, (s', w `mappend` w'))-{-# INLINABLE runRWSC #-}---- | Evaluate 'RWSS.RWST' in the base monad------ Since 1.0.11-evalRWSC- :: (Monad m, Monoid w) =>- r- -> s- -> ConduitM i o (RWSS.RWST r w s m) res- -> ConduitM i o m (res, w)-evalRWSC i s p = fmap f $ runRWSC i s p- where f x = let (r, _, w) = x in (r, w)-{-# INLINABLE evalRWSC #-}---- | Execute 'RWSS.RWST' in the base monad------ Since 1.0.11-execRWSC- :: (Monad m, Monoid w) =>- r- -> s- -> ConduitM i o (RWSS.RWST r w s m) res- -> ConduitM i o m (s, w)-execRWSC i s p = fmap f $ runRWSC i s p- where f x = let (_, s2, w2) = x in (s2, w2)-{-# INLINABLE execRWSC #-}
− Data/Conduit/List.hs
@@ -1,837 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE Trustworthy #-}--- | Higher-level functions to interact with the elements of a stream. Most of--- these are based on list functions.------ For many purposes, it's recommended to use the conduit-combinators library,--- which provides a more complete set of functions.------ Note that these functions all deal with individual elements of a stream as a--- sort of \"black box\", where there is no introspection of the contained--- elements. Values such as @ByteString@ and @Text@ will likely need to be--- treated specially to deal with their contents properly (@Word8@ and @Char@,--- respectively). See the "Data.Conduit.Binary" and "Data.Conduit.Text"--- modules.-module Data.Conduit.List- ( -- * Sources- sourceList- , sourceNull- , unfold- , unfoldEither- , unfoldM- , unfoldEitherM- , enumFromTo- , iterate- , replicate- , replicateM- -- * Sinks- -- ** Pure- , fold- , foldMap- , take- , drop- , head- , peek- , consume- , sinkNull- -- ** Monadic- , foldMapM- , foldM- , mapM_- -- * Conduits- -- ** Pure- , map- , mapMaybe- , mapFoldable- , catMaybes- , concat- , concatMap- , concatMapAccum- , scanl- , scan- , mapAccum- , chunksOf- , groupBy- , groupOn1- , isolate- , filter- -- ** Monadic- , mapM- , iterM- , scanlM- , scanM- , mapAccumM- , mapMaybeM- , mapFoldableM- , concatMapM- , concatMapAccumM- -- * Misc- , sequence- ) where--import qualified Prelude-import Prelude- ( ($), return, (==), (-), Int- , (.), id, Maybe (..), Monad- , Either (..)- , Bool (..)- , (>>)- , (>>=)- , seq- , otherwise- , Enum, Eq- , maybe- , (<=)- , (>)- )-import Data.Monoid (Monoid, mempty, mappend)-import qualified Data.Foldable as F-import Data.Conduit-import Data.Conduit.Internal.Fusion-import Data.Conduit.Internal.List.Stream-import qualified Data.Conduit.Internal as CI-import Control.Monad (when, (<=<), liftM, void)-import Control.Monad.Trans.Class (lift)---- Defines INLINE_RULE0, INLINE_RULE, STREAMING0, and STREAMING.-#include "fusion-macros.h"---- | Generate a source from a seed value.------ Subject to fusion------ Since 0.4.2-unfold, unfoldC :: Monad m- => (b -> Maybe (a, b))- -> b- -> Producer m a-unfoldC f =- go- where- go seed =- case f seed of- Just (a, seed') -> yield a >> go seed'- Nothing -> return ()-{-# INLINE unfoldC #-}-STREAMING(unfold, unfoldC, unfoldS, f x)---- | Generate a source from a seed value with a return value.------ Subject to fusion------ @since 1.2.11-unfoldEither, unfoldEitherC :: Monad m- => (b -> Either r (a, b))- -> b- -> ConduitM i a m r-unfoldEitherC f =- go- where- go seed =- case f seed of- Right (a, seed') -> yield a >> go seed'- Left r -> return r-{-# INLINE unfoldEitherC #-}-STREAMING(unfoldEither, unfoldEitherC, unfoldEitherS, f x)---- | A monadic unfold.------ Subject to fusion------ Since 1.1.2-unfoldM, unfoldMC :: Monad m- => (b -> m (Maybe (a, b)))- -> b- -> Producer m a-unfoldMC f =- go- where- go seed = do- mres <- lift $ f seed- case mres of- Just (a, seed') -> yield a >> go seed'- Nothing -> return ()-STREAMING(unfoldM, unfoldMC, unfoldMS, f seed)---- | A monadic unfoldEither.------ Subject to fusion------ @since 1.2.11-unfoldEitherM, unfoldEitherMC :: Monad m- => (b -> m (Either r (a, b)))- -> b- -> ConduitM i a m r-unfoldEitherMC f =- go- where- go seed = do- mres <- lift $ f seed- case mres of- Right (a, seed') -> yield a >> go seed'- Left r -> return r-STREAMING(unfoldEitherM, unfoldEitherMC, unfoldEitherMS, f seed)---- | Yield the values from the list.------ Subject to fusion-sourceList, sourceListC :: Monad m => [a] -> Producer m a-sourceListC = Prelude.mapM_ yield-{-# INLINE sourceListC #-}-STREAMING(sourceList, sourceListC, sourceListS, xs)---- | Enumerate from a value to a final value, inclusive, via 'succ'.------ This is generally more efficient than using @Prelude@\'s @enumFromTo@ and--- combining with @sourceList@ since this avoids any intermediate data--- structures.------ Subject to fusion------ Since 0.4.2-enumFromTo, enumFromToC :: (Enum a, Prelude.Ord a, Monad m)- => a- -> a- -> Producer m a-enumFromToC x0 y =- loop x0- where- loop x- | x Prelude.> y = return ()- | otherwise = yield x >> loop (Prelude.succ x)-{-# INLINE enumFromToC #-}-STREAMING(enumFromTo, enumFromToC, enumFromToS, x0 y)---- | Produces an infinite stream of repeated applications of f to x.------ Subject to fusion----iterate, iterateC :: Monad m => (a -> a) -> a -> Producer m a-iterateC f =- go- where- go a = yield a >> go (f a)-{-# INLINE iterateC #-}-STREAMING(iterate, iterateC, iterateS, f a)---- | Replicate a single value the given number of times.------ Subject to fusion------ Since 1.2.0-replicate, replicateC :: Monad m => Int -> a -> Producer m a-replicateC cnt0 a =- loop cnt0- where- loop i- | i <= 0 = return ()- | otherwise = yield a >> loop (i - 1)-{-# INLINE replicateC #-}-STREAMING(replicate, replicateC, replicateS, cnt0 a)---- | Replicate a monadic value the given number of times.------ Subject to fusion------ Since 1.2.0-replicateM, replicateMC :: Monad m => Int -> m a -> Producer m a-replicateMC cnt0 ma =- loop cnt0- where- loop i- | i <= 0 = return ()- | otherwise = lift ma >>= yield >> loop (i - 1)-{-# INLINE replicateMC #-}-STREAMING(replicateM, replicateMC, replicateMS, cnt0 ma)---- | A strict left fold.------ Subject to fusion------ Since 0.3.0-fold, foldC :: Monad m- => (b -> a -> b)- -> b- -> Consumer a m b-foldC f =- loop- where- loop !accum = await >>= maybe (return accum) (loop . f accum)-{-# INLINE foldC #-}-STREAMING(fold, foldC, foldS, f accum)---- | A monadic strict left fold.------ Subject to fusion------ Since 0.3.0-foldM, foldMC :: Monad m- => (b -> a -> m b)- -> b- -> Consumer a m b-foldMC f =- loop- where- loop accum = do- await >>= maybe (return accum) go- where- go a = do- accum' <- lift $ f accum a- accum' `seq` loop accum'-{-# INLINE foldMC #-}-STREAMING(foldM, foldMC, foldMS, f accum)---------------------------------------------------------------------- These are for cases where- for whatever reason- stream fusion cannot be--- applied.-connectFold :: Monad m => Source m a -> (b -> a -> b) -> b -> m b-connectFold (CI.ConduitM src0) f =- go (src0 CI.Done)- where- go (CI.Done ()) b = return b- go (CI.HaveOutput src _ a) b = go src Prelude.$! f b a- go (CI.NeedInput _ c) b = go (c ()) b- go (CI.Leftover src ()) b = go src b- go (CI.PipeM msrc) b = do- src <- msrc- go src b-{-# INLINE connectFold #-}-{-# RULES "conduit: $$ fold" forall src f b. src $$ fold f b = connectFold src f b #-}--connectFoldM :: Monad m => Source m a -> (b -> a -> m b) -> b -> m b-connectFoldM (CI.ConduitM src0) f =- go (src0 CI.Done)- where- go (CI.Done ()) b = return b- go (CI.HaveOutput src _ a) b = do- !b' <- f b a- go src b'- go (CI.NeedInput _ c) b = go (c ()) b- go (CI.Leftover src ()) b = go src b- go (CI.PipeM msrc) b = do- src <- msrc- go src b-{-# INLINE connectFoldM #-}-{-# RULES "conduit: $$ foldM" forall src f b. src $$ foldM f b = connectFoldM src f b #-}---------------------------------------------------------------------- | A monoidal strict left fold.------ Subject to fusion------ Since 0.5.3-foldMap :: (Monad m, Monoid b)- => (a -> b)- -> Consumer a m b-INLINE_RULE(foldMap, f, let combiner accum = mappend accum . f in fold combiner mempty)---- | A monoidal strict left fold in a Monad.------ Since 1.0.8-foldMapM :: (Monad m, Monoid b)- => (a -> m b)- -> Consumer a m b-INLINE_RULE(foldMapM, f, let combiner accum = liftM (mappend accum) . f in foldM combiner mempty)---- | Apply the action to all values in the stream.------ Subject to fusion------ Since 0.3.0-mapM_, mapM_C :: Monad m- => (a -> m ())- -> Consumer a m ()-mapM_C f = awaitForever $ lift . f-{-# INLINE mapM_C #-}-STREAMING(mapM_, mapM_C, mapM_S, f)--srcMapM_ :: Monad m => Source m a -> (a -> m ()) -> m ()-srcMapM_ (CI.ConduitM src) f =- go (src CI.Done)- where- go (CI.Done ()) = return ()- go (CI.PipeM mp) = mp >>= go- go (CI.Leftover p ()) = go p- go (CI.HaveOutput p _ o) = f o >> go p- go (CI.NeedInput _ c) = go (c ())-{-# INLINE srcMapM_ #-}-{-# RULES "conduit: connect to mapM_" [2] forall f src. src $$ mapM_ f = srcMapM_ src f #-}---- | Ignore a certain number of values in the stream. This function is--- semantically equivalent to:------ > drop i = take i >> return ()------ However, @drop@ is more efficient as it does not need to hold values in--- memory.------ Subject to fusion------ Since 0.3.0-drop, dropC :: Monad m- => Int- -> Consumer a m ()-dropC =- loop- where- loop i | i <= 0 = return ()- loop count = await >>= maybe (return ()) (\_ -> loop (count - 1))-{-# INLINE dropC #-}-STREAMING(drop, dropC, dropS, i)---- | Take some values from the stream and return as a list. If you want to--- instead create a conduit that pipes data to another sink, see 'isolate'.--- This function is semantically equivalent to:------ > take i = isolate i =$ consume------ Subject to fusion------ Since 0.3.0-take, takeC :: Monad m- => Int- -> Consumer a m [a]-takeC =- loop id- where- loop front count | count <= 0 = return $ front []- loop front count = await >>= maybe- (return $ front [])- (\x -> loop (front . (x:)) (count - 1))-{-# INLINE takeC #-}-STREAMING(take, takeC, takeS, i)---- | Take a single value from the stream, if available.------ Subject to fusion------ Since 0.3.0-head, headC :: Monad m => Consumer a m (Maybe a)-headC = await-{-# INLINE headC #-}-STREAMING0(head, headC, headS)---- | Look at the next value in the stream, if available. This function will not--- change the state of the stream.------ Since 0.3.0-peek :: Monad m => Consumer a m (Maybe a)-peek = await >>= maybe (return Nothing) (\x -> leftover x >> return (Just x))---- | Apply a transformation to all values in a stream.------ Subject to fusion------ Since 0.3.0-map, mapC :: Monad m => (a -> b) -> Conduit a m b-mapC f = awaitForever $ yield . f-{-# INLINE mapC #-}-STREAMING(map, mapC, mapS, f)---- Since a Source never has any leftovers, fusion rules on it are safe.-{--{-# RULES "conduit: source/map fusion =$=" forall f src. src =$= map f = mapFuseRight src f #-}--mapFuseRight :: Monad m => Source m a -> (a -> b) -> Source m b-mapFuseRight src f = CIC.mapOutput f src-{-# INLINE mapFuseRight #-}--}--{---It might be nice to include these rewrite rules, but they may have subtle-differences based on leftovers.--{-# RULES "conduit: map-to-mapOutput pipeL" forall f src. pipeL src (map f) = mapOutput f src #-}-{-# RULES "conduit: map-to-mapOutput $=" forall f src. src $= (map f) = mapOutput f src #-}-{-# RULES "conduit: map-to-mapOutput pipe" forall f src. pipe src (map f) = mapOutput f src #-}-{-# RULES "conduit: map-to-mapOutput >+>" forall f src. src >+> (map f) = mapOutput f src #-}--{-# RULES "conduit: map-to-mapInput pipeL" forall f sink. pipeL (map f) sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}-{-# RULES "conduit: map-to-mapInput =$" forall f sink. map f =$ sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}-{-# RULES "conduit: map-to-mapInput pipe" forall f sink. pipe (map f) sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}-{-# RULES "conduit: map-to-mapInput >+>" forall f sink. map f >+> sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}--{-# RULES "conduit: map-to-mapOutput =$=" forall f con. con =$= map f = mapOutput f con #-}-{-# RULES "conduit: map-to-mapInput =$=" forall f con. map f =$= con = mapInput f (Prelude.const Prelude.Nothing) con #-}--{-# INLINE [1] map #-}---}---- | Apply a monadic transformation to all values in a stream.------ If you do not need the transformed values, and instead just want the monadic--- side-effects of running the action, see 'mapM_'.------ Subject to fusion------ Since 0.3.0-mapM, mapMC :: Monad m => (a -> m b) -> Conduit a m b-mapMC f = awaitForever $ \a -> lift (f a) >>= yield-{-# INLINE mapMC #-}-STREAMING(mapM, mapMC, mapMS, f)---- | Apply a monadic action on all values in a stream.------ This @Conduit@ can be used to perform a monadic side-effect for every--- value, whilst passing the value through the @Conduit@ as-is.------ > iterM f = mapM (\a -> f a >>= \() -> return a)------ Subject to fusion------ Since 0.5.6-iterM, iterMC :: Monad m => (a -> m ()) -> Conduit a m a-iterMC f = awaitForever $ \a -> lift (f a) >> yield a-{-# INLINE iterMC #-}-STREAMING(iterM, iterMC, iterMS, f)---- | Apply a transformation that may fail to all values in a stream, discarding--- the failures.------ Subject to fusion------ Since 0.5.1-mapMaybe, mapMaybeC :: Monad m => (a -> Maybe b) -> Conduit a m b-mapMaybeC f = awaitForever $ maybe (return ()) yield . f-{-# INLINE mapMaybeC #-}-STREAMING(mapMaybe, mapMaybeC, mapMaybeS, f)---- | Apply a monadic transformation that may fail to all values in a stream,--- discarding the failures.------ Subject to fusion------ Since 0.5.1-mapMaybeM, mapMaybeMC :: Monad m => (a -> m (Maybe b)) -> Conduit a m b-mapMaybeMC f = awaitForever $ maybe (return ()) yield <=< lift . f-{-# INLINE mapMaybeMC #-}-STREAMING(mapMaybeM, mapMaybeMC, mapMaybeMS, f)---- | Filter the @Just@ values from a stream, discarding the @Nothing@ values.------ Subject to fusion------ Since 0.5.1-catMaybes, catMaybesC :: Monad m => Conduit (Maybe a) m a-catMaybesC = awaitForever $ maybe (return ()) yield-{-# INLINE catMaybesC #-}-STREAMING0(catMaybes, catMaybesC, catMaybesS)---- | Generalization of 'catMaybes'. It puts all values from--- 'F.Foldable' into stream.------ Subject to fusion------ Since 1.0.6-concat, concatC :: (Monad m, F.Foldable f) => Conduit (f a) m a-concatC = awaitForever $ F.mapM_ yield-{-# INLINE concatC #-}-STREAMING0(concat, concatC, concatS)---- | Apply a transformation to all values in a stream, concatenating the output--- values.------ Subject to fusion------ Since 0.3.0-concatMap, concatMapC :: Monad m => (a -> [b]) -> Conduit a m b-concatMapC f = awaitForever $ sourceList . f-{-# INLINE concatMapC #-}-STREAMING(concatMap, concatMapC, concatMapS, f)---- | Apply a monadic transformation to all values in a stream, concatenating--- the output values.------ Subject to fusion------ Since 0.3.0-concatMapM, concatMapMC :: Monad m => (a -> m [b]) -> Conduit a m b-concatMapMC f = awaitForever $ sourceList <=< lift . f-{-# INLINE concatMapMC #-}-STREAMING(concatMapM, concatMapMC, concatMapMS, f)---- | 'concatMap' with a strict accumulator.------ Subject to fusion------ Since 0.3.0-concatMapAccum, concatMapAccumC :: Monad m => (a -> accum -> (accum, [b])) -> accum -> Conduit a m b-concatMapAccumC f x0 = void (mapAccum f x0) =$= concat-{-# INLINE concatMapAccumC #-}-STREAMING(concatMapAccum, concatMapAccumC, concatMapAccumS, f x0)---- | Deprecated synonym for @mapAccum@------ Since 1.0.6-scanl :: Monad m => (a -> s -> (s, b)) -> s -> Conduit a m b-scanl f s = void $ mapAccum f s-{-# DEPRECATED scanl "Use mapAccum instead" #-}---- | Deprecated synonym for @mapAccumM@------ Since 1.0.6-scanlM :: Monad m => (a -> s -> m (s, b)) -> s -> Conduit a m b-scanlM f s = void $ mapAccumM f s-{-# DEPRECATED scanlM "Use mapAccumM instead" #-}---- | Analog of @mapAccumL@ for lists. Note that in contrast to @mapAccumL@, the function argument--- takes the accumulator as its second argument, not its first argument, and the accumulated value--- is strict.------ Subject to fusion------ Since 1.1.1-mapAccum, mapAccumC :: Monad m => (a -> s -> (s, b)) -> s -> ConduitM a b m s-mapAccumC f =- loop- where- loop !s = await >>= maybe (return s) go- where- go a = case f a s of- (s', b) -> yield b >> loop s'-STREAMING(mapAccum, mapAccumC, mapAccumS, f s)---- | Monadic `mapAccum`.------ Subject to fusion------ Since 1.1.1-mapAccumM, mapAccumMC :: Monad m => (a -> s -> m (s, b)) -> s -> ConduitM a b m s-mapAccumMC f =- loop- where- loop !s = await >>= maybe (return s) go- where- go a = do (s', b) <- lift $ f a s- yield b- loop s'-{-# INLINE mapAccumMC #-}-STREAMING(mapAccumM, mapAccumMC, mapAccumMS, f s)---- | Analog of 'Prelude.scanl' for lists.------ Subject to fusion------ Since 1.1.1-scan :: Monad m => (a -> b -> b) -> b -> ConduitM a b m b-INLINE_RULE(scan, f, mapAccum (\a b -> let r = f a b in (r, r)))---- | Monadic @scanl@.------ Subject to fusion------ Since 1.1.1-scanM :: Monad m => (a -> b -> m b) -> b -> ConduitM a b m b-INLINE_RULE(scanM, f, mapAccumM (\a b -> f a b >>= \r -> return (r, r)))---- | 'concatMapM' with a strict accumulator.------ Subject to fusion------ Since 0.3.0-concatMapAccumM, concatMapAccumMC :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> Conduit a m b-concatMapAccumMC f x0 = void (mapAccumM f x0) =$= concat-{-# INLINE concatMapAccumMC #-}-STREAMING(concatMapAccumM, concatMapAccumMC, concatMapAccumMS, f x0)---- | Generalization of 'mapMaybe' and 'concatMap'. It applies function--- to all values in a stream and send values inside resulting--- 'Foldable' downstream.------ Subject to fusion------ Since 1.0.6-mapFoldable, mapFoldableC :: (Monad m, F.Foldable f) => (a -> f b) -> Conduit a m b-mapFoldableC f = awaitForever $ F.mapM_ yield . f-{-# INLINE mapFoldableC #-}-STREAMING(mapFoldable, mapFoldableC, mapFoldableS, f)---- | Monadic variant of 'mapFoldable'.------ Subject to fusion------ Since 1.0.6-mapFoldableM, mapFoldableMC :: (Monad m, F.Foldable f) => (a -> m (f b)) -> Conduit a m b-mapFoldableMC f = awaitForever $ F.mapM_ yield <=< lift . f-{-# INLINE mapFoldableMC #-}-STREAMING(mapFoldableM, mapFoldableMC, mapFoldableMS, f)---- | Consume all values from the stream and return as a list. Note that this--- will pull all values into memory.------ Subject to fusion------ Since 0.3.0-consume, consumeC :: Monad m => Consumer a m [a]-consumeC =- loop id- where- loop front = await >>= maybe (return $ front []) (\x -> loop $ front . (x:))-{-# INLINE consumeC #-}-STREAMING0(consume, consumeC, consumeS)---- | Group a stream into chunks of a given size. The last chunk may contain--- fewer than n elements.------ Subject to fusion------ Since 1.2.9-chunksOf :: Monad m => Int -> Conduit a m [a]-chunksOf n =- start- where- start = await >>= maybe (return ()) (\x -> loop n (x:))-- loop !count rest =- await >>= maybe (yield (rest [])) go- where- go y- | count > 1 = loop (count - 1) (rest . (y:))- | otherwise = yield (rest []) >> loop n (y:)---- | Grouping input according to an equality function.------ Subject to fusion------ Since 0.3.0-groupBy, groupByC :: Monad m => (a -> a -> Bool) -> Conduit a m [a]-groupByC f =- start- where- start = await >>= maybe (return ()) (loop id)-- loop rest x =- await >>= maybe (yield (x : rest [])) go- where- go y- | f x y = loop (rest . (y:)) x- | otherwise = yield (x : rest []) >> loop id y-STREAMING(groupBy, groupByC, groupByS, f)---- | 'groupOn1' is similar to @groupBy id@------ returns a pair, indicating there are always 1 or more items in the grouping.--- This is designed to be converted into a NonEmpty structure--- but it avoids a dependency on another package------ > import Data.List.NonEmpty--- >--- > groupOn1 :: (Monad m, Eq b) => (a -> b) -> Conduit a m (NonEmpty a)--- > groupOn1 f = CL.groupOn1 f =$= CL.map (uncurry (:|))------ Subject to fusion------ Since 1.1.7-groupOn1, groupOn1C :: (Monad m, Eq b)- => (a -> b)- -> Conduit a m (a, [a])-groupOn1C f =- start- where- start = await >>= maybe (return ()) (loop id)-- loop rest x =- await >>= maybe (yield (x, rest [])) go- where- go y- | f x == f y = loop (rest . (y:)) x- | otherwise = yield (x, rest []) >> loop id y-STREAMING(groupOn1, groupOn1C, groupOn1S, f)---- | Ensure that the inner sink consumes no more than the given number of--- values. Note this this does /not/ ensure that the sink consumes all of those--- values. To get the latter behavior, combine with 'sinkNull', e.g.:------ > src $$ do--- > x <- isolate count =$ do--- > x <- someSink--- > sinkNull--- > return x--- > someOtherSink--- > ...------ Subject to fusion------ Since 0.3.0-isolate, isolateC :: Monad m => Int -> Conduit a m a-isolateC =- loop- where- loop count | count <= 0 = return ()- loop count = await >>= maybe (return ()) (\x -> yield x >> loop (count - 1))-STREAMING(isolate, isolateC, isolateS, count)---- | Keep only values in the stream passing a given predicate.------ Subject to fusion------ Since 0.3.0-filter, filterC :: Monad m => (a -> Bool) -> Conduit a m a-filterC f = awaitForever $ \i -> when (f i) (yield i)-STREAMING(filter, filterC, filterS, f)--filterFuseRight :: Monad m => Source m a -> (a -> Bool) -> Source m a-filterFuseRight (CI.ConduitM src) f = CI.ConduitM $ \rest -> let- go (CI.Done ()) = rest ()- go (CI.PipeM mp) = CI.PipeM (liftM go mp)- go (CI.Leftover p i) = CI.Leftover (go p) i- go (CI.HaveOutput p c o)- | f o = CI.HaveOutput (go p) c o- | otherwise = go p- go (CI.NeedInput p c) = CI.NeedInput (go . p) (go . c)- in go (src CI.Done)--- Intermediate finalizers are dropped, but this is acceptable: the next--- yielded value would be demanded by downstream in any event, and that new--- finalizer will always override the existing finalizer.-{-# RULES "conduit: source/filter fusion =$=" forall f src. src =$= filter f = filterFuseRight src f #-}-{-# INLINE filterFuseRight #-}---- | Ignore the remainder of values in the source. Particularly useful when--- combined with 'isolate'.------ Subject to fusion------ Since 0.3.0-sinkNull, sinkNullC :: Monad m => Consumer a m ()-sinkNullC = awaitForever $ \_ -> return ()-{-# INLINE sinkNullC #-}-STREAMING0(sinkNull, sinkNullC, sinkNullS)--srcSinkNull :: Monad m => Source m a -> m ()-srcSinkNull (CI.ConduitM src) =- go (src CI.Done)- where- go (CI.Done ()) = return ()- go (CI.PipeM mp) = mp >>= go- go (CI.Leftover p ()) = go p- go (CI.HaveOutput p _ _) = go p- go (CI.NeedInput _ c) = go (c ())-{-# INLINE srcSinkNull #-}-{-# RULES "conduit: connect to sinkNull" forall src. src $$ sinkNull = srcSinkNull src #-}---- | A source that outputs no values. Note that this is just a type-restricted--- synonym for 'mempty'.------ Subject to fusion------ Since 0.3.0-sourceNull, sourceNullC :: Monad m => Producer m a-sourceNullC = return ()-{-# INLINE sourceNullC #-}-STREAMING0(sourceNull, sourceNullC, sourceNullS)---- | Run a @Pipe@ repeatedly, and output its result value downstream. Stops--- when no more input is available from upstream.------ Since 0.5.0-sequence :: Monad m- => Consumer i m o -- ^ @Pipe@ to run repeatedly- -> Conduit i m o-sequence sink =- self- where- self = awaitForever $ \i -> leftover i >> sink >>= yield
benchmarks/optimize-201408.hs view
@@ -9,16 +9,12 @@ import Control.DeepSeq import Control.Monad (foldM) import Control.Monad (when, liftM)-import Control.Monad.Codensity (lowerCodensity)-import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad.Trans.Class (lift)-import Criterion.Main+import Control.Monad.IO.Class (liftIO)+import Gauge.Main import Data.Conduit-import Data.Conduit.Internal (ConduitM (..), Pipe (..)) import qualified Data.Conduit.Internal as CI import qualified Data.Conduit.List as CL import qualified Data.Foldable as F-import Data.Functor.Identity (runIdentity) import Data.IORef import Data.List (foldl') import Data.Monoid (mempty)@@ -96,15 +92,15 @@ , TBPure "unboxed vectors" upper0 expected $ \upper -> VU.foldl' (+) 0 (VU.enumFromTo 1 upper) , TBPure "conduit, pure, fold" upper0 expected- $ \upper -> runIdentity $ CL.enumFromTo 1 upper $$ CL.fold (+) 0+ $ \upper -> runConduitPure $ CL.enumFromTo 1 upper .| CL.fold (+) 0 , TBPure "conduit, pure, foldM" upper0 expected- $ \upper -> runIdentity $ CL.enumFromTo 1 upper $$ CL.foldM plusM 0+ $ \upper -> runConduitPure $ CL.enumFromTo 1 upper .| CL.foldM plusM 0 , TBIO "conduit, IO, fold" expected $ do upper <- readIORef upperRef- CL.enumFromTo 1 upper $$ CL.fold (+) 0+ runConduit $ CL.enumFromTo 1 upper .| CL.fold (+) 0 , TBIO "conduit, IO, foldM" expected $ do upper <- readIORef upperRef- CL.enumFromTo 1 upper $$ CL.foldM plusM 0+ runConduit $ CL.enumFromTo 1 upper .| CL.foldM plusM 0 ] where upper0 = 10000 :: Int@@ -126,26 +122,11 @@ $ VU.map (+ 1) $ VU.map (* 2) $ VU.enumFromTo 1 upper- , TBPure "conduit, connect1" upper0 expected $ \upper -> runIdentity- $ CL.enumFromTo 1 upper- $$ CL.map (* 2)- =$= CL.map (+ 1)- =$= CL.fold (+) 0- , TBPure "conduit, connect2" upper0 expected $ \upper -> runIdentity- $ CL.enumFromTo 1 upper- =$= CL.map (* 2)- $$ CL.map (+ 1)- =$= CL.fold (+) 0- , TBPure "conduit, connect3" upper0 expected $ \upper -> runIdentity- $ CL.enumFromTo 1 upper- =$= CL.map (* 2)- =$= CL.map (+ 1)- $$ CL.fold (+) 0- , TBPure "conduit, inner fuse" upper0 expected $ \upper -> runIdentity+ , TBPure "conduit, connect1" upper0 expected $ \upper -> runConduitPure $ CL.enumFromTo 1 upper- =$= (CL.map (* 2)- =$= CL.map (+ 1))- $$ CL.fold (+) 0+ .| CL.map (* 2)+ .| CL.map (+ 1)+ .| CL.fold (+) 0 ] where upper0 = 10000 :: Int@@ -157,8 +138,9 @@ monteCarloTB = return $ TBGroup "monte carlo" [ TBIOTest "conduit" closeEnough $ do gen <- MWC.createSystemRandom- successes <- CL.replicateM count (MWC.uniform gen)- $$ CL.fold (\t (x, y) ->+ successes <- runConduit+ $ CL.replicateM count (MWC.uniform gen)+ .| CL.fold (\t (x, y) -> if (x*x + y*(y :: Double) < 1) then t + 1 else t)@@ -290,9 +272,10 @@ swConduitSeq window upperRef t0 f final = do upper <- readIORef upperRef - t <- CL.enumFromTo 1 upper- $= slidingWindowC window- $$ CL.fold f t0+ t <- runConduit+ $ CL.enumFromTo 1 upper+ .| slidingWindowC window+ .| CL.fold f t0 return $! final t swConduitVector :: V.Vector v Int@@ -305,19 +288,20 @@ swConduitVector window upperRef t0 f final = do upper <- readIORef upperRef - t <- CL.enumFromTo 1 upper- $= slidingVectorC window- $$ CL.fold f t0+ t <- runConduit+ $ CL.enumFromTo 1 upper+ .| slidingVectorC window+ .| CL.fold f t0 return $! final t -slidingWindowC :: Monad m => Int -> Conduit a m (Seq.Seq a)+slidingWindowC :: Monad m => Int -> ConduitT a (Seq.Seq a) m () slidingWindowC = slidingWindowCC {-# INLINE [0] slidingWindowC #-} {-# RULES "unstream slidingWindowC" forall i. slidingWindowC i = CI.unstream (CI.streamConduit (slidingWindowCC i) (slidingWindowS i)) #-} -slidingWindowCC :: Monad m => Int -> Conduit a m (Seq.Seq a)+slidingWindowCC :: Monad m => Int -> ConduitT a (Seq.Seq a) m () slidingWindowCC sz = go sz mempty where@@ -356,14 +340,14 @@ in CI.Emit (Right (s', st')) st' {-# INLINE slidingWindowS #-} -slidingVectorC :: V.Vector v a => Int -> Conduit a IO (v a)+slidingVectorC :: V.Vector v a => Int -> ConduitT a (v a) IO () slidingVectorC = slidingVectorCC {-# INLINE [0] slidingVectorC #-} {-# RULES "unstream slidingVectorC" forall i. slidingVectorC i = CI.unstream (CI.streamConduit (slidingVectorCC i) (slidingVectorS i)) #-} -slidingVectorCC :: V.Vector v a => Int -> Conduit a IO (v a)+slidingVectorCC :: V.Vector v a => Int -> ConduitT a (v a) IO () slidingVectorCC sz = do mv <- newBuf mv2 <- newBuf
benchmarks/unfused.hs view
@@ -2,12 +2,10 @@ -- Compare low-level, fused, unfused, and partially fused import Data.Conduit import qualified Data.Conduit.List as CL-import Data.Conduit.Internal (Step (..), Stream (..), unstream, StreamConduit (..))-import Criterion.Main-import Data.Functor.Identity (runIdentity)+import Gauge.Main -- | unfused-enumFromToC :: (Eq a, Monad m, Enum a) => a -> a -> Producer m a+enumFromToC :: (Eq a, Monad m, Enum a) => a -> a -> ConduitT i a m () enumFromToC x0 y = loop x0 where@@ -17,12 +15,12 @@ {-# INLINE enumFromToC #-} -- | unfused-mapC :: Monad m => (a -> b) -> Conduit a m b+mapC :: Monad m => (a -> b) -> ConduitT a b m () mapC f = awaitForever $ yield . f {-# INLINE mapC #-} -- | unfused-foldC :: Monad m => (b -> a -> b) -> b -> Consumer a m b+foldC :: Monad m => (b -> a -> b) -> b -> ConduitT a o m b foldC f = loop where@@ -37,44 +35,43 @@ | otherwise = loop (x + 1) (t + ((x * 2) + 1)) in loop 1 0 , bench "completely fused" $ flip whnf upper0 $ \upper ->- runIdentity+ runConduitPure $ CL.enumFromTo 1 upper- $$ CL.map (* 2)- =$ CL.map (+ 1)- =$ CL.fold (+) 0+ .| CL.map (* 2)+ .| CL.map (+ 1)+ .| CL.fold (+) 0 , bench "runConduit, completely fused" $ flip whnf upper0 $ \upper ->- runIdentity- $ runConduit- $ CL.enumFromTo 1 upper- =$= CL.map (* 2)- =$= CL.map (+ 1)- =$= CL.fold (+) 0+ runConduitPure+ $ CL.enumFromTo 1 upper+ .| CL.map (* 2)+ .| CL.map (+ 1)+ .| CL.fold (+) 0 , bench "completely unfused" $ flip whnf upper0 $ \upper ->- runIdentity+ runConduitPure $ enumFromToC 1 upper- $$ mapC (* 2)- =$ mapC (+ 1)- =$ foldC (+) 0+ .| mapC (* 2)+ .| mapC (+ 1)+ .| foldC (+) 0 , bench "beginning fusion" $ flip whnf upper0 $ \upper ->- runIdentity- $ (CL.enumFromTo 1 upper $= CL.map (* 2))- $$ mapC (+ 1)- =$ foldC (+) 0+ runConduitPure+ $ (CL.enumFromTo 1 upper .| CL.map (* 2))+ .| mapC (+ 1)+ .| foldC (+) 0 , bench "middle fusion" $ flip whnf upper0 $ \upper ->- runIdentity+ runConduitPure $ enumFromToC 1 upper- $$ (CL.map (* 2) =$= CL.map (+ 1))- =$ foldC (+) 0+ .| (CL.map (* 2) .| CL.map (+ 1))+ .| foldC (+) 0 , bench "ending fusion" $ flip whnf upper0 $ \upper ->- runIdentity+ runConduitPure $ enumFromToC 1 upper- $= mapC (* 2)- $$ (CL.map (+ 1) =$ CL.fold (+) 0)+ .| mapC (* 2)+ .| (CL.map (+ 1) .| CL.fold (+) 0) , bench "performance of CL.enumFromTo without fusion" $ flip whnf upper0 $ \upper ->- runIdentity+ runConduitPure $ CL.enumFromTo 1 upper- $= mapC (* 2)- $$ (CL.map (+ 1) =$ CL.fold (+) 0)+ .| mapC (* 2)+ .| (CL.map (+ 1) .| CL.fold (+) 0) ] where upper0 = 100000 :: Int
conduit.cabal view
@@ -1,5 +1,5 @@ Name: conduit-Version: 1.2.13.1+Version: 1.3.0 Synopsis: Streaming data processing library. description: `conduit` is a solution to the streaming data problem, allowing for production,@@ -20,42 +20,60 @@ Cabal-version: >=1.8 Homepage: http://github.com/snoyberg/conduit extra-source-files: test/main.hs+ , test/doctests.hs+ , test/subdir/dummyfile.txt , README.md , ChangeLog.md , fusion-macros.h Library+ hs-source-dirs: src Exposed-modules: Data.Conduit+ Data.Conduit.Combinators Data.Conduit.List Data.Conduit.Internal Data.Conduit.Lift Data.Conduit.Internal.Fusion Data.Conduit.Internal.List.Stream+ Data.Conduit.Combinators.Stream+ Conduit other-modules: Data.Conduit.Internal.Pipe Data.Conduit.Internal.Conduit- Build-depends: base >= 4.5 && < 5- , resourcet >= 1.1 && < 1.2- , exceptions >= 0.6- , lifted-base >= 0.1- , transformers-base >= 0.4.1 && < 0.5- , transformers >= 0.2.2- , transformers-compat >= 0.3+ Data.Conduit.Combinators.Unqualified+ Data.Streaming.FileRead+ Data.Streaming.Filesystem+ Build-depends: base >= 4.9 && < 5+ , resourcet >= 1.2 && < 1.3+ , transformers >= 0.4 , mtl- , mmorph- , monad-control , primitive- if !impl(ghc>=7.9)- build-depends: void >= 0.5.5- if !impl(ghc>=7.11)- build-depends: semigroups >= 0.16+ , unliftio-core+ , exceptions+ , mono-traversable >= 1.0.7+ , vector+ , bytestring+ , text+ , filepath+ , directory++ if os(windows)+ build-depends: Win32+ , filepath+ other-modules: System.Win32File+ cpp-options: -DWINDOWS+ else+ build-depends: unix+ ghc-options: -Wall include-dirs: . -test-suite test+test-suite conduit-test hs-source-dirs: test main-is: main.hs other-modules: Data.Conduit.Extra.ZipConduitSpec , Data.Conduit.StreamSpec+ , Spec+ , StreamSpec type: exitcode-stdio-1.0 cpp-options: -DTEST build-depends: conduit@@ -69,10 +87,14 @@ , exceptions >= 0.6 , safe , split >= 0.2.0.0- if !impl(ghc>=7.9)- build-depends: void- if !impl(ghc>=7.11)- build-depends: semigroups >= 0.16+ , mono-traversable+ , text+ , vector+ , directory+ , bytestring+ , silently+ , filepath+ , unliftio >= 0.2.4.0 ghc-options: -Wall --test-suite doctests@@ -104,7 +126,7 @@ , transformers , hspec , mwc-random- , criterion+ , gauge , kan-extensions main-is: optimize-201408.hs ghc-options: -Wall -O2 -rtsopts@@ -114,7 +136,7 @@ hs-source-dirs: benchmarks build-depends: base , conduit- , criterion+ , gauge , transformers main-is: unfused.hs ghc-options: -Wall -O2 -rtsopts
+ src/Conduit.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}+-- | Your intended one-stop-shop for conduit functionality.+-- This re-exports functions from many commonly used modules.+-- When there is a conflict with standard functions, functions+-- in this module are disambiguated by adding a trailing C+-- (or for chunked functions, replacing a trailing E with CE).+-- This means that the Conduit module can be imported unqualified+-- without causing naming conflicts.+--+-- For more information on the naming scheme and intended usages of the+-- combinators, please see the "Data.Conduit.Combinators" documentation.+module Conduit+ ( -- * Core conduit library+ module Data.Conduit+ , module Data.Conduit.Lift+ -- * Commonly used combinators+ , module Data.Conduit.Combinators.Unqualified+ -- * Monadic lifting+ , MonadIO (..)+ , MonadTrans (..)+ , MonadThrow (..)+ , MonadUnliftIO (..)+ , PrimMonad (..)+ -- * ResourceT+ , MonadResource+ , ResourceT+ , runResourceT+ -- * Acquire+ , module Data.Acquire+ -- * Pure pipelines+ , Identity (..)+ ) where++import Data.Conduit+import Control.Monad.IO.Unlift (MonadIO (..), MonadUnliftIO (..))+import Control.Monad.Trans.Class (MonadTrans (..))+import Control.Monad.Primitive (PrimMonad (..), PrimState)+import Data.Conduit.Lift+import Data.Conduit.Combinators.Unqualified+import Data.Functor.Identity (Identity (..))+import Control.Monad.Trans.Resource (MonadResource, MonadThrow (..), runResourceT, ResourceT)+import Data.Acquire hiding (with)
+ src/Data/Conduit.hs view
@@ -0,0 +1,126 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleContexts #-}+-- | If this is your first time with conduit, you should probably start with+-- the tutorial:+-- <https://github.com/snoyberg/conduit#readme>.+module Data.Conduit+ ( -- * Core interface+ -- ** Types+ ConduitT+ -- *** Deprecated+ , Source+ , Conduit+ , Sink+ , ConduitM+ -- ** Connect/fuse operators+ , (.|)+ , connect+ , fuse+ -- *** Deprecated+ , ($$)+ , ($=)+ , (=$)+ , (=$=)++ -- *** Fuse with upstream results+ , fuseBoth+ , fuseBothMaybe+ , fuseUpstream++ -- ** Primitives+ , await+ , yield+ , yieldM+ , leftover+ , runConduit+ , runConduitPure+ , runConduitRes++ -- ** Finalization+ , bracketP++ -- ** Exception handling+ , catchC+ , handleC+ , tryC++ -- * Generalized conduit types+ , Producer+ , Consumer+ , toProducer+ , toConsumer++ -- * Utility functions+ , awaitForever+ , transPipe+ , mapOutput+ , mapOutputMaybe+ , mapInput+ , mergeSource+ , passthroughSink+ , sourceToList++ -- * Connect-and-resume+ , SealedConduitT+ , sealConduitT+ , unsealConduitT+ , ($$+)+ , ($$++)+ , ($$+-)+ , ($=+)++ -- ** For @Conduit@s+ , (=$$+)+ , (=$$++)+ , (=$$+-)++ -- * Fusion with leftovers+ , fuseLeftovers+ , fuseReturnLeftovers++ -- * Flushing+ , Flush (..)++ -- * Newtype wrappers+ -- ** ZipSource+ , ZipSource (..)+ , sequenceSources++ -- ** ZipSink+ , ZipSink (..)+ , sequenceSinks++ -- ** ZipConduit+ , ZipConduit (..)+ , sequenceConduits++ -- * Convenience reexports+ , Void -- FIXME consider instead relaxing type of runConduit+ ) where++import Data.Conduit.Internal.Conduit+import Data.Void (Void)+import Data.Functor.Identity (Identity, runIdentity)+import Control.Monad.Trans.Resource (ResourceT, runResourceT)+import Control.Monad.IO.Unlift (MonadUnliftIO)++-- | Run a pure pipeline until processing completes, i.e. a pipeline+-- with @Identity@ as the base monad. This is equivalient to+-- @runIdentity . runConduit@.+--+-- @since 1.2.8+runConduitPure :: ConduitT () Void Identity r -> r+runConduitPure = runIdentity . runConduit+{-# INLINE runConduitPure #-}++-- | Run a pipeline which acquires resources with @ResourceT@, and+-- then run the @ResourceT@ transformer. This is equivalent to+-- @runResourceT . runConduit@.+--+-- @since 1.2.8+runConduitRes :: MonadUnliftIO m+ => ConduitT () Void (ResourceT m) r+ -> m r+runConduitRes = runResourceT . runConduit+{-# INLINE runConduitRes #-}
+ src/Data/Conduit/Combinators.hs view
@@ -0,0 +1,2542 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE BangPatterns #-}+-- | This module is meant as a replacement for Data.Conduit.List.+-- That module follows a naming scheme which was originally inspired+-- by its enumerator roots. This module is meant to introduce a naming+-- scheme which encourages conduit best practices.+--+-- There are two versions of functions in this module. Those with a trailing+-- E work in the individual elements of a chunk of data, e.g., the bytes of+-- a ByteString, the Chars of a Text, or the Ints of a Vector Int. Those+-- without a trailing E work on unchunked streams.+--+-- FIXME: discuss overall naming, usage of mono-traversable, etc+--+-- Mention take (Conduit) vs drop (Consumer)+module Data.Conduit.Combinators+ ( -- * Producers+ -- ** Pure+ yieldMany+ , unfold+ , enumFromTo+ , iterate+ , repeat+ , replicate+ , sourceLazy++ -- ** Monadic+ , repeatM+ , repeatWhileM+ , replicateM++ -- ** I\/O+ , sourceFile+ , sourceFileBS+ , sourceHandle+ , sourceHandleUnsafe+ , sourceIOHandle+ , stdin+ , withSourceFile++ -- ** Filesystem+ , sourceDirectory+ , sourceDirectoryDeep++ -- * Consumers+ -- ** Pure+ , drop+ , dropE+ , dropWhile+ , dropWhileE+ , fold+ , foldE+ , foldl+ , foldl1+ , foldlE+ , foldMap+ , foldMapE+ , all+ , allE+ , any+ , anyE+ , and+ , andE+ , or+ , orE+ , asum+ , elem+ , elemE+ , notElem+ , notElemE+ , sinkLazy+ , sinkList+ , sinkVector+ , sinkVectorN+ , sinkLazyBuilder+ , sinkNull+ , awaitNonNull+ , head+ , headDef+ , headE+ , peek+ , peekE+ , last+ , lastDef+ , lastE+ , length+ , lengthE+ , lengthIf+ , lengthIfE+ , maximum+ , maximumE+ , minimum+ , minimumE+ , null+ , nullE+ , sum+ , sumE+ , product+ , productE+ , find++ -- ** Monadic+ , mapM_+ , mapM_E+ , foldM+ , foldME+ , foldMapM+ , foldMapME++ -- ** I\/O+ , sinkFile+ , sinkFileCautious+ , sinkTempFile+ , sinkSystemTempFile+ , sinkFileBS+ , sinkHandle+ , sinkIOHandle+ , print+ , stdout+ , stderr+ , withSinkFile+ , withSinkFileBuilder+ , withSinkFileCautious+ , sinkHandleBuilder+ , sinkHandleFlush++ -- * Transformers+ -- ** Pure+ , map+ , mapE+ , omapE+ , concatMap+ , concatMapE+ , take+ , takeE+ , takeWhile+ , takeWhileE+ , takeExactly+ , takeExactlyE+ , concat+ , filter+ , filterE+ , mapWhile+ , conduitVector+ , scanl+ , mapAccumWhile+ , concatMapAccum+ , intersperse+ , slidingWindow+ , chunksOfE+ , chunksOfExactlyE++ -- ** Monadic+ , mapM+ , mapME+ , omapME+ , concatMapM+ , filterM+ , filterME+ , iterM+ , scanlM+ , mapAccumWhileM+ , concatMapAccumM++ -- ** Textual+ , encodeUtf8+ , decodeUtf8+ , decodeUtf8Lenient+ , line+ , lineAscii+ , unlines+ , unlinesAscii+ , takeExactlyUntilE+ , linesUnbounded+ , linesUnboundedAscii+ , splitOnUnboundedE++ -- ** Builders+ , builderToByteString+ , unsafeBuilderToByteString+ , builderToByteStringWith+ , builderToByteStringFlush+ , builderToByteStringWithFlush+ , BufferAllocStrategy+ , allNewBuffersStrategy+ , reuseBufferStrategy++ -- * Special+ , vectorBuilder+ , mapAccumS+ , peekForever+ , peekForeverE+ ) where++-- BEGIN IMPORTS++import Data.ByteString.Builder (Builder, toLazyByteString, hPutBuilder)+import qualified Data.ByteString.Builder.Internal as BB (flush)+import qualified Data.ByteString.Builder.Extra as BB (runBuilder, Next(Done, More, Chunk))+import qualified Data.NonNull as NonNull+import qualified Data.Traversable+import qualified Data.ByteString as S+import qualified Data.ByteString.Lazy as BL+import Data.ByteString.Lazy.Internal (defaultChunkSize)+import Control.Applicative (Alternative(..), (<$>))+import Control.Exception (catch, throwIO, finally, bracket, try, evaluate)+import Control.Category (Category (..))+import Control.Monad (unless, when, (>=>), liftM, forever)+import Control.Monad.IO.Unlift (MonadIO (..), MonadUnliftIO, withRunInIO)+import Control.Monad.Primitive (PrimMonad, PrimState, unsafePrimToPrim)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Resource (MonadResource, MonadThrow, allocate, throwM)+import Data.Conduit+import Data.Conduit.Internal (ConduitT (..), Pipe (..))+import qualified Data.Conduit.List as CL+import Data.IORef+import Data.Maybe (fromMaybe, isNothing, isJust)+import Data.Monoid (Monoid (..))+import Data.MonoTraversable+import qualified Data.Sequences as Seq+import qualified Data.Vector.Generic as V+import qualified Data.Vector.Generic.Mutable as VM+import Data.Void (absurd)+import Prelude (Bool (..), Eq (..), Int,+ Maybe (..), Either (..), Monad (..), Num (..),+ Ord (..), fromIntegral, maybe, either,+ ($), Functor (..), Enum, seq, Show, Char,+ otherwise, Either (..), not,+ ($!), succ, FilePath, IO, String)+import Data.Word (Word8)+import qualified Prelude+import qualified System.IO as IO+import System.IO.Error (isDoesNotExistError)+import System.IO.Unsafe (unsafePerformIO)+import Data.ByteString (ByteString)+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Text.Encoding.Error as TEE+import Data.Conduit.Combinators.Stream+import Data.Conduit.Internal.Fusion+import Data.Primitive.MutVar (MutVar, newMutVar, readMutVar,+ writeMutVar)+import qualified Data.Streaming.FileRead as FR+import qualified Data.Streaming.Filesystem as F+import GHC.ForeignPtr (mallocPlainForeignPtrBytes, unsafeForeignPtrToPtr)+import Foreign.ForeignPtr (touchForeignPtr, ForeignPtr)+import Foreign.Ptr (Ptr, plusPtr, minusPtr)+import Data.ByteString.Internal (ByteString (PS), mallocByteString)+import System.FilePath ((</>), (<.>), takeDirectory, takeFileName)+import System.Directory (renameFile, getTemporaryDirectory, removeFile)++import qualified Data.Sequences as DTE+import Data.Sequences (LazySequence (..))++-- Defines INLINE_RULE0, INLINE_RULE, STREAMING0, and STREAMING.+#include "fusion-macros.h"++-- END IMPORTS++-- TODO:+--+-- * The functions sourceRandom* are based on, initReplicate and+-- initRepeat have specialized versions for when they're used with+-- ($$). How does this interact with stream fusion?+--+-- * Is it possible to implement fusion for vectorBuilder? Since it+-- takes a Sink yielding function as an input, the rewrite rule+-- would need to trigger when that parameter looks something like+-- (\x -> unstream (...)). I don't see anything preventing doing+-- this, but it would be quite a bit of code.++-- NOTE: Fusion isn't possible for the following operations:+--+-- * Due to a lack of leftovers:+-- - dropE, dropWhile, dropWhileE+-- - headE+-- - peek, peekE+-- - null, nullE+-- - takeE, takeWhile, takeWhileE+-- - mapWhile+-- - codeWith+-- - line+-- - lineAscii+--+-- * Due to a use of leftover in a dependency:+-- - Due to "codeWith": encodeBase64, decodeBase64, encodeBase64URL, decodeBase64URL, decodeBase16+-- - due to "CT.decode": decodeUtf8, decodeUtf8Lenient+--+-- * Due to lack of resource cleanup (e.g. bracketP):+-- - sourceDirectory+-- - sourceDirectoryDeep+-- - sourceFile+--+-- * takeExactly / takeExactlyE - no monadic bind. Another way to+-- look at this is that subsequent streams drive stream evaluation,+-- so there's no way for the conduit to guarantee a certain amount+-- of demand from the upstream.++-- | Yield each of the values contained by the given @MonoFoldable@.+--+-- This will work on many data structures, including lists, @ByteString@s, and @Vector@s.+--+-- Subject to fusion+--+-- @since 1.3.0+yieldMany, yieldManyC :: (Monad m, MonoFoldable mono)+ => mono+ -> ConduitT i (Element mono) m ()+yieldManyC = ofoldMap yield+{-# INLINE yieldManyC #-}+STREAMING(yieldMany, yieldManyC, yieldManyS, x)++-- | Generate a producer from a seed value.+--+-- Subject to fusion+--+-- @since 1.3.0+unfold :: Monad m+ => (b -> Maybe (a, b))+ -> b+ -> ConduitT i a m ()+INLINE_RULE(unfold, f x, CL.unfold f x)++-- | Enumerate from a value to a final value, inclusive, via 'succ'.+--+-- This is generally more efficient than using @Prelude@\'s @enumFromTo@ and+-- combining with @sourceList@ since this avoids any intermediate data+-- structures.+--+-- Subject to fusion+--+-- @since 1.3.0+enumFromTo :: (Monad m, Enum a, Ord a) => a -> a -> ConduitT i a m ()+INLINE_RULE(enumFromTo, f t, CL.enumFromTo f t)++-- | Produces an infinite stream of repeated applications of f to x.+--+-- Subject to fusion+--+-- @since 1.3.0+iterate :: Monad m => (a -> a) -> a -> ConduitT i a m ()+INLINE_RULE(iterate, f t, CL.iterate f t)++-- | Produce an infinite stream consisting entirely of the given value.+--+-- Subject to fusion+--+-- @since 1.3.0+repeat :: Monad m => a -> ConduitT i a m ()+INLINE_RULE(repeat, x, iterate id x)++-- | Produce a finite stream consisting of n copies of the given value.+--+-- Subject to fusion+--+-- @since 1.3.0+replicate :: Monad m+ => Int+ -> a+ -> ConduitT i a m ()+INLINE_RULE(replicate, n x, CL.replicate n x)++-- | Generate a producer by yielding each of the strict chunks in a @LazySequence@.+--+-- For more information, see 'toChunks'.+--+-- Subject to fusion+--+-- @since 1.3.0+sourceLazy :: (Monad m, LazySequence lazy strict)+ => lazy+ -> ConduitT i strict m ()+INLINE_RULE(sourceLazy, x, yieldMany (toChunks x))++-- | Repeatedly run the given action and yield all values it produces.+--+-- Subject to fusion+--+-- @since 1.3.0+repeatM, repeatMC :: Monad m+ => m a+ -> ConduitT i a m ()+repeatMC m = forever $ lift m >>= yield+{-# INLINE repeatMC #-}+STREAMING(repeatM, repeatMC, repeatMS, m)++-- | Repeatedly run the given action and yield all values it produces, until+-- the provided predicate returns @False@.+--+-- Subject to fusion+--+-- @since 1.3.0+repeatWhileM, repeatWhileMC :: Monad m+ => m a+ -> (a -> Bool)+ -> ConduitT i a m ()+repeatWhileMC m f =+ loop+ where+ loop = do+ x <- lift m+ when (f x) $ yield x >> loop+STREAMING(repeatWhileM, repeatWhileMC, repeatWhileMS, m f)++-- | Perform the given action n times, yielding each result.+--+-- Subject to fusion+--+-- @since 1.3.0+replicateM :: Monad m+ => Int+ -> m a+ -> ConduitT i a m ()+INLINE_RULE(replicateM, n m, CL.replicateM n m)++-- | Stream the contents of a file as binary data.+--+-- @since 1.3.0+sourceFile :: MonadResource m+ => FilePath+ -> ConduitT i S.ByteString m ()+sourceFile fp =+ bracketP+ (FR.openFile fp)+ FR.closeFile+ loop+ where+ loop h = do+ bs <- liftIO $ FR.readChunk h+ unless (S.null bs) $ do+ yield bs+ loop h++-- | Stream the contents of a 'IO.Handle' as binary data. Note that this+-- function will /not/ automatically close the @Handle@ when processing+-- completes, since it did not acquire the @Handle@ in the first place.+--+-- @since 1.3.0+sourceHandle :: MonadIO m+ => IO.Handle+ -> ConduitT i S.ByteString m ()+sourceHandle h =+ loop+ where+ loop = do+ bs <- liftIO (S.hGetSome h defaultChunkSize)+ if S.null bs+ then return ()+ else yield bs >> loop++-- | Same as @sourceHandle@, but instead of allocating a new buffer for each+-- incoming chunk of data, reuses the same buffer. Therefore, the @ByteString@s+-- yielded by this function are not referentially transparent between two+-- different @yield@s.+--+-- This function will be slightly more efficient than @sourceHandle@ by+-- avoiding allocations and reducing garbage collections, but should only be+-- used if you can guarantee that you do not reuse a @ByteString@ (or any slice+-- thereof) between two calls to @await@.+--+-- @since 1.3.0+sourceHandleUnsafe :: MonadIO m => IO.Handle -> ConduitT i ByteString m ()+sourceHandleUnsafe handle = do+ fptr <- liftIO $ mallocPlainForeignPtrBytes defaultChunkSize+ let ptr = unsafeForeignPtrToPtr fptr+ loop = do+ count <- liftIO $ IO.hGetBuf handle ptr defaultChunkSize+ when (count > 0) $ do+ yield (PS fptr 0 count)+ loop++ loop++ liftIO $ touchForeignPtr fptr++-- | An alternative to 'sourceHandle'.+-- Instead of taking a pre-opened 'IO.Handle', it takes an action that opens+-- a 'IO.Handle' (in read mode), so that it can open it only when needed+-- and close it as soon as possible.+--+-- @since 1.3.0+sourceIOHandle :: MonadResource m+ => IO IO.Handle+ -> ConduitT i S.ByteString m ()+sourceIOHandle alloc = bracketP alloc IO.hClose sourceHandle++-- | 'sourceFile' specialized to 'ByteString' to help with type+-- inference.+--+-- @since 1.3.0+sourceFileBS :: MonadResource m => FilePath -> ConduitT i ByteString m ()+sourceFileBS = sourceFile+{-# INLINE sourceFileBS #-}++-- | @sourceHandle@ applied to @stdin@.+--+-- Subject to fusion+--+-- @since 1.3.0+stdin :: MonadIO m => ConduitT i ByteString m ()+INLINE_RULE0(stdin, sourceHandle IO.stdin)++-- | Stream all incoming data to the given file.+--+-- @since 1.3.0+sinkFile :: MonadResource m+ => FilePath+ -> ConduitT S.ByteString o m ()+sinkFile fp = sinkIOHandle (IO.openBinaryFile fp IO.WriteMode)++-- | Cautious version of 'sinkFile'. The idea here is to stream the+-- values to a temporary file in the same directory of the destination+-- file, and only on successfully writing the entire file, moves it+-- atomically to the destination path.+--+-- In the event of an exception occurring, the temporary file will be+-- deleted and no move will be made. If the application shuts down+-- without running exception handling (such as machine failure or a+-- SIGKILL), the temporary file will remain and the destination file+-- will be untouched.+--+-- @since 1.3.0+sinkFileCautious+ :: MonadResource m+ => FilePath+ -> ConduitM S.ByteString o m ()+sinkFileCautious fp =+ bracketP (cautiousAcquire fp) cautiousCleanup inner+ where+ inner (tmpFP, h) = do+ sinkHandle h+ liftIO $ do+ IO.hClose h+ renameFile tmpFP fp++-- | Like 'sinkFileCautious', but uses the @with@ pattern instead of+-- @MonadResource@.+--+-- @since 1.3.0+withSinkFileCautious+ :: (MonadUnliftIO m, MonadIO n)+ => FilePath+ -> (ConduitM S.ByteString o n () -> m a)+ -> m a+withSinkFileCautious fp inner =+ withRunInIO $ \run -> bracket+ (cautiousAcquire fp)+ cautiousCleanup+ (\(tmpFP, h) -> do+ a <- run $ inner $ sinkHandle h+ IO.hClose h+ renameFile tmpFP fp+ return a)++-- | Helper function for Cautious functions above, do not export!+cautiousAcquire :: FilePath -> IO (FilePath, IO.Handle)+cautiousAcquire fp = IO.openBinaryTempFile (takeDirectory fp) (takeFileName fp <.> "tmp")++-- | Helper function for Cautious functions above, do not export!+cautiousCleanup :: (FilePath, IO.Handle) -> IO ()+cautiousCleanup (tmpFP, h) = do+ IO.hClose h+ removeFile tmpFP `Control.Exception.catch` \e ->+ if isDoesNotExistError e+ then return ()+ else throwIO e++-- | Stream data into a temporary file in the given directory with the+-- given filename pattern, and return the temporary filename. The+-- temporary file will be automatically deleted when exiting the+-- active 'ResourceT' block, if it still exists.+--+-- @since 1.3.0+sinkTempFile :: MonadResource m+ => FilePath -- ^ temp directory+ -> String -- ^ filename pattern+ -> ConduitM ByteString o m FilePath+sinkTempFile tmpdir pattern = do+ (_releaseKey, (fp, h)) <- allocate+ (IO.openBinaryTempFile tmpdir pattern)+ (\(fp, h) -> IO.hClose h `finally` (removeFile fp `Control.Exception.catch` \e ->+ if isDoesNotExistError e+ then return ()+ else throwIO e))+ sinkHandle h+ liftIO $ IO.hClose h+ return fp++-- | Same as 'sinkTempFile', but will use the default temp file+-- directory for the system as the first argument.+--+-- @since 1.3.0+sinkSystemTempFile+ :: MonadResource m+ => String -- ^ filename pattern+ -> ConduitM ByteString o m FilePath+sinkSystemTempFile pattern = do+ dir <- liftIO getTemporaryDirectory+ sinkTempFile dir pattern++-- | Stream all incoming data to the given 'IO.Handle'. Note that this function+-- does /not/ flush and will /not/ close the @Handle@ when processing completes.+--+-- @since 1.3.0+sinkHandle :: MonadIO m+ => IO.Handle+ -> ConduitT S.ByteString o m ()+sinkHandle h = awaitForever (liftIO . S.hPut h)++-- | Stream incoming builders, executing them directly on the buffer of the+-- given 'IO.Handle'. Note that this function does /not/ automatically close the+-- @Handle@ when processing completes.+-- Pass 'Data.ByteString.Builder.Extra.flush' to flush the buffer.+--+-- @since 1.3.0+sinkHandleBuilder :: MonadIO m => IO.Handle -> ConduitM Builder o m ()+sinkHandleBuilder h = awaitForever (liftIO . hPutBuilder h)++-- | Stream incoming @Flush@es, executing them on @IO.Handle@+-- Note that this function does /not/ automatically close the @Handle@ when+-- processing completes+--+-- @since 1.3.0+sinkHandleFlush :: MonadIO m+ => IO.Handle+ -> ConduitM (Flush S.ByteString) o m ()+sinkHandleFlush h =+ awaitForever $ \mbs -> liftIO $+ case mbs of+ Chunk bs -> S.hPut h bs+ Flush -> IO.hFlush h++-- | An alternative to 'sinkHandle'.+-- Instead of taking a pre-opened 'IO.Handle', it takes an action that opens+-- a 'IO.Handle' (in write mode), so that it can open it only when needed+-- and close it as soon as possible.+--+-- @since 1.3.0+sinkIOHandle :: MonadResource m+ => IO IO.Handle+ -> ConduitT S.ByteString o m ()+sinkIOHandle alloc = bracketP alloc IO.hClose sinkHandle++-- | Like 'IO.withBinaryFile', but provides a source to read bytes from.+--+-- @since 1.3.0+withSourceFile+ :: (MonadUnliftIO m, MonadIO n)+ => FilePath+ -> (ConduitM i ByteString n () -> m a)+ -> m a+withSourceFile fp inner =+ withRunInIO $ \run ->+ IO.withBinaryFile fp IO.ReadMode $+ run . inner . sourceHandle++-- | Like 'IO.withBinaryFile', but provides a sink to write bytes to.+--+-- @since 1.3.0+withSinkFile+ :: (MonadUnliftIO m, MonadIO n)+ => FilePath+ -> (ConduitM ByteString o n () -> m a)+ -> m a+withSinkFile fp inner =+ withRunInIO $ \run ->+ IO.withBinaryFile fp IO.ReadMode $+ run . inner . sinkHandle++-- | Same as 'withSinkFile', but lets you use a 'BB.Builder'.+--+-- @since 1.3.0+withSinkFileBuilder+ :: (MonadUnliftIO m, MonadIO n)+ => FilePath+ -> (ConduitM Builder o n () -> m a)+ -> m a+withSinkFileBuilder fp inner =+ withRunInIO $ \run ->+ IO.withBinaryFile fp IO.WriteMode $ \h ->+ run $ inner $ CL.mapM_ (liftIO . hPutBuilder h)++-- | Stream the contents of the given directory, without traversing deeply.+--+-- This function will return /all/ of the contents of the directory, whether+-- they be files, directories, etc.+--+-- Note that the generated filepaths will be the complete path, not just the+-- filename. In other words, if you have a directory @foo@ containing files+-- @bar@ and @baz@, and you use @sourceDirectory@ on @foo@, the results will be+-- @foo/bar@ and @foo/baz@.+--+-- @since 1.3.0+sourceDirectory :: MonadResource m => FilePath -> ConduitT i FilePath m ()+sourceDirectory dir =+ bracketP (F.openDirStream dir) F.closeDirStream go+ where+ go ds =+ loop+ where+ loop = do+ mfp <- liftIO $ F.readDirStream ds+ case mfp of+ Nothing -> return ()+ Just fp -> do+ yield $ dir </> fp+ loop++-- | Deeply stream the contents of the given directory.+--+-- This works the same as @sourceDirectory@, but will not return directories at+-- all. This function also takes an extra parameter to indicate whether+-- symlinks will be followed.+--+-- @since 1.3.0+sourceDirectoryDeep :: MonadResource m+ => Bool -- ^ Follow directory symlinks+ -> FilePath -- ^ Root directory+ -> ConduitT i FilePath m ()+sourceDirectoryDeep followSymlinks =+ start+ where+ start :: MonadResource m => FilePath -> ConduitT i FilePath m ()+ start dir = sourceDirectory dir .| awaitForever go++ go :: MonadResource m => FilePath -> ConduitT i FilePath m ()+ go fp = do+ ft <- liftIO $ F.getFileType fp+ case ft of+ F.FTFile -> yield fp+ F.FTFileSym -> yield fp+ F.FTDirectory -> start fp+ F.FTDirectorySym+ | followSymlinks -> start fp+ | otherwise -> return ()+ F.FTOther -> return ()++-- | Ignore a certain number of values in the stream.+--+-- Note: since this function doesn't produce anything, you probably want to+-- use it with ('>>') instead of directly plugging it into a pipeline:+--+-- >>> runConduit $ yieldMany [1..5] .| drop 2 .| sinkList+-- []+-- >>> runConduit $ yieldMany [1..5] .| (drop 2 >> sinkList)+-- [3,4,5]+--+-- @since 1.3.0+drop :: Monad m+ => Int+ -> ConduitT a o m ()+INLINE_RULE(drop, n, CL.drop n)++-- | Drop a certain number of elements from a chunked stream.+--+-- Note: you likely want to use it with monadic composition. See the docs+-- for 'drop'.+--+-- @since 1.3.0+dropE :: (Monad m, Seq.IsSequence seq)+ => Seq.Index seq+ -> ConduitT seq o m ()+dropE =+ loop+ where+ loop i = if i <= 0+ then return ()+ else await >>= maybe (return ()) (go i)++ go i sq = do+ unless (onull y) $ leftover y+ loop i'+ where+ (x, y) = Seq.splitAt i sq+ i' = i - fromIntegral (olength x)+{-# INLINEABLE dropE #-}++-- | Drop all values which match the given predicate.+--+-- Note: you likely want to use it with monadic composition. See the docs+-- for 'drop'.+--+-- @since 1.3.0+dropWhile :: Monad m+ => (a -> Bool)+ -> ConduitT a o m ()+dropWhile f =+ loop+ where+ loop = await >>= maybe (return ()) go+ go x = if f x then loop else leftover x+{-# INLINE dropWhile #-}++-- | Drop all elements in the chunked stream which match the given predicate.+--+-- Note: you likely want to use it with monadic composition. See the docs+-- for 'drop'.+--+-- @since 1.3.0+dropWhileE :: (Monad m, Seq.IsSequence seq)+ => (Element seq -> Bool)+ -> ConduitT seq o m ()+dropWhileE f =+ loop+ where+ loop = await >>= maybe (return ()) go++ go sq =+ if onull x then loop else leftover x+ where+ x = Seq.dropWhile f sq+{-# INLINE dropWhileE #-}++-- | Monoidally combine all values in the stream.+--+-- Subject to fusion+--+-- @since 1.3.0+fold :: (Monad m, Monoid a)+ => ConduitT a o m a+INLINE_RULE0(fold, CL.foldMap id)++-- | Monoidally combine all elements in the chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+foldE :: (Monad m, MonoFoldable mono, Monoid (Element mono))+ => ConduitT mono o m (Element mono)+INLINE_RULE0(foldE, CL.fold (\accum mono -> accum `mappend` ofoldMap id mono) mempty)++-- | A strict left fold.+--+-- Subject to fusion+--+-- @since 1.3.0+foldl :: Monad m => (a -> b -> a) -> a -> ConduitT b o m a+INLINE_RULE(foldl, f x, CL.fold f x)++-- | A strict left fold on a chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+foldlE :: (Monad m, MonoFoldable mono)+ => (a -> Element mono -> a)+ -> a+ -> ConduitT mono o m a+INLINE_RULE(foldlE, f x, CL.fold (ofoldlPrime f) x)++-- Work around CPP not supporting identifiers with primes...+ofoldlPrime :: MonoFoldable mono => (a -> Element mono -> a) -> a -> mono -> a+ofoldlPrime = ofoldl'++-- | Apply the provided mapping function and monoidal combine all values.+--+-- Subject to fusion+--+-- @since 1.3.0+foldMap :: (Monad m, Monoid b)+ => (a -> b)+ -> ConduitT a o m b+INLINE_RULE(foldMap, f, CL.foldMap f)++-- | Apply the provided mapping function and monoidal combine all elements of the chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+foldMapE :: (Monad m, MonoFoldable mono, Monoid w)+ => (Element mono -> w)+ -> ConduitT mono o m w+INLINE_RULE(foldMapE, f, CL.foldMap (ofoldMap f))++-- | A strict left fold with no starting value. Returns 'Nothing'+-- when the stream is empty.+--+-- Subject to fusion+foldl1, foldl1C :: Monad m => (a -> a -> a) -> ConduitT a o m (Maybe a)+foldl1C f =+ await >>= maybe (return Nothing) loop+ where+ loop !prev = await >>= maybe (return $ Just prev) (loop . f prev)+STREAMING(foldl1, foldl1C, foldl1S, f)++-- | A strict left fold on a chunked stream, with no starting value.+-- Returns 'Nothing' when the stream is empty.+--+-- Subject to fusion+--+-- @since 1.3.0+foldl1E :: (Monad m, MonoFoldable mono, a ~ Element mono)+ => (a -> a -> a)+ -> ConduitT mono o m (Maybe a)+INLINE_RULE(foldl1E, f, foldl (foldMaybeNull f) Nothing)++-- Helper for foldl1E+foldMaybeNull :: (MonoFoldable mono, e ~ Element mono)+ => (e -> e -> e)+ -> Maybe e+ -> mono+ -> Maybe e+foldMaybeNull f macc mono =+ case (macc, NonNull.fromNullable mono) of+ (Just acc, Just nn) -> Just $ ofoldl' f acc nn+ (Nothing, Just nn) -> Just $ NonNull.ofoldl1' f nn+ _ -> macc+{-# INLINE foldMaybeNull #-}++-- | Check that all values in the stream return True.+--+-- Subject to shortcut logic: at the first False, consumption of the stream+-- will stop.+--+-- Subject to fusion+--+-- @since 1.3.0+all, allC :: Monad m+ => (a -> Bool)+ -> ConduitT a o m Bool+allC f = fmap isNothing $ find (Prelude.not . f)+{-# INLINE allC #-}+STREAMING(all, allC, allS, f)++-- | Check that all elements in the chunked stream return True.+--+-- Subject to shortcut logic: at the first False, consumption of the stream+-- will stop.+--+-- Subject to fusion+--+-- @since 1.3.0+allE :: (Monad m, MonoFoldable mono)+ => (Element mono -> Bool)+ -> ConduitT mono o m Bool+INLINE_RULE(allE, f, all (oall f))++-- | Check that at least one value in the stream returns True.+--+-- Subject to shortcut logic: at the first True, consumption of the stream+-- will stop.+--+-- Subject to fusion+--+-- @since 1.3.0+any, anyC :: Monad m+ => (a -> Bool)+ -> ConduitT a o m Bool+anyC = fmap isJust . find+{-# INLINE anyC #-}+STREAMING(any, anyC, anyS, f)++-- | Check that at least one element in the chunked stream returns True.+--+-- Subject to shortcut logic: at the first True, consumption of the stream+-- will stop.+--+-- Subject to fusion+--+-- @since 1.3.0+anyE :: (Monad m, MonoFoldable mono)+ => (Element mono -> Bool)+ -> ConduitT mono o m Bool+INLINE_RULE(anyE, f, any (oany f))++-- | Are all values in the stream True?+--+-- Consumption stops once the first False is encountered.+--+-- Subject to fusion+--+-- @since 1.3.0+and :: Monad m => ConduitT Bool o m Bool+INLINE_RULE0(and, all id)++-- | Are all elements in the chunked stream True?+--+-- Consumption stops once the first False is encountered.+--+-- Subject to fusion+--+-- @since 1.3.0+andE :: (Monad m, MonoFoldable mono, Element mono ~ Bool)+ => ConduitT mono o m Bool+INLINE_RULE0(andE, allE id)++-- | Are any values in the stream True?+--+-- Consumption stops once the first True is encountered.+--+-- Subject to fusion+--+-- @since 1.3.0+or :: Monad m => ConduitT Bool o m Bool+INLINE_RULE0(or, any id)++-- | Are any elements in the chunked stream True?+--+-- Consumption stops once the first True is encountered.+--+-- Subject to fusion+--+-- @since 1.3.0+orE :: (Monad m, MonoFoldable mono, Element mono ~ Bool)+ => ConduitT mono o m Bool+INLINE_RULE0(orE, anyE id)++-- | 'Alternative'ly combine all values in the stream.+--+-- @since 1.3.0+asum :: (Monad m, Alternative f)+ => ConduitT (f a) o m (f a)+INLINE_RULE0(asum, foldl (<|>) empty)++-- | Are any values in the stream equal to the given value?+--+-- Stops consuming as soon as a match is found.+--+-- Subject to fusion+--+-- @since 1.3.0+elem :: (Monad m, Eq a) => a -> ConduitT a o m Bool+INLINE_RULE(elem, x, any (== x))++-- | Are any elements in the chunked stream equal to the given element?+--+-- Stops consuming as soon as a match is found.+--+-- Subject to fusion+--+-- @since 1.3.0+elemE :: (Monad m, Seq.IsSequence seq, Eq (Element seq))+ => Element seq+ -> ConduitT seq o m Bool+INLINE_RULE(elemE, f, any (oelem f))++-- | Are no values in the stream equal to the given value?+--+-- Stops consuming as soon as a match is found.+--+-- Subject to fusion+--+-- @since 1.3.0+notElem :: (Monad m, Eq a) => a -> ConduitT a o m Bool+INLINE_RULE(notElem, x, all (/= x))++-- | Are no elements in the chunked stream equal to the given element?+--+-- Stops consuming as soon as a match is found.+--+-- Subject to fusion+--+-- @since 1.3.0+notElemE :: (Monad m, Seq.IsSequence seq, Eq (Element seq))+ => Element seq+ -> ConduitT seq o m Bool+INLINE_RULE(notElemE, x, all (onotElem x))++-- | Consume all incoming strict chunks into a lazy sequence.+-- Note that the entirety of the sequence will be resident at memory.+--+-- This can be used to consume a stream of strict ByteStrings into a lazy+-- ByteString, for example.+--+-- Subject to fusion+--+-- @since 1.3.0+sinkLazy, sinkLazyC :: (Monad m, LazySequence lazy strict)+ => ConduitT strict o m lazy+sinkLazyC = (fromChunks . ($ [])) <$> CL.fold (\front next -> front . (next:)) id+{-# INLINE sinkLazyC #-}+STREAMING0(sinkLazy, sinkLazyC, sinkLazyS)++-- | Consume all values from the stream and return as a list. Note that this+-- will pull all values into memory.+--+-- Subject to fusion+--+-- @since 1.3.0+sinkList :: Monad m => ConduitT a o m [a]+INLINE_RULE0(sinkList, CL.consume)++-- | Sink incoming values into a vector, growing the vector as necessary to fit+-- more elements.+--+-- Note that using this function is more memory efficient than @sinkList@ and+-- then converting to a @Vector@, as it avoids intermediate list constructors.+--+-- Subject to fusion+--+-- @since 1.3.0+sinkVector, sinkVectorC :: (V.Vector v a, PrimMonad m)+ => ConduitT a o m (v a)+sinkVectorC = do+ let initSize = 10+ mv0 <- VM.new initSize+ let go maxSize i mv | i >= maxSize = do+ let newMax = maxSize * 2+ mv' <- VM.grow mv maxSize+ go newMax i mv'+ go maxSize i mv = do+ mx <- await+ case mx of+ Nothing -> V.slice 0 i <$> V.unsafeFreeze mv+ Just x -> do+ VM.write mv i x+ go maxSize (i + 1) mv+ go initSize 0 mv0+{-# INLINEABLE sinkVectorC #-}+STREAMING0(sinkVector, sinkVectorC, sinkVectorS)++-- | Sink incoming values into a vector, up until size @maxSize@. Subsequent+-- values will be left in the stream. If there are less than @maxSize@ values+-- present, returns a @Vector@ of smaller size.+--+-- Note that using this function is more memory efficient than @sinkList@ and+-- then converting to a @Vector@, as it avoids intermediate list constructors.+--+-- Subject to fusion+--+-- @since 1.3.0+sinkVectorN, sinkVectorNC :: (V.Vector v a, PrimMonad m)+ => Int -- ^ maximum allowed size+ -> ConduitT a o m (v a)+sinkVectorNC maxSize = do+ mv <- VM.new maxSize+ let go i | i >= maxSize = V.unsafeFreeze mv+ go i = do+ mx <- await+ case mx of+ Nothing -> V.slice 0 i <$> V.unsafeFreeze mv+ Just x -> do+ VM.write mv i x+ go (i + 1)+ go 0+{-# INLINEABLE sinkVectorNC #-}+STREAMING(sinkVectorN, sinkVectorNC, sinkVectorNS, maxSize)++-- | Same as @sinkBuilder@, but afterwards convert the builder to its lazy+-- representation.+--+-- Alternatively, this could be considered an alternative to @sinkLazy@, with+-- the following differences:+--+-- * This function will allow multiple input types, not just the strict version+-- of the lazy structure.+--+-- * Some buffer copying may occur in this version.+--+-- Subject to fusion+--+-- @since 1.3.0+sinkLazyBuilder, sinkLazyBuilderC :: Monad m => ConduitT Builder o m BL.ByteString+sinkLazyBuilderC = fmap toLazyByteString fold+{-# INLINE sinkLazyBuilderC #-}+STREAMING0(sinkLazyBuilder, sinkLazyBuilderC, sinkLazyBuilderS)++-- | Consume and discard all remaining values in the stream.+--+-- Subject to fusion+--+-- @since 1.3.0+sinkNull :: Monad m => ConduitT a o m ()+INLINE_RULE0(sinkNull, CL.sinkNull)++-- | Same as @await@, but discards any leading 'onull' values.+--+-- @since 1.3.0+awaitNonNull :: (Monad m, MonoFoldable a) => ConduitT a o m (Maybe (NonNull.NonNull a))+awaitNonNull =+ go+ where+ go = await >>= maybe (return Nothing) go'++ go' = maybe go (return . Just) . NonNull.fromNullable+{-# INLINE awaitNonNull #-}++-- | Take a single value from the stream, if available.+--+-- @since 1.3.0+head :: Monad m => ConduitT a o m (Maybe a)+head = CL.head++-- | Same as 'head', but returns a default value if none are available from the stream.+--+-- @since 1.3.0+headDef :: Monad m => a -> ConduitT a o m a+headDef a = fromMaybe a <$> head++-- | Get the next element in the chunked stream.+--+-- @since 1.3.0+headE :: (Monad m, Seq.IsSequence seq) => ConduitT seq o m (Maybe (Element seq))+headE =+ loop+ where+ loop = await >>= maybe (return Nothing) go+ go x =+ case Seq.uncons x of+ Nothing -> loop+ Just (y, z) -> do+ unless (onull z) $ leftover z+ return $ Just y+{-# INLINE headE #-}++-- | View the next value in the stream without consuming it.+--+-- @since 1.3.0+peek :: Monad m => ConduitT a o m (Maybe a)+peek = CL.peek+{-# INLINE peek #-}++-- | View the next element in the chunked stream without consuming it.+--+-- @since 1.3.0+peekE :: (Monad m, MonoFoldable mono) => ConduitT mono o m (Maybe (Element mono))+peekE =+ loop+ where+ loop = await >>= maybe (return Nothing) go+ go x =+ case headMay x of+ Nothing -> loop+ Just y -> do+ leftover x+ return $ Just y+{-# INLINE peekE #-}++-- | Retrieve the last value in the stream, if present.+--+-- Subject to fusion+--+-- @since 1.3.0+last, lastC :: Monad m => ConduitT a o m (Maybe a)+lastC =+ await >>= maybe (return Nothing) loop+ where+ loop prev = await >>= maybe (return $ Just prev) loop+STREAMING0(last, lastC, lastS)++-- | Same as 'last', but returns a default value if none are available from the stream.+--+-- @since 1.3.0+lastDef :: Monad m => a -> ConduitT a o m a+lastDef a = fromMaybe a <$> last++-- | Retrieve the last element in the chunked stream, if present.+--+-- Subject to fusion+--+-- @since 1.3.0+lastE, lastEC :: (Monad m, Seq.IsSequence seq) => ConduitT seq o m (Maybe (Element seq))+lastEC =+ awaitNonNull >>= maybe (return Nothing) (loop . NonNull.last)+ where+ loop prev = awaitNonNull >>= maybe (return $ Just prev) (loop . NonNull.last)+STREAMING0(lastE, lastEC, lastES)++-- | Count how many values are in the stream.+--+-- Subject to fusion+--+-- @since 1.3.0+length :: (Monad m, Num len) => ConduitT a o m len+INLINE_RULE0(length, foldl (\x _ -> x + 1) 0)++-- | Count how many elements are in the chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+lengthE :: (Monad m, Num len, MonoFoldable mono) => ConduitT mono o m len+INLINE_RULE0(lengthE, foldl (\x y -> x + fromIntegral (olength y)) 0)++-- | Count how many values in the stream pass the given predicate.+--+-- Subject to fusion+--+-- @since 1.3.0+lengthIf :: (Monad m, Num len) => (a -> Bool) -> ConduitT a o m len+INLINE_RULE(lengthIf, f, foldl (\cnt a -> if f a then (cnt + 1) else cnt) 0)++-- | Count how many elements in the chunked stream pass the given predicate.+--+-- Subject to fusion+--+-- @since 1.3.0+lengthIfE :: (Monad m, Num len, MonoFoldable mono)+ => (Element mono -> Bool) -> ConduitT mono o m len+INLINE_RULE(lengthIfE, f, foldlE (\cnt a -> if f a then (cnt + 1) else cnt) 0)++-- | Get the largest value in the stream, if present.+--+-- Subject to fusion+--+-- @since 1.3.0+maximum :: (Monad m, Ord a) => ConduitT a o m (Maybe a)+INLINE_RULE0(maximum, foldl1 max)++-- | Get the largest element in the chunked stream, if present.+--+-- Subject to fusion+--+-- @since 1.3.0+maximumE :: (Monad m, Seq.IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))+INLINE_RULE0(maximumE, foldl1E max)++-- | Get the smallest value in the stream, if present.+--+-- Subject to fusion+--+-- @since 1.3.0+minimum :: (Monad m, Ord a) => ConduitT a o m (Maybe a)+INLINE_RULE0(minimum, foldl1 min)++-- | Get the smallest element in the chunked stream, if present.+--+-- Subject to fusion+--+-- @since 1.3.0+minimumE :: (Monad m, Seq.IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))+INLINE_RULE0(minimumE, foldl1E min)++-- | True if there are no values in the stream.+--+-- This function does not modify the stream.+--+-- @since 1.3.0+null :: Monad m => ConduitT a o m Bool+null = (maybe True (\_ -> False)) `fmap` peek+{-# INLINE null #-}++-- | True if there are no elements in the chunked stream.+--+-- This function may remove empty leading chunks from the stream, but otherwise+-- will not modify it.+--+-- @since 1.3.0+nullE :: (Monad m, MonoFoldable mono)+ => ConduitT mono o m Bool+nullE =+ go+ where+ go = await >>= maybe (return True) go'+ go' x = if onull x then go else leftover x >> return False+{-# INLINE nullE #-}++-- | Get the sum of all values in the stream.+--+-- Subject to fusion+--+-- @since 1.3.0+sum :: (Monad m, Num a) => ConduitT a o m a+INLINE_RULE0(sum, foldl (+) 0)++-- | Get the sum of all elements in the chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+sumE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)+INLINE_RULE0(sumE, foldlE (+) 0)++-- | Get the product of all values in the stream.+--+-- Subject to fusion+--+-- @since 1.3.0+product :: (Monad m, Num a) => ConduitT a o m a+INLINE_RULE0(product, foldl (*) 1)++-- | Get the product of all elements in the chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+productE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)+INLINE_RULE0(productE, foldlE (*) 1)++-- | Find the first matching value.+--+-- Subject to fusion+--+-- @since 1.3.0+find, findC :: Monad m => (a -> Bool) -> ConduitT a o m (Maybe a)+findC f =+ loop+ where+ loop = await >>= maybe (return Nothing) go+ go x = if f x then return (Just x) else loop+{-# INLINE findC #-}+STREAMING(find, findC, findS, f)++-- | Apply the action to all values in the stream.+--+-- Note: if you want to /pass/ the values instead of /consuming/ them, use+-- 'iterM' instead.+--+-- Subject to fusion+--+-- @since 1.3.0+mapM_ :: Monad m => (a -> m ()) -> ConduitT a o m ()+INLINE_RULE(mapM_, f, CL.mapM_ f)++-- | Apply the action to all elements in the chunked stream.+--+-- Note: the same caveat as with 'mapM_' applies. If you don't want to+-- consume the values, you can use 'iterM':+--+-- > iterM (omapM_ f)+--+-- Subject to fusion+--+-- @since 1.3.0+mapM_E :: (Monad m, MonoFoldable mono) => (Element mono -> m ()) -> ConduitT mono o m ()+INLINE_RULE(mapM_E, f, CL.mapM_ (omapM_ f))++-- | A monadic strict left fold.+--+-- Subject to fusion+--+-- @since 1.3.0+foldM :: Monad m => (a -> b -> m a) -> a -> ConduitT b o m a+INLINE_RULE(foldM, f x, CL.foldM f x)++-- | A monadic strict left fold on a chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+foldME :: (Monad m, MonoFoldable mono)+ => (a -> Element mono -> m a)+ -> a+ -> ConduitT mono o m a+INLINE_RULE(foldME, f x, foldM (ofoldlM f) x)++-- | Apply the provided monadic mapping function and monoidal combine all values.+--+-- Subject to fusion+--+-- @since 1.3.0+foldMapM :: (Monad m, Monoid w) => (a -> m w) -> ConduitT a o m w+INLINE_RULE(foldMapM, f, CL.foldMapM f)++-- | Apply the provided monadic mapping function and monoidal combine all+-- elements in the chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+foldMapME :: (Monad m, MonoFoldable mono, Monoid w)+ => (Element mono -> m w)+ -> ConduitT mono o m w+INLINE_RULE(foldMapME, f, CL.foldM (ofoldlM (\accum e -> mappend accum `liftM` f e)) mempty)++-- | 'sinkFile' specialized to 'ByteString' to help with type+-- inference.+--+-- @since 1.3.0+sinkFileBS :: MonadResource m => FilePath -> ConduitT ByteString o m ()+sinkFileBS = sinkFile+{-# INLINE sinkFileBS #-}++-- | Print all incoming values to stdout.+--+-- Subject to fusion+--+-- @since 1.3.0+print :: (Show a, MonadIO m) => ConduitT a o m ()+INLINE_RULE0(print, mapM_ (liftIO . Prelude.print))++-- | @sinkHandle@ applied to @stdout@.+--+-- Subject to fusion+--+-- @since 1.3.0+stdout :: MonadIO m => ConduitT ByteString o m ()+INLINE_RULE0(stdout, sinkHandle IO.stdout)++-- | @sinkHandle@ applied to @stderr@.+--+-- Subject to fusion+--+-- @since 1.3.0+stderr :: MonadIO m => ConduitT ByteString o m ()+INLINE_RULE0(stderr, sinkHandle IO.stderr)++-- | Apply a transformation to all values in a stream.+--+-- Subject to fusion+--+-- @since 1.3.0+map :: Monad m => (a -> b) -> ConduitT a b m ()+INLINE_RULE(map, f, CL.map f)++-- | Apply a transformation to all elements in a chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+mapE :: (Monad m, Functor f) => (a -> b) -> ConduitT (f a) (f b) m ()+INLINE_RULE(mapE, f, CL.map (fmap f))++-- | Apply a monomorphic transformation to all elements in a chunked stream.+--+-- Unlike @mapE@, this will work on types like @ByteString@ and @Text@ which+-- are @MonoFunctor@ but not @Functor@.+--+-- Subject to fusion+--+-- @since 1.3.0+omapE :: (Monad m, MonoFunctor mono) => (Element mono -> Element mono) -> ConduitT mono mono m ()+INLINE_RULE(omapE, f, CL.map (omap f))++-- | Apply the function to each value in the stream, resulting in a foldable+-- value (e.g., a list). Then yield each of the individual values in that+-- foldable value separately.+--+-- Generalizes concatMap, mapMaybe, and mapFoldable.+--+-- Subject to fusion+--+-- @since 1.3.0+concatMap, concatMapC :: (Monad m, MonoFoldable mono)+ => (a -> mono)+ -> ConduitT a (Element mono) m ()+concatMapC f = awaitForever (yieldMany . f)+{-# INLINE concatMapC #-}+STREAMING(concatMap, concatMapC, concatMapS, f)++-- | Apply the function to each element in the chunked stream, resulting in a+-- foldable value (e.g., a list). Then yield each of the individual values in+-- that foldable value separately.+--+-- Generalizes concatMap, mapMaybe, and mapFoldable.+--+-- Subject to fusion+--+-- @since 1.3.0+concatMapE :: (Monad m, MonoFoldable mono, Monoid w)+ => (Element mono -> w)+ -> ConduitT mono w m ()+INLINE_RULE(concatMapE, f, CL.map (ofoldMap f))++-- | Stream up to n number of values downstream.+--+-- Note that, if downstream terminates early, not all values will be consumed.+-- If you want to force /exactly/ the given number of values to be consumed,+-- see 'takeExactly'.+--+-- Subject to fusion+--+-- @since 1.3.0+take :: Monad m => Int -> ConduitT a a m ()+INLINE_RULE(take, n, CL.isolate n)++-- | Stream up to n number of elements downstream in a chunked stream.+--+-- Note that, if downstream terminates early, not all values will be consumed.+-- If you want to force /exactly/ the given number of values to be consumed,+-- see 'takeExactlyE'.+--+-- @since 1.3.0+takeE :: (Monad m, Seq.IsSequence seq)+ => Seq.Index seq+ -> ConduitT seq seq m ()+takeE =+ loop+ where+ loop i = if i <= 0+ then return ()+ else await >>= maybe (return ()) (go i)++ go i sq = do+ unless (onull x) $ yield x+ unless (onull y) $ leftover y+ loop i'+ where+ (x, y) = Seq.splitAt i sq+ i' = i - fromIntegral (olength x)+{-# INLINEABLE takeE #-}++-- | Stream all values downstream that match the given predicate.+--+-- Same caveats regarding downstream termination apply as with 'take'.+--+-- @since 1.3.0+takeWhile :: Monad m+ => (a -> Bool)+ -> ConduitT a a m ()+takeWhile f =+ loop+ where+ loop = await >>= maybe (return ()) go+ go x = if f x+ then yield x >> loop+ else leftover x+{-# INLINE takeWhile #-}++-- | Stream all elements downstream that match the given predicate in a chunked stream.+--+-- Same caveats regarding downstream termination apply as with 'takeE'.+--+-- @since 1.3.0+takeWhileE :: (Monad m, Seq.IsSequence seq)+ => (Element seq -> Bool)+ -> ConduitT seq seq m ()+takeWhileE f =+ loop+ where+ loop = await >>= maybe (return ()) go++ go sq = do+ unless (onull x) $ yield x+ if onull y+ then loop+ else leftover y+ where+ (x, y) = Seq.span f sq+{-# INLINE takeWhileE #-}++-- | Consume precisely the given number of values and feed them downstream.+--+-- This function is in contrast to 'take', which will only consume up to the+-- given number of values, and will terminate early if downstream terminates+-- early. This function will discard any additional values in the stream if+-- they are unconsumed.+--+-- Note that this function takes a downstream @ConduitT@ as a parameter, as+-- opposed to working with normal fusion. For more information, see+-- <http://www.yesodweb.com/blog/2013/10/core-flaw-pipes-conduit>, the section+-- titled \"pipes and conduit: isolate\".+--+-- @since 1.3.0+takeExactly :: Monad m+ => Int+ -> ConduitT a b m r+ -> ConduitT a b m r+takeExactly count inner = take count .| do+ r <- inner+ CL.sinkNull+ return r++-- | Same as 'takeExactly', but for chunked streams.+--+-- @since 1.3.0+takeExactlyE :: (Monad m, Seq.IsSequence a)+ => Seq.Index a+ -> ConduitT a b m r+ -> ConduitT a b m r+takeExactlyE count inner = takeE count .| do+ r <- inner+ CL.sinkNull+ return r+{-# INLINE takeExactlyE #-}++-- | Flatten out a stream by yielding the values contained in an incoming+-- @MonoFoldable@ as individually yielded values.+--+-- Subject to fusion+--+-- @since 1.3.0+concat, concatC :: (Monad m, MonoFoldable mono)+ => ConduitT mono (Element mono) m ()+concatC = awaitForever yieldMany+STREAMING0(concat, concatC, concatS)++-- | Keep only values in the stream passing a given predicate.+--+-- Subject to fusion+--+-- @since 1.3.0+filter :: Monad m => (a -> Bool) -> ConduitT a a m ()+INLINE_RULE(filter, f, CL.filter f)++-- | Keep only elements in the chunked stream passing a given predicate.+--+-- Subject to fusion+--+-- @since 1.3.0+filterE :: (Seq.IsSequence seq, Monad m) => (Element seq -> Bool) -> ConduitT seq seq m ()+INLINE_RULE(filterE, f, CL.map (Seq.filter f))++-- | Map values as long as the result is @Just@.+--+-- @since 1.3.0+mapWhile :: Monad m => (a -> Maybe b) -> ConduitT a b m ()+mapWhile f =+ loop+ where+ loop = await >>= maybe (return ()) go+ go x =+ case f x of+ Just y -> yield y >> loop+ Nothing -> leftover x+{-# INLINE mapWhile #-}++-- | Break up a stream of values into vectors of size n. The final vector may+-- be smaller than n if the total number of values is not a strict multiple of+-- n. No empty vectors will be yielded.+--+-- @since 1.3.0+conduitVector :: (V.Vector v a, PrimMonad m)+ => Int -- ^ maximum allowed size+ -> ConduitT a (v a) m ()+conduitVector size =+ loop+ where+ loop = do+ v <- sinkVectorN size+ unless (V.null v) $ do+ yield v+ loop+{-# INLINE conduitVector #-}++-- | Analog of 'Prelude.scanl' for lists.+--+-- Subject to fusion+--+-- @since 1.3.0+scanl, scanlC :: Monad m => (a -> b -> a) -> a -> ConduitT b a m ()+scanlC f =+ loop+ where+ loop seed =+ await >>= maybe (yield seed) go+ where+ go b = do+ let seed' = f seed b+ seed' `seq` yield seed+ loop seed'+STREAMING(scanl, scanlC, scanlS, f x)++-- | 'mapWhile' with a break condition dependent on a strict accumulator.+-- Equivalently, 'CL.mapAccum' as long as the result is @Right@. Instead of+-- producing a leftover, the breaking input determines the resulting+-- accumulator via @Left@.+--+-- Subject to fusion+mapAccumWhile, mapAccumWhileC :: Monad m => (a -> s -> Either s (s, b)) -> s -> ConduitT a b m s+mapAccumWhileC f =+ loop+ where+ loop !s = await >>= maybe (return s) go+ where+ go a = either (return $!) (\(s', b) -> yield b >> loop s') $ f a s+{-# INLINE mapAccumWhileC #-}+STREAMING(mapAccumWhile, mapAccumWhileC, mapAccumWhileS, f s)++-- | 'concatMap' with an accumulator.+--+-- Subject to fusion+--+-- @since 1.3.0+concatMapAccum :: Monad m => (a -> accum -> (accum, [b])) -> accum -> ConduitT a b m ()+INLINE_RULE0(concatMapAccum, CL.concatMapAccum)++-- | Insert the given value between each two values in the stream.+--+-- Subject to fusion+--+-- @since 1.3.0+intersperse, intersperseC :: Monad m => a -> ConduitT a a m ()+intersperseC x =+ await >>= omapM_ go+ where+ go y = yield y >> concatMap (\z -> [x, z])+STREAMING(intersperse, intersperseC, intersperseS, x)++-- | Sliding window of values+-- 1,2,3,4,5 with window size 2 gives+-- [1,2],[2,3],[3,4],[4,5]+--+-- Best used with structures that support O(1) snoc.+--+-- Subject to fusion+--+-- @since 1.3.0+slidingWindow, slidingWindowC :: (Monad m, Seq.IsSequence seq, Element seq ~ a) => Int -> ConduitT a seq m ()+slidingWindowC sz = go (max 1 sz) mempty+ where goContinue st = await >>=+ maybe (return ())+ (\x -> do+ let st' = Seq.snoc st x+ yield st' >> goContinue (Seq.unsafeTail st')+ )+ go 0 st = yield st >> goContinue (Seq.unsafeTail st)+ go !n st = CL.head >>= \m ->+ case m of+ Nothing -> yield st+ Just x -> go (n-1) (Seq.snoc st x)+STREAMING(slidingWindow, slidingWindowC, slidingWindowS, sz)+++-- | Split input into chunk of size 'chunkSize'+--+-- The last element may be smaller than the 'chunkSize' (see also+-- 'chunksOfExactlyE' which will not yield this last element)+--+-- @since 1.3.0+chunksOfE :: (Monad m, Seq.IsSequence seq) => Seq.Index seq -> ConduitT seq seq m ()+chunksOfE chunkSize = chunksOfExactlyE chunkSize >> (await >>= maybe (return ()) yield)++-- | Split input into chunk of size 'chunkSize'+--+-- If the input does not split into chunks exactly, the remainder will be+-- leftover (see also 'chunksOfE')+--+-- @since 1.3.0+chunksOfExactlyE :: (Monad m, Seq.IsSequence seq) => Seq.Index seq -> ConduitT seq seq m ()+chunksOfExactlyE chunkSize = await >>= maybe (return ()) start+ where+ start b+ | onull b = chunksOfE chunkSize+ | Seq.lengthIndex b < chunkSize = continue (Seq.lengthIndex b) [b]+ | otherwise = let (first,rest) = Seq.splitAt chunkSize b in+ yield first >> start rest+ continue !sofar bs = do+ next <- await+ case next of+ Nothing -> leftover (mconcat $ Prelude.reverse bs)+ Just next' ->+ let !sofar' = Seq.lengthIndex next' + sofar+ bs' = next':bs+ in if sofar' < chunkSize+ then continue sofar' bs'+ else start (mconcat (Prelude.reverse bs'))++-- | Apply a monadic transformation to all values in a stream.+--+-- If you do not need the transformed values, and instead just want the monadic+-- side-effects of running the action, see 'mapM_'.+--+-- Subject to fusion+--+-- @since 1.3.0+mapM :: Monad m => (a -> m b) -> ConduitT a b m ()+INLINE_RULE(mapM, f, CL.mapM f)++-- | Apply a monadic transformation to all elements in a chunked stream.+--+-- Subject to fusion+--+-- @since 1.3.0+mapME :: (Monad m, Data.Traversable.Traversable f) => (a -> m b) -> ConduitT (f a) (f b) m ()+INLINE_RULE(mapME, f, CL.mapM (Data.Traversable.mapM f))++-- | Apply a monadic monomorphic transformation to all elements in a chunked stream.+--+-- Unlike @mapME@, this will work on types like @ByteString@ and @Text@ which+-- are @MonoFunctor@ but not @Functor@.+--+-- Subject to fusion+--+-- @since 1.3.0+omapME :: (Monad m, MonoTraversable mono)+ => (Element mono -> m (Element mono))+ -> ConduitT mono mono m ()+INLINE_RULE(omapME, f, CL.mapM (omapM f))++-- | Apply the monadic function to each value in the stream, resulting in a+-- foldable value (e.g., a list). Then yield each of the individual values in+-- that foldable value separately.+--+-- Generalizes concatMapM, mapMaybeM, and mapFoldableM.+--+-- Subject to fusion+--+-- @since 1.3.0+concatMapM, concatMapMC :: (Monad m, MonoFoldable mono)+ => (a -> m mono)+ -> ConduitT a (Element mono) m ()+concatMapMC f = awaitForever (lift . f >=> yieldMany)+STREAMING(concatMapM, concatMapMC, concatMapMS, f)++-- | Keep only values in the stream passing a given monadic predicate.+--+-- Subject to fusion+--+-- @since 1.3.0+filterM, filterMC :: Monad m+ => (a -> m Bool)+ -> ConduitT a a m ()+filterMC f =+ awaitForever go+ where+ go x = do+ b <- lift $ f x+ when b $ yield x+STREAMING(filterM, filterMC, filterMS, f)++-- | Keep only elements in the chunked stream passing a given monadic predicate.+--+-- Subject to fusion+--+-- @since 1.3.0+filterME :: (Monad m, Seq.IsSequence seq) => (Element seq -> m Bool) -> ConduitT seq seq m ()+INLINE_RULE(filterME, f, CL.mapM (Seq.filterM f))++-- | Apply a monadic action on all values in a stream.+--+-- This @Conduit@ can be used to perform a monadic side-effect for every+-- value, whilst passing the value through the @Conduit@ as-is.+--+-- > iterM f = mapM (\a -> f a >>= \() -> return a)+--+-- Subject to fusion+--+-- @since 1.3.0+iterM :: Monad m => (a -> m ()) -> ConduitT a a m ()+INLINE_RULE(iterM, f, CL.iterM f)++-- | Analog of 'Prelude.scanl' for lists, monadic.+--+-- Subject to fusion+--+-- @since 1.3.0+scanlM, scanlMC :: Monad m => (a -> b -> m a) -> a -> ConduitT b a m ()+scanlMC f =+ loop+ where+ loop seed =+ await >>= maybe (yield seed) go+ where+ go b = do+ seed' <- lift $ f seed b+ seed' `seq` yield seed+ loop seed'+STREAMING(scanlM, scanlMC, scanlMS, f x)++-- | Monadic `mapAccumWhile`.+--+-- Subject to fusion+mapAccumWhileM, mapAccumWhileMC :: Monad m => (a -> s -> m (Either s (s, b))) -> s -> ConduitT a b m s+mapAccumWhileMC f =+ loop+ where+ loop !s = await >>= maybe (return s) go+ where+ go a = lift (f a s) >>= either (return $!) (\(s', b) -> yield b >> loop s')+{-# INLINE mapAccumWhileMC #-}+STREAMING(mapAccumWhileM, mapAccumWhileMC, mapAccumWhileMS, f s)++-- | 'concatMapM' with an accumulator.+--+-- Subject to fusion+--+-- @since 1.3.0+concatMapAccumM :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> ConduitT a b m ()+INLINE_RULE(concatMapAccumM, f x, CL.concatMapAccumM f x)++-- | Encode a stream of text as UTF8.+--+-- Subject to fusion+--+-- @since 1.3.0+encodeUtf8 :: (Monad m, DTE.Utf8 text binary) => ConduitT text binary m ()+INLINE_RULE0(encodeUtf8, map DTE.encodeUtf8)++-- | Decode a stream of binary data as UTF8.+--+-- @since 1.3.0+decodeUtf8 :: MonadThrow m => ConduitT ByteString Text m ()+decodeUtf8 =+ loop TE.streamDecodeUtf8+ where+ loop parse =+ await >>= maybe done go+ where+ parse' = unsafePerformIO . try . evaluate . parse+ done =+ case parse' mempty of+ Left e -> throwM (e :: TEE.UnicodeException)+ Right (TE.Some t bs _) -> do+ unless (T.null t) (yield t)+ unless (S.null bs) (yield $ T.replicate (S.length bs) (T.singleton '\xFFFD'))++ go bs = do+ case parse' bs of+ Left e -> do+ leftover bs+ throwM (e :: TEE.UnicodeException)+ Right (TE.Some t _ next) -> do+ unless (T.null t) (yield t)+ loop next++-- | Decode a stream of binary data as UTF8, replacing any invalid bytes with+-- the Unicode replacement character.+--+-- @since 1.3.0+decodeUtf8Lenient :: Monad m => ConduitT ByteString Text m ()+decodeUtf8Lenient =+ loop (TE.streamDecodeUtf8With TEE.lenientDecode)+ where+ loop parse =+ await >>= maybe done go+ where+ done = do+ let TE.Some t bs _ = parse mempty+ unless (T.null t) (yield t)+ unless (S.null bs) (yield $ T.replicate (S.length bs) (T.singleton '\xFFFD'))++ go bs = do+ let TE.Some t _ next = parse bs+ unless (T.null t) (yield t)+ loop next++-- | Stream in the entirety of a single line.+--+-- Like @takeExactly@, this will consume the entirety of the line regardless of+-- the behavior of the inner Conduit.+--+-- @since 1.3.0+line :: (Monad m, Seq.IsSequence seq, Element seq ~ Char)+ => ConduitT seq o m r+ -> ConduitT seq o m r+line = takeExactlyUntilE (== '\n')+{-# INLINE line #-}++-- | Same as 'line', but operates on ASCII/binary data.+--+-- @since 1.3.0+lineAscii :: (Monad m, Seq.IsSequence seq, Element seq ~ Word8)+ => ConduitT seq o m r+ -> ConduitT seq o m r+lineAscii = takeExactlyUntilE (== 10)+{-# INLINE lineAscii #-}++-- | Stream in the chunked input until an element matches a predicate.+--+-- Like @takeExactly@, this will consume the entirety of the prefix+-- regardless of the behavior of the inner Conduit.+takeExactlyUntilE :: (Monad m, Seq.IsSequence seq)+ => (Element seq -> Bool)+ -> ConduitT seq o m r+ -> ConduitT seq o m r+takeExactlyUntilE f inner =+ loop .| do+ x <- inner+ sinkNull+ return x+ where+ loop = await >>= omapM_ go+ go t =+ if onull y+ then yield x >> loop+ else do+ unless (onull x) $ yield x+ let y' = Seq.drop 1 y+ unless (onull y') $ leftover y'+ where+ (x, y) = Seq.break f t+{-# INLINE takeExactlyUntilE #-}++-- | Insert a newline character after each incoming chunk of data.+--+-- Subject to fusion+--+-- @since 1.3.0+unlines :: (Monad m, Seq.IsSequence seq, Element seq ~ Char) => ConduitT seq seq m ()+INLINE_RULE0(unlines, concatMap (:[Seq.singleton '\n']))++-- | Same as 'unlines', but operates on ASCII/binary data.+--+-- Subject to fusion+--+-- @since 1.3.0+unlinesAscii :: (Monad m, Seq.IsSequence seq, Element seq ~ Word8) => ConduitT seq seq m ()+INLINE_RULE0(unlinesAscii, concatMap (:[Seq.singleton 10]))++-- | Split a stream of arbitrarily-chunked data, based on a predicate+-- on elements. Elements that satisfy the predicate will cause chunks+-- to be split, and aren't included in these output chunks. Note+-- that, if you have unknown or untrusted input, this function is+-- /unsafe/, since it would allow an attacker to form chunks of+-- massive length and exhaust memory.+splitOnUnboundedE, splitOnUnboundedEC :: (Monad m, Seq.IsSequence seq) => (Element seq -> Bool) -> ConduitT seq seq m ()+splitOnUnboundedEC f =+ start+ where+ start = await >>= maybe (return ()) (loop id)++ loop bldr t =+ if onull y+ then do+ mt <- await+ case mt of+ Nothing -> let finalChunk = mconcat $ bldr [t]+ in unless (onull finalChunk) $ yield finalChunk+ Just t' -> loop (bldr . (t:)) t'+ else yield (mconcat $ bldr [x]) >> loop id (Seq.drop 1 y)+ where+ (x, y) = Seq.break f t+STREAMING(splitOnUnboundedE, splitOnUnboundedEC, splitOnUnboundedES, f)++-- | Convert a stream of arbitrarily-chunked textual data into a stream of data+-- where each chunk represents a single line. Note that, if you have+-- unknown or untrusted input, this function is /unsafe/, since it would allow an+-- attacker to form lines of massive length and exhaust memory.+--+-- Subject to fusion+--+-- @since 1.3.0+linesUnbounded :: (Monad m, Seq.IsSequence seq, Element seq ~ Char)+ => ConduitT seq seq m ()+INLINE_RULE0(linesUnbounded, splitOnUnboundedE (== '\n'))++-- | Same as 'linesUnbounded', but for ASCII/binary data.+--+-- Subject to fusion+--+-- @since 1.3.0+linesUnboundedAscii :: (Monad m, Seq.IsSequence seq, Element seq ~ Word8)+ => ConduitT seq seq m ()+INLINE_RULE0(linesUnboundedAscii, splitOnUnboundedE (== 10))++-- | Incrementally execute builders and pass on the filled chunks as+-- bytestrings.+--+-- @since 1.3.0+builderToByteString :: PrimMonad m => ConduitT Builder S.ByteString m ()+builderToByteString = builderToByteStringWith defaultStrategy+{-# INLINE builderToByteString #-}++-- | Same as 'builderToByteString', but input and output are wrapped in+-- 'Flush'.+--+-- @since 1.3.0+builderToByteStringFlush :: PrimMonad m+ => ConduitT (Flush Builder) (Flush S.ByteString) m ()+builderToByteStringFlush = builderToByteStringWithFlush defaultStrategy+{-# INLINE builderToByteStringFlush #-}++-- | Incrementally execute builders on the given buffer and pass on the filled+-- chunks as bytestrings. Note that, if the given buffer is too small for the+-- execution of a build step, a larger one will be allocated.+--+-- WARNING: This conduit yields bytestrings that are NOT+-- referentially transparent. Their content will be overwritten as soon+-- as control is returned from the inner sink!+--+-- @since 1.3.0+unsafeBuilderToByteString :: PrimMonad m+ => ConduitT Builder S.ByteString m ()+unsafeBuilderToByteString =+ builderToByteStringWith (reuseBufferStrategy (allocBuffer defaultChunkSize))+{-# INLINE unsafeBuilderToByteString #-}+++-- | A conduit that incrementally executes builders and passes on the+-- filled chunks as bytestrings to an inner sink.+--+-- INV: All bytestrings passed to the inner sink are non-empty.+--+-- @since 1.3.0+builderToByteStringWith :: PrimMonad m+ => BufferAllocStrategy+ -> ConduitT Builder S.ByteString m ()+builderToByteStringWith =+ bbhelper (liftM (fmap Chunk) await) yield'+ where+ yield' Flush = return ()+ yield' (Chunk bs) = yield bs+{-# INLINE builderToByteStringWith #-}++-- |+--+-- @since 1.3.0+builderToByteStringWithFlush+ :: PrimMonad m+ => BufferAllocStrategy+ -> ConduitT (Flush Builder) (Flush S.ByteString) m ()+builderToByteStringWithFlush = bbhelper await yield+{-# INLINE builderToByteStringWithFlush #-}++bbhelper+ :: PrimMonad m+ => m (Maybe (Flush Builder))+ -> (Flush S.ByteString -> m ())+ -> BufferAllocStrategy+ -> m ()+bbhelper await' yield' strat = do+ (recv, finish) <- unsafePrimToPrim $ newByteStringBuilderRecv strat+ let loop = await' >>= maybe finish' cont+ finish' = do+ mbs <- unsafePrimToPrim finish+ maybe (return ()) (yield' . Chunk) mbs+ cont fbuilder = do+ let builder =+ case fbuilder of+ Flush -> BB.flush+ Chunk b -> b+ popper <- unsafePrimToPrim $ recv builder+ let cont' = do+ bs <- unsafePrimToPrim popper+ unless (S.null bs) $ do+ yield' (Chunk bs)+ cont'+ cont'+ case fbuilder of+ Flush -> yield' Flush+ Chunk _ -> return ()+ loop+ loop+{-# INLINE bbhelper #-}++-- | Provides a series of @ByteString@s until empty, at which point it provides+-- an empty @ByteString@.+--+-- @since 1.3.0+--+type BuilderPopper = IO S.ByteString++type BuilderRecv = Builder -> IO BuilderPopper++type BuilderFinish = IO (Maybe S.ByteString)++newByteStringBuilderRecv :: BufferAllocStrategy -> IO (BuilderRecv, BuilderFinish)+newByteStringBuilderRecv (ioBufInit, nextBuf) = do+ refBuf <- newIORef ioBufInit+ return (push refBuf, finish refBuf)+ where+ finish refBuf = do+ ioBuf <- readIORef refBuf+ buf <- ioBuf+ return $ unsafeFreezeNonEmptyBuffer buf++ push refBuf builder = do+ refWri <- newIORef $ Left $ BB.runBuilder builder+ return $ popper refBuf refWri++ popper refBuf refWri = do+ ioBuf <- readIORef refBuf+ ebWri <- readIORef refWri+ case ebWri of+ Left bWri -> do+ !buf@(Buffer _ _ op ope) <- ioBuf+ (bytes, next) <- bWri op (ope `minusPtr` op)+ let op' = op `plusPtr` bytes+ case next of+ BB.Done -> do+ writeIORef refBuf $ return $ updateEndOfSlice buf op'+ return S.empty+ BB.More minSize bWri' -> do+ let buf' = updateEndOfSlice buf op'+ {-# INLINE cont #-}+ cont mbs = do+ -- sequencing the computation of the next buffer+ -- construction here ensures that the reference to the+ -- foreign pointer `fp` is lost as soon as possible.+ ioBuf' <- nextBuf minSize buf'+ writeIORef refBuf ioBuf'+ writeIORef refWri $ Left bWri'+ case mbs of+ Just bs | not $ S.null bs -> return bs+ _ -> popper refBuf refWri+ cont $ unsafeFreezeNonEmptyBuffer buf'+ BB.Chunk bs bWri' -> do+ let buf' = updateEndOfSlice buf op'+ let yieldBS = do+ nextBuf 1 buf' >>= writeIORef refBuf+ writeIORef refWri $ Left bWri'+ if S.null bs+ then popper refBuf refWri+ else return bs+ case unsafeFreezeNonEmptyBuffer buf' of+ Nothing -> yieldBS+ Just bs' -> do+ writeIORef refWri $ Right yieldBS+ return bs'+ Right action -> action++-- | A buffer @Buffer fpbuf p0 op ope@ describes a buffer with the underlying+-- byte array @fpbuf..ope@, the currently written slice @p0..op@ and the free+-- space @op..ope@.+--+-- @since 1.3.0+data Buffer = Buffer {-# UNPACK #-} !(ForeignPtr Word8) -- underlying pinned array+ {-# UNPACK #-} !(Ptr Word8) -- beginning of slice+ {-# UNPACK #-} !(Ptr Word8) -- next free byte+ {-# UNPACK #-} !(Ptr Word8) -- first byte after buffer++-- | Convert the buffer to a bytestring. This operation is unsafe in the sense+-- that created bytestring shares the underlying byte array with the buffer.+-- Hence, depending on the later use of this buffer (e.g., if it gets reset and+-- filled again) referential transparency may be lost.+--+-- @since 1.3.0+--+{-# INLINE unsafeFreezeBuffer #-}+unsafeFreezeBuffer :: Buffer -> S.ByteString+unsafeFreezeBuffer (Buffer fpbuf p0 op _) =+ PS fpbuf (p0 `minusPtr` unsafeForeignPtrToPtr fpbuf) (op `minusPtr` p0)++-- | Convert a buffer to a non-empty bytestring. See 'unsafeFreezeBuffer' for+-- the explanation of why this operation may be unsafe.+--+-- @since 1.3.0+--+{-# INLINE unsafeFreezeNonEmptyBuffer #-}+unsafeFreezeNonEmptyBuffer :: Buffer -> Maybe S.ByteString+unsafeFreezeNonEmptyBuffer buf+ | sliceSize buf <= 0 = Nothing+ | otherwise = Just $ unsafeFreezeBuffer buf++-- | Update the end of slice pointer.+--+-- @since 1.3.0+--+{-# INLINE updateEndOfSlice #-}+updateEndOfSlice :: Buffer -- Old buffer+ -> Ptr Word8 -- New end of slice+ -> Buffer -- Updated buffer+updateEndOfSlice (Buffer fpbuf p0 _ ope) op' = Buffer fpbuf p0 op' ope++-- | The size of the written slice in the buffer.+--+-- @since 1.3.0+--+sliceSize :: Buffer -> Int+sliceSize (Buffer _ p0 op _) = op `minusPtr` p0++-- | A buffer allocation strategy @(buf0, nextBuf)@ specifies the initial+-- buffer to use and how to compute a new buffer @nextBuf minSize buf@ with at+-- least size @minSize@ from a filled buffer @buf@. The double nesting of the+-- @IO@ monad helps to ensure that the reference to the filled buffer @buf@ is+-- lost as soon as possible, but the new buffer doesn't have to be allocated+-- too early.+--+-- @since 1.3.0+type BufferAllocStrategy = (IO Buffer, Int -> Buffer -> IO (IO Buffer))++-- | Safe default: allocate new buffers of default chunk size+--+-- @since 1.3.0+defaultStrategy :: BufferAllocStrategy+defaultStrategy = allNewBuffersStrategy defaultChunkSize++-- | The simplest buffer allocation strategy: whenever a buffer is requested,+-- allocate a new one that is big enough for the next build step to execute.+--+-- NOTE that this allocation strategy may spill quite some memory upon direct+-- insertion of a bytestring by the builder. Thats no problem for garbage+-- collection, but it may lead to unreasonably high memory consumption in+-- special circumstances.+--+-- @since 1.3.0+allNewBuffersStrategy :: Int -- Minimal buffer size.+ -> BufferAllocStrategy+allNewBuffersStrategy bufSize =+ ( allocBuffer bufSize+ , \reqSize _ -> return (allocBuffer (max reqSize bufSize)) )++-- | An unsafe, but possibly more efficient buffer allocation strategy:+-- reuse the buffer, if it is big enough for the next build step to execute.+--+-- @since 1.3.0+reuseBufferStrategy :: IO Buffer+ -> BufferAllocStrategy+reuseBufferStrategy buf0 =+ (buf0, tryReuseBuffer)+ where+ tryReuseBuffer reqSize buf+ | bufferSize buf >= reqSize = return $ return (reuseBuffer buf)+ | otherwise = return $ allocBuffer reqSize++-- | The size of the whole byte array underlying the buffer.+--+-- @since 1.3.0+--+bufferSize :: Buffer -> Int+bufferSize (Buffer fpbuf _ _ ope) =+ ope `minusPtr` unsafeForeignPtrToPtr fpbuf++-- | @allocBuffer size@ allocates a new buffer of size @size@.+--+-- @since 1.3.0+--+{-# INLINE allocBuffer #-}+allocBuffer :: Int -> IO Buffer+allocBuffer size = do+ fpbuf <- mallocByteString size+ let !pbuf = unsafeForeignPtrToPtr fpbuf+ return $! Buffer fpbuf pbuf pbuf (pbuf `plusPtr` size)++-- | Resets the beginning of the next slice and the next free byte such that+-- the whole buffer can be filled again.+--+-- @since 1.3.0+--+{-# INLINE reuseBuffer #-}+reuseBuffer :: Buffer -> Buffer+reuseBuffer (Buffer fpbuf _ _ ope) = Buffer fpbuf p0 p0 ope+ where+ p0 = unsafeForeignPtrToPtr fpbuf++-- | Generally speaking, yielding values from inside a Conduit requires+-- some allocation for constructors. This can introduce an overhead,+-- similar to the overhead needed to represent a list of values instead of+-- a vector. This overhead is even more severe when talking about unboxed+-- values.+--+-- This combinator allows you to overcome this overhead, and efficiently+-- fill up vectors. It takes two parameters. The first is the size of each+-- mutable vector to be allocated. The second is a function. The function+-- takes an argument which will yield the next value into a mutable+-- vector.+--+-- Under the surface, this function uses a number of tricks to get high+-- performance. For more information on both usage and implementation,+-- please see:+-- <https://www.fpcomplete.com/user/snoyberg/library-documentation/vectorbuilder>+--+-- @since 1.3.0+vectorBuilder :: (PrimMonad m, PrimMonad n, V.Vector v e, PrimState m ~ PrimState n)+ => Int -- ^ size+ -> ((e -> n ()) -> ConduitT i Void m r)+ -> ConduitT i (v e) m r+vectorBuilder size inner = do+ ref <- do+ mv <- VM.new size+ newMutVar $! S 0 mv id+ res <- onAwait (yieldS ref) (inner (addE ref))+ vs <- do+ S idx mv front <- readMutVar ref+ end <-+ if idx == 0+ then return []+ else do+ v <- V.unsafeFreeze mv+ return [V.unsafeTake idx v]+ return $ front end+ Prelude.mapM_ yield vs+ return res+{-# INLINE vectorBuilder #-}++data S s v e = S+ {-# UNPACK #-} !Int -- index+ !(V.Mutable v s e)+ ([v e] -> [v e])++onAwait :: Monad m+ => ConduitT i o m ()+ -> ConduitT i Void m r+ -> ConduitT i o m r+onAwait (ConduitT callback) (ConduitT sink0) = ConduitT $ \rest -> let+ go (Done r) = rest r+ go (HaveOutput _ o) = absurd o+ go (NeedInput f g) = callback $ \() -> NeedInput (go . f) (go . g)+ go (PipeM mp) = PipeM (liftM go mp)+ go (Leftover f i) = Leftover (go f) i+ in go (sink0 Done)+{-# INLINE onAwait #-}++yieldS :: PrimMonad m+ => MutVar (PrimState m) (S (PrimState m) v e)+ -> ConduitT i (v e) m ()+yieldS ref = do+ S idx mv front <- readMutVar ref+ Prelude.mapM_ yield (front [])+ writeMutVar ref $! S idx mv id+{-# INLINE yieldS #-}++addE :: (PrimMonad m, V.Vector v e)+ => MutVar (PrimState m) (S (PrimState m) v e)+ -> e+ -> m ()+addE ref e = do+ S idx mv front <- readMutVar ref+ VM.write mv idx e+ let idx' = succ idx+ size = VM.length mv+ if idx' >= size+ then do+ v <- V.unsafeFreeze mv+ let front' = front . (v:)+ mv' <- VM.new size+ writeMutVar ref $! S 0 mv' front'+ else writeMutVar ref $! S idx' mv front+{-# INLINE addE #-}++-- | Consume a source with a strict accumulator, in a way piecewise defined by+-- a controlling stream. The latter will be evaluated until it terminates.+--+-- >>> let f a s = liftM (:s) $ mapC (*a) =$ CL.take a+-- >>> reverse $ runIdentity $ yieldMany [0..3] $$ mapAccumS f [] (yieldMany [1..])+-- [[],[1],[4,6],[12,15,18]] :: [[Int]]+mapAccumS+ :: Monad m+ => (a -> s -> ConduitT b Void m s)+ -> s+ -> ConduitT () b m ()+ -> ConduitT a Void m s+mapAccumS f s xs = do+ (_, u) <- loop (sealConduitT xs, s)+ return u+ where loop r@(ys, !t) = await >>= maybe (return r) go+ where go a = lift (ys $$++ f a t) >>= loop+{-# INLINE mapAccumS #-}++-- | Run a consuming conduit repeatedly, only stopping when there is no more+-- data available from upstream.+--+-- @since 1.3.0+peekForever :: Monad m => ConduitT i o m () -> ConduitT i o m ()+peekForever inner =+ loop+ where+ loop = do+ mx <- peek+ case mx of+ Nothing -> return ()+ Just _ -> inner >> loop++-- | Run a consuming conduit repeatedly, only stopping when there is no more+-- data available from upstream.+--+-- In contrast to 'peekForever', this function will ignore empty+-- chunks of data. So for example, if a stream of data contains an+-- empty @ByteString@, it is still treated as empty, and the consuming+-- function is not called.+--+-- @since 1.3.0+peekForeverE :: (Monad m, MonoFoldable i)+ => ConduitT i o m ()+ -> ConduitT i o m ()+peekForeverE inner =+ loop+ where+ loop = do+ mx <- peekE+ case mx of+ Nothing -> return ()+ Just _ -> inner >> loop
+ src/Data/Conduit/Combinators/Stream.hs view
@@ -0,0 +1,474 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TypeFamilies #-}+-- | These are stream fusion versions of some of the functions in+-- "Data.Conduit.Combinators". Many functions don't have stream+-- versions here because instead they have @RULES@ which inline a+-- definition that fuses.+module Data.Conduit.Combinators.Stream+ ( yieldManyS+ , repeatMS+ , repeatWhileMS+ , foldl1S+ , allS+ , anyS+ , sinkLazyS+ , sinkVectorS+ , sinkVectorNS+ , sinkLazyBuilderS+ , lastS+ , lastES+ , findS+ , concatMapS+ , concatMapMS+ , concatS+ , scanlS+ , scanlMS+ , mapAccumWhileS+ , mapAccumWhileMS+ , intersperseS+ , slidingWindowS+ , filterMS+ , splitOnUnboundedES+ , initReplicateS+ , initRepeatS+ )+ where++-- BEGIN IMPORTS++import Control.Monad (liftM)+import Control.Monad.Primitive (PrimMonad)+import qualified Data.ByteString.Lazy as BL+import Data.ByteString.Builder (Builder, toLazyByteString)+import Data.Conduit.Internal.Fusion+import Data.Conduit.Internal.List.Stream (foldS)+import Data.Maybe (isNothing, isJust)+import Data.MonoTraversable+#if ! MIN_VERSION_base(4,8,0)+import Data.Monoid (Monoid (..))+#endif+import qualified Data.NonNull as NonNull+import qualified Data.Sequences as Seq+import qualified Data.Vector.Generic as V+import qualified Data.Vector.Generic.Mutable as VM+import Prelude++#if MIN_VERSION_mono_traversable(1,0,0)+import Data.Sequences (LazySequence (..))+#else+import Data.Sequences.Lazy+#endif++-- END IMPORTS++yieldManyS :: (Monad m, MonoFoldable mono)+ => mono+ -> StreamProducer m (Element mono)+yieldManyS mono _ =+ Stream (return . step) (return (otoList mono))+ where+ step [] = Stop ()+ step (x:xs) = Emit xs x+{-# INLINE yieldManyS #-}++repeatMS :: Monad m+ => m a+ -> StreamProducer m a+repeatMS m _ =+ Stream step (return ())+ where+ step _ = liftM (Emit ()) m+{-# INLINE repeatMS #-}++repeatWhileMS :: Monad m+ => m a+ -> (a -> Bool)+ -> StreamProducer m a+repeatWhileMS m f _ =+ Stream step (return ())+ where+ step _ = do+ x <- m+ return $ if f x+ then Emit () x+ else Stop ()+{-# INLINE repeatWhileMS #-}++foldl1S :: Monad m+ => (a -> a -> a)+ -> StreamConsumer a m (Maybe a)+foldl1S f (Stream step ms0) =+ Stream step' (liftM (Nothing, ) ms0)+ where+ step' (mprev, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop mprev+ Skip s' -> Skip (mprev, s')+ Emit s' a -> Skip (Just $ maybe a (`f` a) mprev, s')+{-# INLINE foldl1S #-}++allS :: Monad m+ => (a -> Bool)+ -> StreamConsumer a m Bool+allS f = fmapS isNothing (findS (Prelude.not . f))+{-# INLINE allS #-}++anyS :: Monad m+ => (a -> Bool)+ -> StreamConsumer a m Bool+anyS f = fmapS isJust (findS f)+{-# INLINE anyS #-}++--TODO: use a definition like+-- fmapS (fromChunks . ($ [])) <$> CL.fold (\front next -> front . (next:)) id++sinkLazyS :: (Monad m, LazySequence lazy strict)+ => StreamConsumer strict m lazy+sinkLazyS = fmapS (fromChunks . ($ [])) $ foldS (\front next -> front . (next:)) id+{-# INLINE sinkLazyS #-}++sinkVectorS :: (V.Vector v a, PrimMonad m)+ => StreamConsumer a m (v a)+sinkVectorS (Stream step ms0) = do+ Stream step' $ do+ s0 <- ms0+ mv0 <- VM.new initSize+ return (initSize, 0, mv0, s0)+ where+ initSize = 10+ step' (maxSize, i, mv, s) = do+ res <- step s+ case res of+ Stop () -> liftM (Stop . V.slice 0 i) $ V.unsafeFreeze mv+ Skip s' -> return $ Skip (maxSize, i, mv, s')+ Emit s' x -> do+ VM.write mv i x+ let i' = i + 1+ if i' >= maxSize+ then do+ let newMax = maxSize * 2+ mv' <- VM.grow mv maxSize+ return $ Skip (newMax, i', mv', s')+ else return $ Skip (maxSize, i', mv, s')+{-# INLINE sinkVectorS #-}++sinkVectorNS :: (V.Vector v a, PrimMonad m)+ => Int -- ^ maximum allowed size+ -> StreamConsumer a m (v a)+sinkVectorNS maxSize (Stream step ms0) = do+ Stream step' $ do+ s0 <- ms0+ mv0 <- VM.new maxSize+ return (0, mv0, s0)+ where+ step' (i, mv, _) | i >= maxSize = liftM Stop $ V.unsafeFreeze mv+ step' (i, mv, s) = do+ res <- step s+ case res of+ Stop () -> liftM (Stop . V.slice 0 i) $ V.unsafeFreeze mv+ Skip s' -> return $ Skip (i, mv, s')+ Emit s' x -> do+ VM.write mv i x+ let i' = i + 1+ return $ Skip (i', mv, s')+{-# INLINE sinkVectorNS #-}++sinkLazyBuilderS :: Monad m => StreamConsumer Builder m BL.ByteString+sinkLazyBuilderS = fmapS toLazyByteString (foldS mappend mempty)+{-# INLINE sinkLazyBuilderS #-}++lastS :: Monad m+ => StreamConsumer a m (Maybe a)+lastS (Stream step ms0) =+ Stream step' (liftM (Nothing,) ms0)+ where+ step' (mlast, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop mlast+ Skip s' -> Skip (mlast, s')+ Emit s' x -> Skip (Just x, s')+{-# INLINE lastS #-}++lastES :: (Monad m, Seq.IsSequence seq)+ => StreamConsumer seq m (Maybe (Element seq))+lastES (Stream step ms0) =+ Stream step' (liftM (Nothing, ) ms0)+ where+ step' (mlast, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop (fmap NonNull.last mlast)+ Skip s' -> Skip (mlast, s')+ Emit s' (NonNull.fromNullable -> mlast'@(Just _)) -> Skip (mlast', s')+ Emit s' _ -> Skip (mlast, s')+{-# INLINE lastES #-}++findS :: Monad m+ => (a -> Bool) -> StreamConsumer a m (Maybe a)+findS f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ return $ case res of+ Stop () -> Stop Nothing+ Skip s' -> Skip s'+ Emit s' x ->+ if f x+ then Stop (Just x)+ else Skip s'+{-# INLINE findS #-}++concatMapS :: (Monad m, MonoFoldable mono)+ => (a -> mono)+ -> StreamConduit a m (Element mono)+concatMapS f (Stream step ms0) =+ Stream step' (liftM ([], ) ms0)+ where+ step' ([], s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip ([], s')+ Emit s' x -> Skip (otoList (f x), s')+ step' ((x:xs), s) = return (Emit (xs, s) x)+{-# INLINE concatMapS #-}++concatMapMS :: (Monad m, MonoFoldable mono)+ => (a -> m mono)+ -> StreamConduit a m (Element mono)+concatMapMS f (Stream step ms0) =+ Stream step' (liftM ([], ) ms0)+ where+ step' ([], s) = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip ([], s')+ Emit s' x -> do+ o <- f x+ return $ Skip (otoList o, s')+ step' ((x:xs), s) = return (Emit (xs, s) x)+{-# INLINE concatMapMS #-}++concatS :: (Monad m, MonoFoldable mono)+ => StreamConduit mono m (Element mono)+concatS = concatMapS id+{-# INLINE concatS #-}++data ScanState a s+ = ScanEnded+ | ScanContinues a s++scanlS :: Monad m => (a -> b -> a) -> a -> StreamConduit b m a+scanlS f seed0 (Stream step ms0) =+ Stream step' (liftM (ScanContinues seed0) ms0)+ where+ step' ScanEnded = return $ Stop ()+ step' (ScanContinues seed s) = do+ res <- step s+ return $ case res of+ Stop () -> Emit ScanEnded seed+ Skip s' -> Skip (ScanContinues seed s')+ Emit s' x -> Emit (ScanContinues seed' s') seed+ where+ !seed' = f seed x+{-# INLINE scanlS #-}++scanlMS :: Monad m => (a -> b -> m a) -> a -> StreamConduit b m a+scanlMS f seed0 (Stream step ms0) =+ Stream step' (liftM (ScanContinues seed0) ms0)+ where+ step' ScanEnded = return $ Stop ()+ step' (ScanContinues seed s) = do+ res <- step s+ case res of+ Stop () -> return $ Emit ScanEnded seed+ Skip s' -> return $ Skip (ScanContinues seed s')+ Emit s' x -> do+ !seed' <- f seed x+ return $ Emit (ScanContinues seed' s') seed+{-# INLINE scanlMS #-}++mapAccumWhileS :: Monad m =>+ (a -> s -> Either s (s, b)) -> s -> StreamConduitT a b m s+mapAccumWhileS f initial (Stream step ms0) =+ Stream step' (liftM (initial, ) ms0)+ where+ step' (!accum, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop accum+ Skip s' -> Skip (accum, s')+ Emit s' x -> case f x accum of+ Right (!accum', r) -> Emit (accum', s') r+ Left !accum' -> Stop accum'+{-# INLINE mapAccumWhileS #-}++mapAccumWhileMS :: Monad m =>+ (a -> s -> m (Either s (s, b))) -> s -> StreamConduitT a b m s+mapAccumWhileMS f initial (Stream step ms0) =+ Stream step' (liftM (initial, ) ms0)+ where+ step' (!accum, s) = do+ res <- step s+ case res of+ Stop () -> return $ Stop accum+ Skip s' -> return $ Skip (accum, s')+ Emit s' x -> do+ lr <- f x accum+ return $ case lr of+ Right (!accum', r) -> Emit (accum', s') r+ Left !accum' -> Stop accum'+{-# INLINE mapAccumWhileMS #-}++data IntersperseState a s+ = IFirstValue s+ | IGotValue s a+ | IEmitValue s a++intersperseS :: Monad m => a -> StreamConduit a m a+intersperseS sep (Stream step ms0) =+ Stream step' (liftM IFirstValue ms0)+ where+ step' (IFirstValue s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip (IFirstValue s')+ Emit s' x -> Emit (IGotValue s' x) x+ -- Emit the separator once we know it's not the end of the list.+ step' (IGotValue s x) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip (IGotValue s' x)+ Emit s' x' -> Emit (IEmitValue s' x') sep+ -- We emitted a separator, now emit the value that comes after.+ step' (IEmitValue s x) = return $ Emit (IGotValue s x) x+{-# INLINE intersperseS #-}++data SlidingWindowState seq s+ = SWInitial Int seq s+ | SWSliding seq s+ | SWEarlyExit++slidingWindowS :: (Monad m, Seq.IsSequence seq, Element seq ~ a) => Int -> StreamConduit a m seq+slidingWindowS sz (Stream step ms0) =+ Stream step' (liftM (SWInitial (max 1 sz) mempty) ms0)+ where+ step' (SWInitial n st s) = do+ res <- step s+ return $ case res of+ Stop () -> Emit SWEarlyExit st+ Skip s' -> Skip (SWInitial n st s')+ Emit s' x ->+ if n == 1+ then Emit (SWSliding (Seq.unsafeTail st') s') st'+ else Skip (SWInitial (n - 1) st' s')+ where+ st' = Seq.snoc st x+ -- After collecting the initial window, each upstream element+ -- causes an additional window to be yielded.+ step' (SWSliding st s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip (SWSliding st s')+ Emit s' x -> Emit (SWSliding (Seq.unsafeTail st') s') st'+ where+ st' = Seq.snoc st x+ step' SWEarlyExit = return $ Stop ()++{-# INLINE slidingWindowS #-}++filterMS :: Monad m+ => (a -> m Bool)+ -> StreamConduit a m a+filterMS f (Stream step ms0) = do+ Stream step' ms0+ where+ step' s = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip s'+ Emit s' x -> do+ r <- f x+ return $+ if r+ then Emit s' x+ else Skip s'+{-# INLINE filterMS #-}++data SplitState seq s+ = SplitDone+ -- When no element of seq passes the predicate. This allows+ -- 'splitOnUnboundedES' to not run 'Seq.break' multiple times due+ -- to 'Skip's being sent by the upstream.+ | SplitNoSep seq s+ | SplitState seq s++splitOnUnboundedES :: (Monad m, Seq.IsSequence seq)+ => (Element seq -> Bool) -> StreamConduit seq m seq+splitOnUnboundedES f (Stream step ms0) =+ Stream step' (liftM (SplitState mempty) ms0)+ where+ step' SplitDone = return $ Stop ()+ step' (SplitNoSep t s) = do+ res <- step s+ return $ case res of+ Stop () | not (onull t) -> Emit SplitDone t+ | otherwise -> Stop ()+ Skip s' -> Skip (SplitNoSep t s')+ Emit s' t' -> Skip (SplitState (t `mappend` t') s')+ step' (SplitState t s) = do+ if onull y+ then do+ res <- step s+ return $ case res of+ Stop () | not (onull t) -> Emit SplitDone t+ | otherwise -> Stop ()+ Skip s' -> Skip (SplitNoSep t s')+ Emit s' t' -> Skip (SplitState (t `mappend` t') s')+ else return $ Emit (SplitState (Seq.drop 1 y) s) x+ where+ (x, y) = Seq.break f t+{-# INLINE splitOnUnboundedES #-}++-- | Streaming versions of @Data.Conduit.Combinators.Internal.initReplicate@+initReplicateS :: Monad m => m seed -> (seed -> m a) -> Int -> StreamProducer m a+initReplicateS mseed f cnt _ =+ Stream step (liftM (cnt, ) mseed)+ where+ step (ix, _) | ix <= 0 = return $ Stop ()+ step (ix, seed) = do+ x <- f seed+ return $ Emit (ix - 1, seed) x+{-# INLINE initReplicateS #-}++-- | Streaming versions of @Data.Conduit.Combinators.Internal.initRepeat@+initRepeatS :: Monad m => m seed -> (seed -> m a) -> StreamProducer m a+initRepeatS mseed f _ =+ Stream step mseed+ where+ step seed = do+ x <- f seed+ return $ Emit seed x+{-# INLINE initRepeatS #-}++-- | Utility function+fmapS :: Monad m+ => (a -> b)+ -> StreamConduitT i o m a+ -> StreamConduitT i o m b+fmapS f s inp =+ case s inp of+ Stream step ms0 -> Stream (fmap (liftM (fmap f)) step) ms0+{-# INLINE fmapS #-}
+ src/Data/Conduit/Combinators/Unqualified.hs view
@@ -0,0 +1,1206 @@+{-# OPTIONS_HADDOCK not-home #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+module Data.Conduit.Combinators.Unqualified+ ( -- ** Producers+ -- *** Pure+ CC.yieldMany+ , unfoldC+ , enumFromToC+ , iterateC+ , repeatC+ , replicateC+ , CC.sourceLazy++ -- *** Monadic+ , repeatMC+ , repeatWhileMC+ , replicateMC++ -- *** I\/O+ , CC.sourceFile+ , CC.sourceFileBS+ , CC.sourceHandle+ , CC.sourceHandleUnsafe+ , CC.sourceIOHandle+ , stdinC+ , CC.withSourceFile++ -- *** Filesystem+ , CC.sourceDirectory+ , CC.sourceDirectoryDeep++ -- ** Consumers+ -- *** Pure+ , dropC+ , dropCE+ , dropWhileC+ , dropWhileCE+ , foldC+ , foldCE+ , foldlC+ , foldlCE+ , foldMapC+ , foldMapCE+ , allC+ , allCE+ , anyC+ , anyCE+ , andC+ , andCE+ , orC+ , orCE+ , asumC+ , elemC+ , elemCE+ , notElemC+ , notElemCE+ , CC.sinkLazy+ , CC.sinkList+ , CC.sinkVector+ , CC.sinkVectorN+ , CC.sinkLazyBuilder+ , CC.sinkNull+ , CC.awaitNonNull+ , headC+ , headDefC+ , headCE+ , peekC+ , peekCE+ , lastC+ , lastDefC+ , lastCE+ , lengthC+ , lengthCE+ , lengthIfC+ , lengthIfCE+ , maximumC+ , maximumCE+ , minimumC+ , minimumCE+ , nullC+ , nullCE+ , sumC+ , sumCE+ , productC+ , productCE+ , findC++ -- *** Monadic+ , mapM_C+ , mapM_CE+ , foldMC+ , foldMCE+ , foldMapMC+ , foldMapMCE++ -- *** I\/O+ , CC.sinkFile+ , CC.sinkFileCautious+ , CC.sinkTempFile+ , CC.sinkSystemTempFile+ , CC.sinkFileBS+ , CC.sinkHandle+ , CC.sinkIOHandle+ , printC+ , stdoutC+ , stderrC+ , CC.withSinkFile+ , CC.withSinkFileBuilder+ , CC.withSinkFileCautious+ , CC.sinkHandleBuilder+ , CC.sinkHandleFlush++ -- ** Transformers+ -- *** Pure+ , mapC+ , mapCE+ , omapCE+ , concatMapC+ , concatMapCE+ , takeC+ , takeCE+ , takeWhileC+ , takeWhileCE+ , takeExactlyC+ , takeExactlyCE+ , concatC+ , filterC+ , filterCE+ , mapWhileC+ , conduitVector+ , scanlC+ , mapAccumWhileC+ , concatMapAccumC+ , intersperseC+ , slidingWindowC+ , chunksOfCE+ , chunksOfExactlyCE++ -- *** Monadic+ , mapMC+ , mapMCE+ , omapMCE+ , concatMapMC+ , filterMC+ , filterMCE+ , iterMC+ , scanlMC+ , mapAccumWhileMC+ , concatMapAccumMC++ -- *** Textual+ , encodeUtf8C+ , decodeUtf8C+ , decodeUtf8LenientC+ , lineC+ , lineAsciiC+ , unlinesC+ , unlinesAsciiC+ , linesUnboundedC+ , linesUnboundedAsciiC++ -- ** Builders+ , CC.builderToByteString+ , CC.unsafeBuilderToByteString+ , CC.builderToByteStringWith+ , CC.builderToByteStringFlush+ , CC.builderToByteStringWithFlush+ , CC.BufferAllocStrategy+ , CC.allNewBuffersStrategy+ , CC.reuseBufferStrategy++ -- ** Special+ , vectorBuilderC+ , CC.mapAccumS+ , CC.peekForever+ , CC.peekForeverE+ ) where++-- BEGIN IMPORTS++import qualified Data.Conduit.Combinators as CC+-- BEGIN IMPORTS++import qualified Data.Traversable+import Control.Applicative (Alternative)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.Trans.Resource (MonadThrow)+import Data.Conduit+import Data.Monoid (Monoid (..))+import Data.MonoTraversable+import qualified Data.Sequences as Seq+import qualified Data.Vector.Generic as V+import Prelude (Bool (..), Eq (..), Int,+ Maybe (..), Monad (..), Num (..),+ Ord (..), Functor (..), Either (..),+ Enum, Show, Char)+import Data.Word (Word8)+import Data.ByteString (ByteString)+import Data.Text (Text)++import qualified Data.Sequences as DTE+++-- END IMPORTS++-- | Generate a producer from a seed value.+--+-- @since 1.3.0+unfoldC :: Monad m+ => (b -> Maybe (a, b))+ -> b+ -> ConduitT i a m ()+unfoldC = CC.unfold+{-# INLINE unfoldC #-}++-- | Enumerate from a value to a final value, inclusive, via 'succ'.+--+-- This is generally more efficient than using @Prelude@\'s @enumFromTo@ and+-- combining with @sourceList@ since this avoids any intermediate data+-- structures.+--+-- @since 1.3.0+enumFromToC :: (Monad m, Enum a, Ord a) => a -> a -> ConduitT i a m ()+enumFromToC = CC.enumFromTo+{-# INLINE enumFromToC #-}++-- | Produces an infinite stream of repeated applications of f to x.+--+-- @since 1.3.0+iterateC :: Monad m => (a -> a) -> a -> ConduitT i a m ()+iterateC = CC.iterate+{-# INLINE iterateC #-}++-- | Produce an infinite stream consisting entirely of the given value.+--+-- @since 1.3.0+repeatC :: Monad m => a -> ConduitT i a m ()+repeatC = CC.repeat+{-# INLINE repeatC #-}++-- | Produce a finite stream consisting of n copies of the given value.+--+-- @since 1.3.0+replicateC :: Monad m+ => Int+ -> a+ -> ConduitT i a m ()+replicateC = CC.replicate+{-# INLINE replicateC #-}++-- | Repeatedly run the given action and yield all values it produces.+--+-- @since 1.3.0+repeatMC :: Monad m+ => m a+ -> ConduitT i a m ()+repeatMC = CC.repeatM+{-# INLINE repeatMC #-}++-- | Repeatedly run the given action and yield all values it produces, until+-- the provided predicate returns @False@.+--+-- @since 1.3.0+repeatWhileMC :: Monad m+ => m a+ -> (a -> Bool)+ -> ConduitT i a m ()+repeatWhileMC = CC.repeatWhileM+{-# INLINE repeatWhileMC #-}++-- | Perform the given action n times, yielding each result.+--+-- @since 1.3.0+replicateMC :: Monad m+ => Int+ -> m a+ -> ConduitT i a m ()+replicateMC = CC.replicateM+{-# INLINE replicateMC #-}++-- | @sourceHandle@ applied to @stdin@.+--+-- @since 1.3.0+stdinC :: MonadIO m => ConduitT i ByteString m ()+stdinC = CC.stdin+{-# INLINE stdinC #-}++-- | Ignore a certain number of values in the stream.+--+-- Note: since this function doesn't produce anything, you probably want to+-- use it with ('>>') instead of directly plugging it into a pipeline:+--+-- >>> runConduit $ yieldMany [1..5] .| dropC 2 .| sinkList+-- []+-- >>> runConduit $ yieldMany [1..5] .| (dropC 2 >> sinkList)+-- [3,4,5]+--+-- @since 1.3.0+dropC :: Monad m+ => Int+ -> ConduitT a o m ()+dropC = CC.drop+{-# INLINE dropC #-}++-- | Drop a certain number of elements from a chunked stream.+--+-- Note: you likely want to use it with monadic composition. See the docs+-- for 'dropC'.+--+-- @since 1.3.0+dropCE :: (Monad m, Seq.IsSequence seq)+ => Seq.Index seq+ -> ConduitT seq o m ()+dropCE = CC.dropE+{-# INLINE dropCE #-}++-- | Drop all values which match the given predicate.+--+-- Note: you likely want to use it with monadic composition. See the docs+-- for 'dropC'.+--+-- @since 1.3.0+dropWhileC :: Monad m+ => (a -> Bool)+ -> ConduitT a o m ()+dropWhileC = CC.dropWhile+{-# INLINE dropWhileC #-}++-- | Drop all elements in the chunked stream which match the given predicate.+--+-- Note: you likely want to use it with monadic composition. See the docs+-- for 'dropC'.+--+-- @since 1.3.0+dropWhileCE :: (Monad m, Seq.IsSequence seq)+ => (Element seq -> Bool)+ -> ConduitT seq o m ()+dropWhileCE = CC.dropWhileE+{-# INLINE dropWhileCE #-}++-- | Monoidally combine all values in the stream.+--+-- @since 1.3.0+foldC :: (Monad m, Monoid a)+ => ConduitT a o m a+foldC = CC.fold+{-# INLINE foldC #-}++-- | Monoidally combine all elements in the chunked stream.+--+-- @since 1.3.0+foldCE :: (Monad m, MonoFoldable mono, Monoid (Element mono))+ => ConduitT mono o m (Element mono)+foldCE = CC.foldE+{-# INLINE foldCE #-}++-- | A strict left fold.+--+-- @since 1.3.0+foldlC :: Monad m => (a -> b -> a) -> a -> ConduitT b o m a+foldlC = CC.foldl+{-# INLINE foldlC #-}++-- | A strict left fold on a chunked stream.+--+-- @since 1.3.0+foldlCE :: (Monad m, MonoFoldable mono)+ => (a -> Element mono -> a)+ -> a+ -> ConduitT mono o m a+foldlCE = CC.foldlE+{-# INLINE foldlCE #-}++-- | Apply the provided mapping function and monoidal combine all values.+--+-- @since 1.3.0+foldMapC :: (Monad m, Monoid b)+ => (a -> b)+ -> ConduitT a o m b+foldMapC = CC.foldMap+{-# INLINE foldMapC #-}++-- | Apply the provided mapping function and monoidal combine all elements of the chunked stream.+--+-- @since 1.3.0+foldMapCE :: (Monad m, MonoFoldable mono, Monoid w)+ => (Element mono -> w)+ -> ConduitT mono o m w+foldMapCE = CC.foldMapE+{-# INLINE foldMapCE #-}++-- | Check that all values in the stream return True.+--+-- Subject to shortcut logic: at the first False, consumption of the stream+-- will stop.+--+-- @since 1.3.0+allC :: Monad m+ => (a -> Bool)+ -> ConduitT a o m Bool+allC = CC.all+{-# INLINE allC #-}++-- | Check that all elements in the chunked stream return True.+--+-- Subject to shortcut logic: at the first False, consumption of the stream+-- will stop.+--+-- @since 1.3.0+allCE :: (Monad m, MonoFoldable mono)+ => (Element mono -> Bool)+ -> ConduitT mono o m Bool+allCE = CC.allE+{-# INLINE allCE #-}++-- | Check that at least one value in the stream returns True.+--+-- Subject to shortcut logic: at the first True, consumption of the stream+-- will stop.+--+-- @since 1.3.0+anyC :: Monad m+ => (a -> Bool)+ -> ConduitT a o m Bool+anyC = CC.any+{-# INLINE anyC #-}++-- | Check that at least one element in the chunked stream returns True.+--+-- Subject to shortcut logic: at the first True, consumption of the stream+-- will stop.+--+-- @since 1.3.0+anyCE :: (Monad m, MonoFoldable mono)+ => (Element mono -> Bool)+ -> ConduitT mono o m Bool+anyCE = CC.anyE+{-# INLINE anyCE #-}++-- | Are all values in the stream True?+--+-- Consumption stops once the first False is encountered.+--+-- @since 1.3.0+andC :: Monad m => ConduitT Bool o m Bool+andC = CC.and+{-# INLINE andC #-}++-- | Are all elements in the chunked stream True?+--+-- Consumption stops once the first False is encountered.+--+-- @since 1.3.0+andCE :: (Monad m, MonoFoldable mono, Element mono ~ Bool)+ => ConduitT mono o m Bool+andCE = CC.andE+{-# INLINE andCE #-}++-- | Are any values in the stream True?+--+-- Consumption stops once the first True is encountered.+--+-- @since 1.3.0+orC :: Monad m => ConduitT Bool o m Bool+orC = CC.or+{-# INLINE orC #-}++-- | Are any elements in the chunked stream True?+--+-- Consumption stops once the first True is encountered.+--+-- @since 1.3.0+orCE :: (Monad m, MonoFoldable mono, Element mono ~ Bool)+ => ConduitT mono o m Bool+orCE = CC.orE+{-# INLINE orCE #-}++-- | 'Alternative'ly combine all values in the stream.+--+-- @since 1.3.0+asumC :: (Monad m, Alternative f) => ConduitT (f a) o m (f a)+asumC = CC.asum++-- | Are any values in the stream equal to the given value?+--+-- Stops consuming as soon as a match is found.+--+-- @since 1.3.0+elemC :: (Monad m, Eq a) => a -> ConduitT a o m Bool+elemC = CC.elem+{-# INLINE elemC #-}++-- | Are any elements in the chunked stream equal to the given element?+--+-- Stops consuming as soon as a match is found.+--+-- @since 1.3.0+#if MIN_VERSION_mono_traversable(1,0,0)+elemCE :: (Monad m, Seq.IsSequence seq, Eq (Element seq))+#else+elemCE :: (Monad m, Seq.EqSequence seq)+#endif+ => Element seq+ -> ConduitT seq o m Bool+elemCE = CC.elemE+{-# INLINE elemCE #-}++-- | Are no values in the stream equal to the given value?+--+-- Stops consuming as soon as a match is found.+--+-- @since 1.3.0+notElemC :: (Monad m, Eq a) => a -> ConduitT a o m Bool+notElemC = CC.notElem+{-# INLINE notElemC #-}++-- | Are no elements in the chunked stream equal to the given element?+--+-- Stops consuming as soon as a match is found.+--+-- @since 1.3.0+#if MIN_VERSION_mono_traversable(1,0,0)+notElemCE :: (Monad m, Seq.IsSequence seq, Eq (Element seq))+#else+notElemCE :: (Monad m, Seq.EqSequence seq)+#endif+ => Element seq+ -> ConduitT seq o m Bool+notElemCE = CC.notElemE+{-# INLINE notElemCE #-}++-- | Take a single value from the stream, if available.+--+-- @since 1.3.0+headC :: Monad m => ConduitT a o m (Maybe a)+headC = CC.head++-- | Same as 'headC', but returns a default value if none are available from the stream.+--+-- @since 1.3.0+headDefC :: Monad m => a -> ConduitT a o m a+headDefC = CC.headDef++-- | Get the next element in the chunked stream.+--+-- @since 1.3.0+headCE :: (Monad m, Seq.IsSequence seq) => ConduitT seq o m (Maybe (Element seq))+headCE = CC.headE+{-# INLINE headCE #-}++-- | View the next value in the stream without consuming it.+--+-- @since 1.3.0+peekC :: Monad m => ConduitT a o m (Maybe a)+peekC = CC.peek+{-# INLINE peekC #-}++-- | View the next element in the chunked stream without consuming it.+--+-- @since 1.3.0+peekCE :: (Monad m, MonoFoldable mono) => ConduitT mono o m (Maybe (Element mono))+peekCE = CC.peekE+{-# INLINE peekCE #-}++-- | Retrieve the last value in the stream, if present.+--+-- @since 1.3.0+lastC :: Monad m => ConduitT a o m (Maybe a)+lastC = CC.last+{-# INLINE lastC #-}++-- | Same as 'lastC', but returns a default value if none are available from the stream.+--+-- @since 1.3.0+lastDefC :: Monad m => a -> ConduitT a o m a+lastDefC = CC.lastDef++-- | Retrieve the last element in the chunked stream, if present.+--+-- @since 1.3.0+lastCE :: (Monad m, Seq.IsSequence seq) => ConduitT seq o m (Maybe (Element seq))+lastCE = CC.lastE+{-# INLINE lastCE #-}++-- | Count how many values are in the stream.+--+-- @since 1.3.0+lengthC :: (Monad m, Num len) => ConduitT a o m len+lengthC = CC.length+{-# INLINE lengthC #-}++-- | Count how many elements are in the chunked stream.+--+-- @since 1.3.0+lengthCE :: (Monad m, Num len, MonoFoldable mono) => ConduitT mono o m len+lengthCE = CC.lengthE+{-# INLINE lengthCE #-}++-- | Count how many values in the stream pass the given predicate.+--+-- @since 1.3.0+lengthIfC :: (Monad m, Num len) => (a -> Bool) -> ConduitT a o m len+lengthIfC = CC.lengthIf+{-# INLINE lengthIfC #-}++-- | Count how many elements in the chunked stream pass the given predicate.+--+-- @since 1.3.0+lengthIfCE :: (Monad m, Num len, MonoFoldable mono)+ => (Element mono -> Bool) -> ConduitT mono o m len+lengthIfCE = CC.lengthIfE+{-# INLINE lengthIfCE #-}++-- | Get the largest value in the stream, if present.+--+-- @since 1.3.0+maximumC :: (Monad m, Ord a) => ConduitT a o m (Maybe a)+maximumC = CC.maximum+{-# INLINE maximumC #-}++-- | Get the largest element in the chunked stream, if present.+--+-- @since 1.3.0+#if MIN_VERSION_mono_traversable(1,0,0)+maximumCE :: (Monad m, Seq.IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))+#else+maximumCE :: (Monad m, Seq.OrdSequence seq) => ConduitT seq o m (Maybe (Element seq))+#endif+maximumCE = CC.maximumE+{-# INLINE maximumCE #-}++-- | Get the smallest value in the stream, if present.+--+-- @since 1.3.0+minimumC :: (Monad m, Ord a) => ConduitT a o m (Maybe a)+minimumC = CC.minimum+{-# INLINE minimumC #-}++-- | Get the smallest element in the chunked stream, if present.+--+-- @since 1.3.0+#if MIN_VERSION_mono_traversable(1,0,0)+minimumCE :: (Monad m, Seq.IsSequence seq, Ord (Element seq)) => ConduitT seq o m (Maybe (Element seq))+#else+minimumCE :: (Monad m, Seq.OrdSequence seq) => ConduitT seq o m (Maybe (Element seq))+#endif+minimumCE = CC.minimumE+{-# INLINE minimumCE #-}++-- | True if there are no values in the stream.+--+-- This function does not modify the stream.+--+-- @since 1.3.0+nullC :: Monad m => ConduitT a o m Bool+nullC = CC.null+{-# INLINE nullC #-}++-- | True if there are no elements in the chunked stream.+--+-- This function may remove empty leading chunks from the stream, but otherwise+-- will not modify it.+--+-- @since 1.3.0+nullCE :: (Monad m, MonoFoldable mono)+ => ConduitT mono o m Bool+nullCE = CC.nullE+{-# INLINE nullCE #-}++-- | Get the sum of all values in the stream.+--+-- @since 1.3.0+sumC :: (Monad m, Num a) => ConduitT a o m a+sumC = CC.sum+{-# INLINE sumC #-}++-- | Get the sum of all elements in the chunked stream.+--+-- @since 1.3.0+sumCE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)+sumCE = CC.sumE+{-# INLINE sumCE #-}++-- | Get the product of all values in the stream.+--+-- @since 1.3.0+productC :: (Monad m, Num a) => ConduitT a o m a+productC = CC.product+{-# INLINE productC #-}++-- | Get the product of all elements in the chunked stream.+--+-- @since 1.3.0+productCE :: (Monad m, MonoFoldable mono, Num (Element mono)) => ConduitT mono o m (Element mono)+productCE = CC.productE+{-# INLINE productCE #-}++-- | Find the first matching value.+--+-- @since 1.3.0+findC :: Monad m => (a -> Bool) -> ConduitT a o m (Maybe a)+findC = CC.find+{-# INLINE findC #-}++-- | Apply the action to all values in the stream.+--+-- Note: if you want to /pass/ the values instead of /consuming/ them, use+-- 'iterM' instead.+--+-- @since 1.3.0+mapM_C :: Monad m => (a -> m ()) -> ConduitT a o m ()+mapM_C = CC.mapM_+{-# INLINE mapM_C #-}++-- | Apply the action to all elements in the chunked stream.+--+-- Note: the same caveat as with 'mapM_C' applies. If you don't want to+-- consume the values, you can use 'iterM':+--+-- > iterM (omapM_ f)+--+-- @since 1.3.0+mapM_CE :: (Monad m, MonoFoldable mono) => (Element mono -> m ()) -> ConduitT mono o m ()+mapM_CE = CC.mapM_E+{-# INLINE mapM_CE #-}++-- | A monadic strict left fold.+--+-- @since 1.3.0+foldMC :: Monad m => (a -> b -> m a) -> a -> ConduitT b o m a+foldMC = CC.foldM+{-# INLINE foldMC #-}++-- | A monadic strict left fold on a chunked stream.+--+-- @since 1.3.0+foldMCE :: (Monad m, MonoFoldable mono)+ => (a -> Element mono -> m a)+ -> a+ -> ConduitT mono o m a+foldMCE = CC.foldME+{-# INLINE foldMCE #-}++-- | Apply the provided monadic mapping function and monoidal combine all values.+--+-- @since 1.3.0+foldMapMC :: (Monad m, Monoid w) => (a -> m w) -> ConduitT a o m w+foldMapMC = CC.foldMapM+{-# INLINE foldMapMC #-}++-- | Apply the provided monadic mapping function and monoidal combine all+-- elements in the chunked stream.+--+-- @since 1.3.0+foldMapMCE :: (Monad m, MonoFoldable mono, Monoid w)+ => (Element mono -> m w)+ -> ConduitT mono o m w+foldMapMCE = CC.foldMapME+{-# INLINE foldMapMCE #-}++-- | Print all incoming values to stdout.+--+-- @since 1.3.0+printC :: (Show a, MonadIO m) => ConduitT a o m ()+printC = CC.print+{-# INLINE printC #-}++-- | @sinkHandle@ applied to @stdout@.+--+-- @since 1.3.0+stdoutC :: MonadIO m => ConduitT ByteString o m ()+stdoutC = CC.stdout+{-# INLINE stdoutC #-}++-- | @sinkHandle@ applied to @stderr@.+--+-- @since 1.3.0+stderrC :: MonadIO m => ConduitT ByteString o m ()+stderrC = CC.stderr+{-# INLINE stderrC #-}++-- | Apply a transformation to all values in a stream.+--+-- @since 1.3.0+mapC :: Monad m => (a -> b) -> ConduitT a b m ()+mapC = CC.map+{-# INLINE mapC #-}++-- | Apply a transformation to all elements in a chunked stream.+--+-- @since 1.3.0+mapCE :: (Monad m, Functor f) => (a -> b) -> ConduitT (f a) (f b) m ()+mapCE = CC.mapE+{-# INLINE mapCE #-}++-- | Apply a monomorphic transformation to all elements in a chunked stream.+--+-- Unlike @mapE@, this will work on types like @ByteString@ and @Text@ which+-- are @MonoFunctor@ but not @Functor@.+--+-- @since 1.3.0+omapCE :: (Monad m, MonoFunctor mono) => (Element mono -> Element mono) -> ConduitT mono mono m ()+omapCE = CC.omapE+{-# INLINE omapCE #-}++-- | Apply the function to each value in the stream, resulting in a foldable+-- value (e.g., a list). Then yield each of the individual values in that+-- foldable value separately.+--+-- Generalizes concatMap, mapMaybe, and mapFoldable.+--+-- @since 1.3.0+concatMapC :: (Monad m, MonoFoldable mono)+ => (a -> mono)+ -> ConduitT a (Element mono) m ()+concatMapC = CC.concatMap+{-# INLINE concatMapC #-}++-- | Apply the function to each element in the chunked stream, resulting in a+-- foldable value (e.g., a list). Then yield each of the individual values in+-- that foldable value separately.+--+-- Generalizes concatMap, mapMaybe, and mapFoldable.+--+-- @since 1.3.0+concatMapCE :: (Monad m, MonoFoldable mono, Monoid w)+ => (Element mono -> w)+ -> ConduitT mono w m ()+concatMapCE = CC.concatMapE+{-# INLINE concatMapCE #-}++-- | Stream up to n number of values downstream.+--+-- Note that, if downstream terminates early, not all values will be consumed.+-- If you want to force /exactly/ the given number of values to be consumed,+-- see 'takeExactly'.+--+-- @since 1.3.0+takeC :: Monad m => Int -> ConduitT a a m ()+takeC = CC.take+{-# INLINE takeC #-}++-- | Stream up to n number of elements downstream in a chunked stream.+--+-- Note that, if downstream terminates early, not all values will be consumed.+-- If you want to force /exactly/ the given number of values to be consumed,+-- see 'takeExactlyE'.+--+-- @since 1.3.0+takeCE :: (Monad m, Seq.IsSequence seq)+ => Seq.Index seq+ -> ConduitT seq seq m ()+takeCE = CC.takeE+{-# INLINE takeCE #-}++-- | Stream all values downstream that match the given predicate.+--+-- Same caveats regarding downstream termination apply as with 'take'.+--+-- @since 1.3.0+takeWhileC :: Monad m+ => (a -> Bool)+ -> ConduitT a a m ()+takeWhileC = CC.takeWhile+{-# INLINE takeWhileC #-}++-- | Stream all elements downstream that match the given predicate in a chunked stream.+--+-- Same caveats regarding downstream termination apply as with 'takeE'.+--+-- @since 1.3.0+takeWhileCE :: (Monad m, Seq.IsSequence seq)+ => (Element seq -> Bool)+ -> ConduitT seq seq m ()+takeWhileCE = CC.takeWhileE+{-# INLINE takeWhileCE #-}++-- | Consume precisely the given number of values and feed them downstream.+--+-- This function is in contrast to 'take', which will only consume up to the+-- given number of values, and will terminate early if downstream terminates+-- early. This function will discard any additional values in the stream if+-- they are unconsumed.+--+-- Note that this function takes a downstream @ConduitT@ as a parameter, as+-- opposed to working with normal fusion. For more information, see+-- <http://www.yesodweb.com/blog/2013/10/core-flaw-pipes-conduit>, the section+-- titled \"pipes and conduit: isolate\".+--+-- @since 1.3.0+takeExactlyC :: Monad m+ => Int+ -> ConduitT a b m r+ -> ConduitT a b m r+takeExactlyC = CC.takeExactly+{-# INLINE takeExactlyC #-}++-- | Same as 'takeExactly', but for chunked streams.+--+-- @since 1.3.0+takeExactlyCE :: (Monad m, Seq.IsSequence a)+ => Seq.Index a+ -> ConduitT a b m r+ -> ConduitT a b m r+takeExactlyCE = CC.takeExactlyE+{-# INLINE takeExactlyCE #-}++-- | Flatten out a stream by yielding the values contained in an incoming+-- @MonoFoldable@ as individually yielded values.+--+-- @since 1.3.0+concatC :: (Monad m, MonoFoldable mono)+ => ConduitT mono (Element mono) m ()+concatC = CC.concat+{-# INLINE concatC #-}++-- | Keep only values in the stream passing a given predicate.+--+-- @since 1.3.0+filterC :: Monad m => (a -> Bool) -> ConduitT a a m ()+filterC = CC.filter+{-# INLINE filterC #-}++-- | Keep only elements in the chunked stream passing a given predicate.+--+-- @since 1.3.0+filterCE :: (Seq.IsSequence seq, Monad m) => (Element seq -> Bool) -> ConduitT seq seq m ()+filterCE = CC.filterE+{-# INLINE filterCE #-}++-- | Map values as long as the result is @Just@.+--+-- @since 1.3.0+mapWhileC :: Monad m => (a -> Maybe b) -> ConduitT a b m ()+mapWhileC = CC.mapWhile+{-# INLINE mapWhileC #-}++-- | Break up a stream of values into vectors of size n. The final vector may+-- be smaller than n if the total number of values is not a strict multiple of+-- n. No empty vectors will be yielded.+--+-- @since 1.3.0+conduitVector :: (V.Vector v a, PrimMonad m)+ => Int -- ^ maximum allowed size+ -> ConduitT a (v a) m ()+conduitVector = CC.conduitVector+{-# INLINE conduitVector #-}++-- | Analog of 'Prelude.scanl' for lists.+--+-- @since 1.3.0+scanlC :: Monad m => (a -> b -> a) -> a -> ConduitT b a m ()+scanlC = CC.scanl+{-# INLINE scanlC #-}++-- | 'mapWhileC' with a break condition dependent on a strict accumulator.+-- Equivalently, 'CL.mapAccum' as long as the result is @Right@. Instead of+-- producing a leftover, the breaking input determines the resulting+-- accumulator via @Left@.+mapAccumWhileC :: Monad m =>+ (a -> s -> Either s (s, b)) -> s -> ConduitT a b m s+mapAccumWhileC = CC.mapAccumWhile+{-# INLINE mapAccumWhileC #-}++-- | 'concatMap' with an accumulator.+--+-- @since 1.3.0+concatMapAccumC :: Monad m => (a -> accum -> (accum, [b])) -> accum -> ConduitT a b m ()+concatMapAccumC = CC.concatMapAccum+{-# INLINE concatMapAccumC #-}++-- | Insert the given value between each two values in the stream.+--+-- @since 1.3.0+intersperseC :: Monad m => a -> ConduitT a a m ()+intersperseC = CC.intersperse+{-# INLINE intersperseC #-}++-- | Sliding window of values+-- 1,2,3,4,5 with window size 2 gives+-- [1,2],[2,3],[3,4],[4,5]+--+-- Best used with structures that support O(1) snoc.+--+-- @since 1.3.0+slidingWindowC :: (Monad m, Seq.IsSequence seq, Element seq ~ a) => Int -> ConduitT a seq m ()+slidingWindowC = CC.slidingWindow+{-# INLINE slidingWindowC #-}+++-- | Split input into chunk of size 'chunkSize'+--+-- The last element may be smaller than the 'chunkSize' (see also+-- 'chunksOfExactlyE' which will not yield this last element)+--+-- @since 1.3.0+chunksOfCE :: (Monad m, Seq.IsSequence seq) => Seq.Index seq -> ConduitT seq seq m ()+chunksOfCE = CC.chunksOfE+{-# INLINE chunksOfCE #-}++-- | Split input into chunk of size 'chunkSize'+--+-- If the input does not split into chunks exactly, the remainder will be+-- leftover (see also 'chunksOfE')+--+-- @since 1.3.0+chunksOfExactlyCE :: (Monad m, Seq.IsSequence seq) => Seq.Index seq -> ConduitT seq seq m ()+chunksOfExactlyCE = CC.chunksOfExactlyE+{-# INLINE chunksOfExactlyCE #-}++-- | Apply a monadic transformation to all values in a stream.+--+-- If you do not need the transformed values, and instead just want the monadic+-- side-effects of running the action, see 'mapM_'.+--+-- @since 1.3.0+mapMC :: Monad m => (a -> m b) -> ConduitT a b m ()+mapMC = CC.mapM+{-# INLINE mapMC #-}++-- | Apply a monadic transformation to all elements in a chunked stream.+--+-- @since 1.3.0+mapMCE :: (Monad m, Data.Traversable.Traversable f) => (a -> m b) -> ConduitT (f a) (f b) m ()+mapMCE = CC.mapME+{-# INLINE mapMCE #-}++-- | Apply a monadic monomorphic transformation to all elements in a chunked stream.+--+-- Unlike @mapME@, this will work on types like @ByteString@ and @Text@ which+-- are @MonoFunctor@ but not @Functor@.+--+-- @since 1.3.0+omapMCE :: (Monad m, MonoTraversable mono)+ => (Element mono -> m (Element mono))+ -> ConduitT mono mono m ()+omapMCE = CC.omapME+{-# INLINE omapMCE #-}++-- | Apply the monadic function to each value in the stream, resulting in a+-- foldable value (e.g., a list). Then yield each of the individual values in+-- that foldable value separately.+--+-- Generalizes concatMapM, mapMaybeM, and mapFoldableM.+--+-- @since 1.3.0+concatMapMC :: (Monad m, MonoFoldable mono)+ => (a -> m mono)+ -> ConduitT a (Element mono) m ()+concatMapMC = CC.concatMapM+{-# INLINE concatMapMC #-}++-- | Keep only values in the stream passing a given monadic predicate.+--+-- @since 1.3.0+filterMC :: Monad m+ => (a -> m Bool)+ -> ConduitT a a m ()+filterMC = CC.filterM+{-# INLINE filterMC #-}++-- | Keep only elements in the chunked stream passing a given monadic predicate.+--+-- @since 1.3.0+filterMCE :: (Monad m, Seq.IsSequence seq) => (Element seq -> m Bool) -> ConduitT seq seq m ()+filterMCE = CC.filterME+{-# INLINE filterMCE #-}++-- | Apply a monadic action on all values in a stream.+--+-- This @Conduit@ can be used to perform a monadic side-effect for every+-- value, whilst passing the value through the @Conduit@ as-is.+--+-- > iterM f = mapM (\a -> f a >>= \() -> return a)+--+-- @since 1.3.0+iterMC :: Monad m => (a -> m ()) -> ConduitT a a m ()+iterMC = CC.iterM+{-# INLINE iterMC #-}++-- | Analog of 'Prelude.scanl' for lists, monadic.+--+-- @since 1.3.0+scanlMC :: Monad m => (a -> b -> m a) -> a -> ConduitT b a m ()+scanlMC = CC.scanlM+{-# INLINE scanlMC #-}++-- | Monadic `mapAccumWhileC`.+mapAccumWhileMC :: Monad m => (a -> s -> m (Either s (s, b))) -> s -> ConduitT a b m s+mapAccumWhileMC = CC.mapAccumWhileM+{-# INLINE mapAccumWhileMC #-}++-- | 'concatMapM' with an accumulator.+--+-- @since 1.3.0+concatMapAccumMC :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> ConduitT a b m ()+concatMapAccumMC = CC.concatMapAccumM+{-# INLINE concatMapAccumMC #-}++-- | Encode a stream of text as UTF8.+--+-- @since 1.3.0+encodeUtf8C :: (Monad m, DTE.Utf8 text binary) => ConduitT text binary m ()+encodeUtf8C = CC.encodeUtf8+{-# INLINE encodeUtf8C #-}++-- | Decode a stream of binary data as UTF8.+--+-- @since 1.3.0+decodeUtf8C :: MonadThrow m => ConduitT ByteString Text m ()+decodeUtf8C = CC.decodeUtf8+{-# INLINE decodeUtf8C #-}++-- | Decode a stream of binary data as UTF8, replacing any invalid bytes with+-- the Unicode replacement character.+--+-- @since 1.3.0+decodeUtf8LenientC :: Monad m => ConduitT ByteString Text m ()+decodeUtf8LenientC = CC.decodeUtf8Lenient+{-# INLINE decodeUtf8LenientC #-}++-- | Stream in the entirety of a single line.+--+-- Like @takeExactly@, this will consume the entirety of the line regardless of+-- the behavior of the inner Conduit.+--+-- @since 1.3.0+lineC :: (Monad m, Seq.IsSequence seq, Element seq ~ Char)+ => ConduitT seq o m r+ -> ConduitT seq o m r+lineC = CC.line+{-# INLINE lineC #-}++-- | Same as 'line', but operates on ASCII/binary data.+--+-- @since 1.3.0+lineAsciiC :: (Monad m, Seq.IsSequence seq, Element seq ~ Word8)+ => ConduitT seq o m r+ -> ConduitT seq o m r+lineAsciiC = CC.lineAscii+{-# INLINE lineAsciiC #-}++-- | Insert a newline character after each incoming chunk of data.+--+-- @since 1.3.0+unlinesC :: (Monad m, Seq.IsSequence seq, Element seq ~ Char) => ConduitT seq seq m ()+unlinesC = CC.unlines+{-# INLINE unlinesC #-}++-- | Same as 'unlines', but operates on ASCII/binary data.+--+-- @since 1.3.0+unlinesAsciiC :: (Monad m, Seq.IsSequence seq, Element seq ~ Word8) => ConduitT seq seq m ()+unlinesAsciiC = CC.unlinesAscii+{-# INLINE unlinesAsciiC #-}++-- | Convert a stream of arbitrarily-chunked textual data into a stream of data+-- where each chunk represents a single line. Note that, if you have+-- unknown/untrusted input, this function is /unsafe/, since it would allow an+-- attacker to form lines of massive length and exhaust memory.+--+-- @since 1.3.0+linesUnboundedC :: (Monad m, Seq.IsSequence seq, Element seq ~ Char)+ => ConduitT seq seq m ()+linesUnboundedC = CC.linesUnbounded+{-# INLINE linesUnboundedC #-}++-- | Same as 'linesUnbounded', but for ASCII/binary data.+--+-- @since 1.3.0+linesUnboundedAsciiC :: (Monad m, Seq.IsSequence seq, Element seq ~ Word8)+ => ConduitT seq seq m ()+linesUnboundedAsciiC = CC.linesUnboundedAscii+{-# INLINE linesUnboundedAsciiC #-}++-- | Generally speaking, yielding values from inside a Conduit requires+-- some allocation for constructors. This can introduce an overhead,+-- similar to the overhead needed to represent a list of values instead of+-- a vector. This overhead is even more severe when talking about unboxed+-- values.+--+-- This combinator allows you to overcome this overhead, and efficiently+-- fill up vectors. It takes two parameters. The first is the size of each+-- mutable vector to be allocated. The second is a function. The function+-- takes an argument which will yield the next value into a mutable+-- vector.+--+-- Under the surface, this function uses a number of tricks to get high+-- performance. For more information on both usage and implementation,+-- please see:+-- <https://www.fpcomplete.com/user/snoyberg/library-documentation/vectorbuilder>+--+-- @since 1.3.0+vectorBuilderC :: (PrimMonad m, V.Vector v e, PrimMonad n, PrimState m ~ PrimState n)+ => Int -- ^ size+ -> ((e -> n ()) -> ConduitT i Void m r)+ -> ConduitT i (v e) m r+vectorBuilderC = CC.vectorBuilder+{-# INLINE vectorBuilderC #-}
+ src/Data/Conduit/Internal.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE Safe #-}+{-# OPTIONS_HADDOCK not-home #-}+module Data.Conduit.Internal+ ( -- * Pipe+ module Data.Conduit.Internal.Pipe+ -- * Conduit+ , module Data.Conduit.Internal.Conduit+ -- * Fusion (highly experimental!!!)+ , module Data.Conduit.Internal.Fusion+ ) where++import Data.Conduit.Internal.Conduit hiding (await,+ awaitForever, bracketP,+ leftover, mapInput, mapOutput,+ mapOutputMaybe, transPipe,+ yield, yieldM)+import Data.Conduit.Internal.Pipe+import Data.Conduit.Internal.Fusion
+ src/Data/Conduit/Internal/Conduit.hs view
@@ -0,0 +1,1232 @@+{-# OPTIONS_HADDOCK not-home #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE TypeFamilies #-}+module Data.Conduit.Internal.Conduit+ ( -- ** Types+ ConduitT (..)+ , ConduitM+ , Source+ , Producer+ , Sink+ , Consumer+ , Conduit+ , Flush (..)+ -- *** Newtype wrappers+ , ZipSource (..)+ , ZipSink (..)+ , ZipConduit (..)+ -- ** Sealed+ , SealedConduitT (..)+ , sealConduitT+ , unsealConduitT+ -- ** Primitives+ , await+ , awaitForever+ , yield+ , yieldM+ , leftover+ , runConduit+ , fuse+ , connect+ -- ** Composition+ , connectResume+ , connectResumeConduit+ , fuseLeftovers+ , fuseReturnLeftovers+ , ($$+)+ , ($$++)+ , ($$+-)+ , ($=+)+ , (=$$+)+ , (=$$++)+ , (=$$+-)+ , ($$)+ , ($=)+ , (=$)+ , (=$=)+ , (.|)+ -- ** Generalizing+ , sourceToPipe+ , sinkToPipe+ , conduitToPipe+ , toProducer+ , toConsumer+ -- ** Cleanup+ , bracketP+ -- ** Exceptions+ , catchC+ , handleC+ , tryC+ -- ** Utilities+ , Data.Conduit.Internal.Conduit.transPipe+ , Data.Conduit.Internal.Conduit.mapOutput+ , Data.Conduit.Internal.Conduit.mapOutputMaybe+ , Data.Conduit.Internal.Conduit.mapInput+ , zipSinks+ , zipSources+ , zipSourcesApp+ , zipConduitApp+ , mergeSource+ , passthroughSink+ , sourceToList+ , fuseBoth+ , fuseBothMaybe+ , fuseUpstream+ , sequenceSources+ , sequenceSinks+ , sequenceConduits+ ) where++import Control.Applicative (Applicative (..))+import Control.Exception (Exception)+import qualified Control.Exception as E (catch)+import Control.Monad (liftM, liftM2, ap)+import Control.Monad.Error.Class(MonadError(..))+import Control.Monad.Reader.Class(MonadReader(..))+import Control.Monad.RWS.Class(MonadRWS())+import Control.Monad.Writer.Class(MonadWriter(..), censor)+import Control.Monad.State.Class(MonadState(..))+import Control.Monad.Trans.Class (MonadTrans (lift))+import Control.Monad.IO.Unlift (MonadIO (liftIO), MonadUnliftIO, withRunInIO)+import Control.Monad.Primitive (PrimMonad, PrimState, primitive)+import Data.Void (Void, absurd)+import Data.Monoid (Monoid (mappend, mempty))+import Data.Semigroup (Semigroup ((<>)))+import Control.Monad.Trans.Resource+import Data.Conduit.Internal.Pipe hiding (yield, mapOutput, leftover, yieldM, await, awaitForever, bracketP)+import qualified Data.Conduit.Internal.Pipe as CI+import Control.Monad (forever)+import Data.Traversable (Traversable (..))++-- | 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 ConduitT i o m r = ConduitT+ { unConduitT :: forall b.+ (r -> Pipe i i o () m b) -> Pipe i i o () m b+ }++-- | In order to provide for efficient monadic composition, the+-- @ConduitT@ type is implemented internally using a technique known+-- as the codensity transform. This allows for cheap appending, but+-- makes one case much more expensive: partially running a @ConduitT@+-- and that capturing the new state.+--+-- This data type is the same as @ConduitT@, but does not use the+-- codensity transform technique.+--+-- @since 1.3.0+newtype SealedConduitT i o m r = SealedConduitT (Pipe i i o () m r)++-- | Same as 'ConduitT', for backwards compat+type ConduitM = ConduitT++instance Functor (ConduitT i o m) where+ fmap f (ConduitT c) = ConduitT $ \rest -> c (rest . f)++instance Applicative (ConduitT i o m) where+ pure x = ConduitT ($ x)+ {-# INLINE pure #-}+ (<*>) = ap+ {-# INLINE (<*>) #-}++instance Monad (ConduitT i o m) where+ return = pure+ ConduitT f >>= g = ConduitT $ \h -> f $ \a -> unConduitT (g a) h++instance MonadThrow m => MonadThrow (ConduitT i o m) where+ throwM = lift . throwM++instance MonadIO m => MonadIO (ConduitT i o m) where+ liftIO = lift . liftIO+ {-# INLINE liftIO #-}++instance MonadReader r m => MonadReader r (ConduitT i o m) where+ ask = lift ask+ {-# INLINE ask #-}++ local f (ConduitT c0) = ConduitT $ \rest ->+ let go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput p c) = NeedInput (\i -> go (p i)) (\u -> go (c u))+ go (Done x) = rest x+ go (PipeM mp) = PipeM (liftM go $ local f mp)+ go (Leftover p i) = Leftover (go p) i+ in go (c0 Done)++#ifndef MIN_VERSION_mtl+#define MIN_VERSION_mtl(x, y, z) 0+#endif++instance MonadWriter w m => MonadWriter w (ConduitT i o m) where+#if MIN_VERSION_mtl(2, 1, 0)+ writer = lift . writer+#endif+ tell = lift . tell++ listen (ConduitT c0) = ConduitT $ \rest ->+ let go front (HaveOutput p o) = HaveOutput (go front p) o+ go front (NeedInput p c) = NeedInput (\i -> go front (p i)) (\u -> go front (c u))+ go front (Done x) = rest (x, front)+ go front (PipeM mp) = PipeM $ do+ (p,w) <- listen mp+ return $ go (front `mappend` w) p+ go front (Leftover p i) = Leftover (go front p) i+ in go mempty (c0 Done)++ pass (ConduitT c0) = ConduitT $ \rest ->+ let go front (HaveOutput p o) = HaveOutput (go front p) o+ go front (NeedInput p c) = NeedInput (\i -> go front (p i)) (\u -> go front (c u))+ go front (PipeM mp) = PipeM $ do+ (p,w) <- censor (const mempty) (listen mp)+ return $ go (front `mappend` w) p+ go front (Done (x,f)) = PipeM $ do+ tell (f front)+ return $ rest x+ go front (Leftover p i) = Leftover (go front p) i+ in go mempty (c0 Done)++instance MonadState s m => MonadState s (ConduitT i o m) where+ get = lift get+ put = lift . put+#if MIN_VERSION_mtl(2, 1, 0)+ state = lift . state+#endif++instance MonadRWS r w s m => MonadRWS r w s (ConduitT i o m)++instance MonadError e m => MonadError e (ConduitT i o m) where+ throwError = lift . throwError+ catchError (ConduitT c0) f = ConduitT $ \rest ->+ let go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput p c) = NeedInput (\i -> go (p i)) (\u -> go (c u))+ go (Done x) = rest x+ go (PipeM mp) =+ PipeM $ catchError (liftM go mp) $ \e -> do+ return $ unConduitT (f e) rest+ go (Leftover p i) = Leftover (go p) i+ in go (c0 Done)++instance MonadTrans (ConduitT i o) where+ lift mr = ConduitT $ \rest -> PipeM (liftM rest mr)+ {-# INLINE [1] lift #-}++instance MonadResource m => MonadResource (ConduitT i o m) where+ liftResourceT = lift . liftResourceT+ {-# INLINE liftResourceT #-}++instance Monad m => Semigroup (ConduitT i o m ()) where+ (<>) = (>>)+ {-# INLINE (<>) #-}++instance Monad m => Monoid (ConduitT i o m ()) where+ mempty = return ()+ {-# INLINE mempty #-}+#if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ {-# INLINE mappend #-}+#endif++instance PrimMonad m => PrimMonad (ConduitT i o m) where+ type PrimState (ConduitT i o m) = PrimState m+ primitive = lift . primitive++-- | Provides a stream of output values, without consuming any input or+-- producing a final result.+--+-- Since 0.5.0+type Source m o = ConduitT () o m ()+{-# DEPRECATED Source "Use ConduitT directly" #-}++-- | 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 1.0.0+type Producer m o = forall i. ConduitT i o m ()+{-# DEPRECATED Producer "Use ConduitT directly" #-}++-- | Consumes a stream of input values and produces a final result, without+-- producing any output.+--+-- > type Sink i m r = ConduitT i Void m r+--+-- Since 0.5.0+type Sink i = ConduitT i Void+{-# DEPRECATED Sink "Use ConduitT directly" #-}++-- | 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 1.0.0+type Consumer i m r = forall o. ConduitT i o m r+{-# DEPRECATED Consumer "Use ConduitT directly" #-}++-- | Consumes a stream of input values and produces a stream of output values,+-- without producing a final result.+--+-- Since 0.5.0+type Conduit i m o = ConduitT i o m ()+{-# DEPRECATED Conduit "Use ConduitT directly" #-}++sealConduitT :: ConduitT i o m r -> SealedConduitT i o m r+sealConduitT (ConduitT f) = SealedConduitT (f Done)++unsealConduitT :: Monad m => SealedConduitT i o m r -> ConduitT i o m r+unsealConduitT (SealedConduitT f) = ConduitT (f >>=)++-- | Connect a @Source@ to a @Sink@ until the latter closes. Returns both the+-- most recent state of the @Source@ and the result of the @Sink@.+--+-- Since 0.5.0+connectResume :: Monad m+ => SealedConduitT () a m ()+ -> ConduitT a Void m r+ -> m (SealedConduitT () a m (), r)+connectResume (SealedConduitT left0) (ConduitT right0) =+ goRight left0 (right0 Done)+ where+ goRight left right =+ case right of+ HaveOutput _ o -> absurd o+ NeedInput rp rc -> goLeft rp rc left+ Done r2 -> return (SealedConduitT left, r2)+ PipeM mp -> mp >>= goRight left+ Leftover p i -> goRight (HaveOutput left i) p++ goLeft rp rc left =+ case left of+ HaveOutput left' o -> goRight left' (rp o)+ NeedInput _ lc -> recurse (lc ())+ Done () -> goRight (Done ()) (rc ())+ PipeM mp -> mp >>= recurse+ Leftover p () -> recurse p+ where+ recurse = goLeft rp rc++sourceToPipe :: Monad m => Source m o -> Pipe l i o u m ()+sourceToPipe =+ go . flip unConduitT Done+ where+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput _ c) = go $ c ()+ go (Done ()) = Done ()+ go (PipeM mp) = PipeM (liftM go mp)+ go (Leftover p ()) = go p++sinkToPipe :: Monad m => Sink i m r -> Pipe l i o u m r+sinkToPipe =+ go . injectLeftovers . flip unConduitT Done+ where+ go (HaveOutput _ o) = absurd o+ go (NeedInput p c) = NeedInput (go . p) (const $ go $ c ())+ go (Done r) = Done r+ go (PipeM mp) = PipeM (liftM go mp)+ go (Leftover _ l) = absurd l++conduitToPipe :: Monad m => Conduit i m o -> Pipe l i o u m ()+conduitToPipe =+ go . injectLeftovers . flip unConduitT Done+ where+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput p c) = NeedInput (go . p) (const $ go $ c ())+ go (Done ()) = Done ()+ go (PipeM mp) = PipeM (liftM go mp)+ go (Leftover _ l) = absurd l++-- | Generalize a 'Source' to a 'Producer'.+--+-- Since 1.0.0+toProducer :: Monad m => Source m a -> Producer m a+toProducer (ConduitT c0) = ConduitT $ \rest -> let+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput _ c) = go (c ())+ go (Done r) = rest r+ go (PipeM mp) = PipeM (liftM go mp)+ go (Leftover p ()) = go p+ in go (c0 Done)++-- | Generalize a 'Sink' to a 'Consumer'.+--+-- Since 1.0.0+toConsumer :: Monad m => Sink a m b -> Consumer a m b+toConsumer (ConduitT c0) = ConduitT $ \rest -> let+ go (HaveOutput _ o) = absurd o+ go (NeedInput p c) = NeedInput (go . p) (go . c)+ go (Done r) = rest r+ go (PipeM mp) = PipeM (liftM go mp)+ go (Leftover p l) = Leftover (go p) l+ in go (c0 Done)++-- | Catch all exceptions thrown by the current component of the pipeline.+--+-- Note: this will /not/ catch exceptions thrown by other components! For+-- example, if an exception is thrown in a @Source@ feeding to a @Sink@, and+-- the @Sink@ uses @catchC@, the exception will /not/ be caught.+--+-- Due to this behavior (as well as lack of async exception safety), you+-- should not try to implement combinators such as @onException@ in terms of this+-- primitive function.+--+-- Note also that the exception handling will /not/ be applied to any+-- finalizers generated by this conduit.+--+-- Since 1.0.11+catchC :: (MonadUnliftIO m, Exception e)+ => ConduitT i o m r+ -> (e -> ConduitT i o m r)+ -> ConduitT i o m r+catchC (ConduitT p0) onErr = ConduitT $ \rest -> let+ go (Done r) = rest r+ go (PipeM mp) = PipeM $ withRunInIO $ \run -> E.catch (run (liftM go mp))+ (return . flip unConduitT rest . onErr)+ go (Leftover p i) = Leftover (go p) i+ go (NeedInput x y) = NeedInput (go . x) (go . y)+ go (HaveOutput p o) = HaveOutput (go p) o+ in go (p0 Done)+{-# INLINE catchC #-}++-- | The same as @flip catchC@.+--+-- Since 1.0.11+handleC :: (MonadUnliftIO m, Exception e)+ => (e -> ConduitT i o m r)+ -> ConduitT i o m r+ -> ConduitT i o m r+handleC = flip catchC+{-# INLINE handleC #-}++-- | A version of @try@ for use within a pipeline. See the comments in @catchC@+-- for more details.+--+-- Since 1.0.11+tryC :: (MonadUnliftIO m, Exception e)+ => ConduitT i o m r+ -> ConduitT i o m (Either e r)+tryC c = fmap Right c `catchC` (return . Left)+{-# INLINE tryC #-}++-- | Combines two sinks. The new sink will complete when both input sinks have+-- completed.+--+-- Any leftovers are discarded.+--+-- Since 0.4.1+zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')+zipSinks (ConduitT x0) (ConduitT y0) = ConduitT $ \rest -> let+ Leftover _ i >< _ = absurd i+ _ >< Leftover _ i = absurd i+ HaveOutput _ o >< _ = absurd o+ _ >< HaveOutput _ o = absurd o++ PipeM mx >< y = PipeM (liftM (>< y) mx)+ x >< PipeM my = PipeM (liftM (x ><) my)+ Done x >< Done y = rest (x, y)+ 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)+ in injectLeftovers (x0 Done) >< injectLeftovers (y0 Done)++-- | Combines two sources. The new source will stop producing once either+-- source has been exhausted.+--+-- Since 1.0.13+zipSources :: Monad m => Source m a -> Source m b -> Source m (a, b)+zipSources (ConduitT left0) (ConduitT right0) = ConduitT $ \rest -> let+ go (Leftover left ()) right = go left right+ go left (Leftover right ()) = go left right+ go (Done ()) (Done ()) = rest ()+ go (Done ()) (HaveOutput _ _) = rest ()+ go (HaveOutput _ _) (Done ()) = rest ()+ go (Done ()) (PipeM _) = rest ()+ go (PipeM _) (Done ()) = rest ()+ go (PipeM mx) (PipeM my) = PipeM (liftM2 go mx my)+ go (PipeM mx) y@HaveOutput{} = PipeM (liftM (\x -> go x y) mx)+ go x@HaveOutput{} (PipeM my) = PipeM (liftM (go x) my)+ go (HaveOutput srcx x) (HaveOutput srcy y) = HaveOutput (go srcx srcy) (x, y)+ go (NeedInput _ c) right = go (c ()) right+ go left (NeedInput _ c) = go left (c ())+ in go (left0 Done) (right0 Done)++-- | Combines two sources. The new source will stop producing once either+-- source has been exhausted.+--+-- Since 1.0.13+zipSourcesApp :: Monad m => Source m (a -> b) -> Source m a -> Source m b+zipSourcesApp (ConduitT left0) (ConduitT right0) = ConduitT $ \rest -> let+ go (Leftover left ()) right = go left right+ go left (Leftover right ()) = go left right+ go (Done ()) (Done ()) = rest ()+ go (Done ()) (HaveOutput _ _) = rest ()+ go (HaveOutput _ _) (Done ()) = rest ()+ go (Done ()) (PipeM _) = rest ()+ go (PipeM _) (Done ()) = rest ()+ go (PipeM mx) (PipeM my) = PipeM (liftM2 go mx my)+ go (PipeM mx) y@HaveOutput{} = PipeM (liftM (\x -> go x y) mx)+ go x@HaveOutput{} (PipeM my) = PipeM (liftM (go x) my)+ go (HaveOutput srcx x) (HaveOutput srcy y) = HaveOutput (go srcx srcy) (x y)+ go (NeedInput _ c) right = go (c ()) right+ go left (NeedInput _ c) = go left (c ())+ in go (left0 Done) (right0 Done)++-- |+--+-- Since 1.0.17+zipConduitApp+ :: Monad m+ => ConduitT i o m (x -> y)+ -> ConduitT i o m x+ -> ConduitT i o m y+zipConduitApp (ConduitT left0) (ConduitT right0) = ConduitT $ \rest -> let+ go (Done f) (Done x) = rest (f x)+ go (PipeM mx) y = PipeM (flip go y `liftM` mx)+ go x (PipeM my) = PipeM (go x `liftM` my)+ go (HaveOutput x o) y = HaveOutput (go x y) o+ go x (HaveOutput y o) = HaveOutput (go x y) o+ go (Leftover _ i) _ = absurd i+ go _ (Leftover _ i) = absurd i+ go (NeedInput px cx) (NeedInput py cy) = NeedInput+ (\i -> go (px i) (py i))+ (\u -> go (cx u) (cy u))+ go (NeedInput px cx) (Done y) = NeedInput+ (\i -> go (px i) (Done y))+ (\u -> go (cx u) (Done y))+ go (Done x) (NeedInput py cy) = NeedInput+ (\i -> go (Done x) (py i))+ (\u -> go (Done x) (cy u))+ in go (injectLeftovers $ left0 Done) (injectLeftovers $ right0 Done)++-- | Same as normal fusion (e.g. @=$=@), except instead of discarding leftovers+-- from the downstream component, return them.+--+-- Since 1.0.17+fuseReturnLeftovers :: Monad m+ => ConduitT a b m ()+ -> ConduitT b c m r+ -> ConduitT a c m (r, [b])+fuseReturnLeftovers (ConduitT left0) (ConduitT right0) = ConduitT $ \rest -> let+ goRight bs left right =+ case right of+ HaveOutput p o -> HaveOutput (recurse p) o+ NeedInput rp rc ->+ case bs of+ [] -> goLeft rp rc left+ b:bs' -> goRight bs' left (rp b)+ Done r2 -> rest (r2, bs)+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover p b -> goRight (b:bs) left p+ where+ recurse = goRight bs left++ goLeft rp rc left =+ case left of+ HaveOutput left' o -> goRight [] left' (rp o)+ NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)+ Done r1 -> goRight [] (Done r1) (rc r1)+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover left' i -> Leftover (recurse left') i+ where+ recurse = goLeft rp rc+ in goRight [] (left0 Done) (right0 Done)++-- | Similar to @fuseReturnLeftovers@, but use the provided function to convert+-- downstream leftovers to upstream leftovers.+--+-- Since 1.0.17+fuseLeftovers+ :: Monad m+ => ([b] -> [a])+ -> ConduitT a b m ()+ -> ConduitT b c m r+ -> ConduitT a c m r+fuseLeftovers f left right = do+ (r, bs) <- fuseReturnLeftovers left right+ mapM_ leftover $ reverse $ f bs+ return r++-- | Connect a 'Conduit' to a sink and return the output of the sink+-- together with a new 'Conduit'.+--+-- Since 1.0.17+connectResumeConduit+ :: Monad m+ => SealedConduitT i o m ()+ -> ConduitT o Void m r+ -> ConduitT i Void m (SealedConduitT i o m (), r)+connectResumeConduit (SealedConduitT left0) (ConduitT right0) = ConduitT $ \rest -> let+ goRight left right =+ case right of+ HaveOutput _ o -> absurd o+ NeedInput rp rc -> goLeft rp rc left+ Done r2 -> rest (SealedConduitT left, r2)+ PipeM mp -> PipeM (liftM (goRight left) mp)+ Leftover p i -> goRight (HaveOutput left i) p++ goLeft rp rc left =+ case left of+ HaveOutput left' o -> goRight left' (rp o)+ NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)+ Done () -> goRight (Done ()) (rc ())+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover left' i -> Leftover (recurse left') i -- recurse p+ where+ recurse = goLeft rp rc+ in goRight left0 (right0 Done)++-- | Merge a @Source@ into a @Conduit@.+-- The new conduit will stop processing once either source or upstream have been exhausted.+mergeSource+ :: Monad m+ => Source m i+ -> Conduit a m (i, a)+mergeSource = loop . sealConduitT+ where+ loop :: Monad m => SealedConduitT () i m () -> Conduit a m (i, a)+ loop src0 = await >>= maybe (return ()) go+ where+ go a = do+ (src1, mi) <- lift $ src0 $$++ await+ case mi of+ Nothing -> return ()+ Just i -> yield (i, a) >> loop src1+++-- | 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.1.0+passthroughSink :: Monad m+ => Sink i m r+ -> (r -> m ()) -- ^ finalizer+ -> Conduit i m i+passthroughSink (ConduitT sink0) final = ConduitT $ \rest -> let+ -- A bit of explanation is in order, this function is+ -- non-obvious. The purpose of go is to keep track of the sink+ -- we're passing values to, and then yield values downstream. The+ -- third argument to go is the current state of that sink. That's+ -- relatively straightforward.+ --+ -- The second value is the leftover buffer. These are values that+ -- the sink itself has called leftover on, and must be provided+ -- back to the sink the next time it awaits. _However_, these+ -- values should _not_ be reyielded downstream: we have already+ -- yielded them downstream ourself, and it is the responsibility+ -- of the functions wrapping around passthroughSink to handle the+ -- leftovers from downstream.+ --+ -- The trickiest bit is the first argument, which is a solution to+ -- bug https://github.com/snoyberg/conduit/issues/304. The issue+ -- is that, once we get a value, we need to provide it to both the+ -- inner sink _and_ yield it downstream. The obvious thing to do+ -- is yield first and then recursively call go. Unfortunately,+ -- this doesn't work in all cases: if the downstream component+ -- never calls await again, our yield call will never return, and+ -- our sink will not get the last value. This results is confusing+ -- behavior where the sink and downstream component receive a+ -- different number of values.+ --+ -- Solution: keep a buffer of the next value to yield downstream,+ -- and only yield it downstream in one of two cases: our sink is+ -- asking for another value, or our sink is done. This way, we+ -- ensure that, in all cases, we pass exactly the same number of+ -- values to the inner sink as to downstream.++ go mbuf _ (Done r) = do+ maybe (return ()) CI.yield mbuf+ lift $ final r+ unConduitT (awaitForever yield) rest+ go mbuf is (Leftover sink i) = go mbuf (i:is) sink+ go _ _ (HaveOutput _ o) = absurd o+ go mbuf is (PipeM mx) = do+ x <- lift mx+ go mbuf is x+ go mbuf (i:is) (NeedInput next _) = go mbuf is (next i)+ go mbuf [] (NeedInput next done) = do+ maybe (return ()) CI.yield mbuf+ mx <- CI.await+ case mx of+ Nothing -> go Nothing [] (done ())+ Just x -> go (Just x) [] (next x)+ in go Nothing [] (sink0 Done)++-- | Convert a @Source@ into a list. The basic functionality can be explained as:+--+-- > sourceToList src = src $$ Data.Conduit.List.consume+--+-- However, @sourceToList@ is able to produce its results lazily, which cannot+-- be done when running a conduit pipeline in general. Unlike the+-- @Data.Conduit.Lazy@ module (in conduit-extra), this function performs no+-- unsafe I\/O operations, and therefore can only be as lazily as the+-- underlying monad.+--+-- Since 1.2.6+sourceToList :: Monad m => Source m a -> m [a]+sourceToList =+ go . flip unConduitT Done+ where+ go (Done _) = return []+ go (HaveOutput src x) = liftM (x:) (go src)+ go (PipeM msrc) = msrc >>= go+ go (NeedInput _ c) = go (c ())+ go (Leftover p _) = go p++-- Define fixity of all our operators+infixr 0 $$+infixl 1 $=+infixr 2 =$+infixr 2 =$=+infixr 0 $$++infixr 0 $$+++infixr 0 $$+-+infixl 1 $=++infixr 2 .|++-- | Equivalent to using 'runConduit' and '.|' together.+--+-- Since 1.2.3+connect :: Monad m+ => ConduitT () a m ()+ -> ConduitT a Void m r+ -> m r+connect = ($$)++-- | Named function synonym for '.|'.+--+-- Since 1.2.3+fuse :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r+fuse = (=$=)++-- | Combine two @Conduit@s together into a new @Conduit@ (aka 'fuse').+--+-- Output from the upstream (left) conduit will be fed into the+-- downstream (right) conduit. Processing will terminate when+-- downstream (right) returns. Leftover data returned from the right+-- @Conduit@ will be discarded.+--+-- @since 1.2.8+(.|) :: Monad m+ => ConduitM a b m () -- ^ upstream+ -> ConduitM b c m r -- ^ downstream+ -> ConduitM a c m r+(.|) = fuse+{-# INLINE (.|) #-}++-- | The connect operator, which pulls data from a source and pushes to a sink.+-- 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+($$) :: Monad m => Source m a -> Sink a m b -> m b+src $$ sink = do+ (rsrc, res) <- src $$+ sink+ rsrc $$+- return ()+ return res+{-# INLINE [1] ($$) #-}+{-# DEPRECATED ($$) "Use runConduit and .|" #-}++-- | A synonym for '=$=' for backwards compatibility.+--+-- Since 0.4.0+($=) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r+($=) = (=$=)+{-# INLINE [0] ($=) #-}+{-# RULES "conduit: $= is =$=" ($=) = (=$=) #-}+{-# DEPRECATED ($=) "Use .|" #-}++-- | A synonym for '=$=' for backwards compatibility.+--+-- Since 0.4.0+(=$) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r+(=$) = (=$=)+{-# INLINE [0] (=$) #-}+{-# RULES "conduit: =$ is =$=" (=$) = (=$=) #-}+{-# DEPRECATED (=$) "Use .|" #-}++-- | Fusion operator, combining two @Conduit@s together into a new @Conduit@.+--+-- Both @Conduit@s will be closed when the newly-created @Conduit@ is closed.+--+-- Leftover data returned from the right @Conduit@ will be discarded.+--+-- Since 0.4.0+(=$=) :: Monad m => Conduit a m b -> ConduitT b c m r -> ConduitT a c m r+ConduitT left0 =$= ConduitT right0 = ConduitT $ \rest ->+ let goRight left right =+ case right of+ HaveOutput p o -> HaveOutput (recurse p) o+ NeedInput rp rc -> goLeft rp rc left+ Done r2 -> rest r2+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover right' i -> goRight (HaveOutput left i) right'+ where+ recurse = goRight left++ goLeft rp rc left =+ case left of+ HaveOutput left' o -> goRight left' (rp o)+ NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)+ Done r1 -> goRight (Done r1) (rc r1)+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover left' i -> Leftover (recurse left') i+ where+ recurse = goLeft rp rc+ in goRight (left0 Done) (right0 Done)+ where+{-# INLINE [1] (=$=) #-}+{-# DEPRECATED (=$=) "Use .|" #-}++-- | Wait for a single input value from upstream. If no data is available,+-- returns @Nothing@. Once @await@ returns @Nothing@, subsequent calls will+-- also return @Nothing@.+--+-- Since 0.5.0+await :: Monad m => Consumer i m (Maybe i)+await = ConduitT $ \f -> NeedInput (f . Just) (const $ f Nothing)+{-# INLINE [0] await #-}++await' :: Monad m+ => ConduitT i o m r+ -> (i -> ConduitT i o m r)+ -> ConduitT i o m r+await' f g = ConduitT $ \rest -> NeedInput+ (\i -> unConduitT (g i) rest)+ (const $ unConduitT f rest)+{-# INLINE await' #-}+{-# RULES "conduit: await >>= maybe" forall x y. await >>= maybe x y = await' x y #-}++-- | Send a value downstream to the next component to consume. If the+-- downstream component terminates, this call will never return control.+--+-- Since 0.5.0+yield :: Monad m+ => o -- ^ output value+ -> ConduitT i o m ()+yield o = ConduitT $ \rest -> HaveOutput (rest ()) o+{-# INLINE yield #-}++-- | Send a monadic value downstream for the next component to consume.+--+-- @since 1.2.7+yieldM :: Monad m => m o -> ConduitT i o m ()+yieldM mo = lift mo >>= yield+{-# INLINE yieldM #-}++ -- FIXME rule won't fire, see FIXME in .Pipe; "mapM_ yield" mapM_ yield = ConduitT . sourceList++-- | 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 -> ConduitT i o m ()+leftover i = ConduitT $ \rest -> Leftover (rest ()) i+{-# INLINE leftover #-}++-- | Run a pipeline until processing completes.+--+-- Since 1.2.1+runConduit :: Monad m => ConduitT () Void m r -> m r+runConduit (ConduitT p) = runPipe $ injectLeftovers $ p Done+{-# INLINE [0] runConduit #-}++-- | Bracket a conduit computation between allocation and release of a+-- resource. 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+ -- ^ computation to run first (\"acquire resource\")+ -> (a -> IO ())+ -- ^ computation to run last (\"release resource\")+ -> (a -> ConduitT i o m r)+ -- ^ computation to run in-between+ -> ConduitT i o m r+ -- returns the value from the in-between computation+bracketP alloc free inside = ConduitT $ \rest -> do+ (key, seed) <- allocate alloc free+ unConduitT (inside seed) $ \res -> do+ release key+ rest res++-- | Wait for input forever, calling the given inner component for each piece of+-- new input.+--+-- 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 -> ConduitT i o m r) -> ConduitT i o m ()+awaitForever f = ConduitT $ \rest ->+ let go = NeedInput (\i -> unConduitT (f i) (const go)) rest+ in go++-- | Transform the monad that a @ConduitT@ 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) -> ConduitT i o m r -> ConduitT i o n r+transPipe f (ConduitT c0) = ConduitT $ \rest -> let+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput p c) = NeedInput (go . p) (go . c)+ go (Done r) = rest r+ go (PipeM mp) =+ PipeM (f $ liftM go $ collapse mp)+ where+ -- Combine a series of monadic actions into a single action. Since we+ -- throw away side effects between different actions, an arbitrary break+ -- between actions will lead to a violation of the monad transformer laws.+ -- Example available at:+ --+ -- http://hpaste.org/75520+ collapse mpipe = do+ pipe' <- mpipe+ case pipe' of+ PipeM mpipe' -> collapse mpipe'+ _ -> return pipe'+ go (Leftover p i) = Leftover (go p) i+ in go (c0 Done)++-- | Apply a function to all the output values of a @ConduitT@.+--+-- 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) -> ConduitT i o1 m r -> ConduitT i o2 m r+mapOutput f (ConduitT c0) = ConduitT $ \rest -> let+ go (HaveOutput p o) = HaveOutput (go p) (f o)+ go (NeedInput p c) = NeedInput (go . p) (go . c)+ go (Done r) = rest r+ go (PipeM mp) = PipeM (liftM (go) mp)+ go (Leftover p i) = Leftover (go p) i+ in go (c0 Done)++-- | Same as 'mapOutput', but use a function that returns @Maybe@ values.+--+-- Since 0.5.0+mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> ConduitT i o1 m r -> ConduitT i o2 m r+mapOutputMaybe f (ConduitT c0) = ConduitT $ \rest -> let+ go (HaveOutput p o) = maybe id (\o' p' -> HaveOutput p' o') (f o) (go p)+ go (NeedInput p c) = NeedInput (go . p) (go . c)+ go (Done r) = rest r+ go (PipeM mp) = PipeM (liftM (go) mp)+ go (Leftover p i) = Leftover (go p) i+ in go (c0 Done)++-- | Apply a function to all the input values of a @ConduitT@.+--+-- Since 0.5.0+mapInput :: Monad m+ => (i1 -> i2) -- ^ map initial input to new input+ -> (i2 -> Maybe i1) -- ^ map new leftovers to initial leftovers+ -> ConduitT i2 o m r+ -> ConduitT i1 o m r+mapInput f f' (ConduitT c0) = ConduitT $ \rest -> let+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput p c) = NeedInput (go . p . f) (go . c)+ go (Done r) = rest r+ go (PipeM mp) = PipeM $ liftM go mp+ go (Leftover p i) = maybe id (flip Leftover) (f' i) (go p)+ in go (c0 Done)++-- | 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+-- in the @Sink@ monad.+--+-- Mnemonic: connect + do more.+--+-- Since 0.5.0+($$+) :: Monad m => Source m a -> Sink a m b -> m (SealedConduitT () a m (), b)+src $$+ sink = connectResume (sealConduitT src) sink+{-# INLINE ($$+) #-}++-- | Continue processing after usage of @$$+@.+--+-- Since 0.5.0+($$++) :: Monad m => SealedConduitT () a m () -> Sink a m b -> m (SealedConduitT () a m (), b)+($$++) = connectResume+{-# INLINE ($$++) #-}++-- | Same as @$$++@ and @connectResume@, but doesn't include the+-- updated @SealedConduitT@.+--+-- /NOTE/ In previous versions, this would cause finalizers to+-- run. Since version 1.3.0, there are no finalizers in conduit.+--+-- Since 0.5.0+($$+-) :: Monad m => SealedConduitT () a m () -> Sink a m b -> m b+rsrc $$+- sink = do+ (_, res) <- connectResume rsrc sink+ return res+{-# INLINE ($$+-) #-}++-- | Left fusion for a sealed source.+--+-- Since 1.0.16+($=+) :: Monad m => SealedConduitT () a m () -> Conduit a m b -> SealedConduitT () b m ()+SealedConduitT src $=+ ConduitT sink = SealedConduitT (src `pipeL` sink Done)++-- | Provide for a stream of data that can be flushed.+--+-- A number of @Conduit@s (e.g., zlib compression) need the ability to flush+-- the stream at some point. This provides a single wrapper datatype to be used+-- in all such circumstances.+--+-- Since 0.3.0+data Flush a = Chunk a | Flush+ deriving (Show, Eq, Ord)+instance Functor Flush where+ fmap _ Flush = Flush+ fmap f (Chunk a) = Chunk (f a)++-- | A wrapper for defining an 'Applicative' instance for 'Source's which allows+-- to combine sources together, generalizing 'zipSources'. A combined source+-- will take input yielded from each of its @Source@s until any of them stop+-- producing output.+--+-- Since 1.0.13+newtype ZipSource m o = ZipSource { getZipSource :: Source m o }++instance Monad m => Functor (ZipSource m) where+ fmap f = ZipSource . mapOutput f . getZipSource+instance Monad m => Applicative (ZipSource m) where+ pure = ZipSource . forever . yield+ (ZipSource f) <*> (ZipSource x) = ZipSource $ zipSourcesApp f x++-- | Coalesce all values yielded by all of the @Source@s.+--+-- Implemented on top of @ZipSource@ and as such, it exhibits the same+-- short-circuiting behavior as @ZipSource@. See that data type for more+-- details. If you want to create a source that yields *all* values from+-- multiple sources, use `sequence_`.+--+-- Since 1.0.13+sequenceSources :: (Traversable f, Monad m) => f (Source m o) -> Source m (f o)+sequenceSources = getZipSource . sequenceA . fmap ZipSource++-- | A wrapper for defining an 'Applicative' instance for 'Sink's which allows+-- to combine sinks together, generalizing 'zipSinks'. A combined sink+-- distributes the input to all its participants and when all finish, produces+-- the result. This allows to define functions like+--+-- @+-- sequenceSinks :: (Monad m)+-- => [Sink i m r] -> Sink i m [r]+-- sequenceSinks = getZipSink . sequenceA . fmap ZipSink+-- @+--+-- Note that the standard 'Applicative' instance for conduits works+-- differently. It feeds one sink with input until it finishes, then switches+-- to another, etc., and at the end combines their results.+--+-- This newtype is in fact a type constrained version of 'ZipConduit', and has+-- the same behavior. It's presented as a separate type since (1) it+-- historically predates @ZipConduit@, and (2) the type constraining can make+-- your code clearer (and thereby make your error messages more easily+-- understood).+--+-- Since 1.0.13+newtype ZipSink i m r = ZipSink { getZipSink :: Sink i m r }++instance Monad m => Functor (ZipSink i m) where+ fmap f (ZipSink x) = ZipSink (liftM f x)+instance Monad m => Applicative (ZipSink i m) where+ pure = ZipSink . return+ (ZipSink f) <*> (ZipSink x) =+ ZipSink $ liftM (uncurry ($)) $ zipSinks f x++-- | Send incoming values to all of the @Sink@ providing, and ultimately+-- coalesce together all return values.+--+-- Implemented on top of @ZipSink@, see that data type for more details.+--+-- Since 1.0.13+sequenceSinks :: (Traversable f, Monad m) => f (Sink i m r) -> Sink i m (f r)+sequenceSinks = getZipSink . sequenceA . fmap ZipSink++-- | The connect-and-resume operator. This does not close the @Conduit@, but+-- instead returns it to be used again. This allows a @Conduit@ to be used+-- incrementally in a large program, without forcing the entire program to live+-- in the @Sink@ monad.+--+-- Leftover data returned from the @Sink@ will be discarded.+--+-- Mnemonic: connect + do more.+--+-- Since 1.0.17+(=$$+) :: Monad m+ => ConduitT a b m ()+ -> ConduitT b Void m r+ -> ConduitT a Void m (SealedConduitT a b m (), r)+(=$$+) conduit = connectResumeConduit (sealConduitT conduit)+{-# INLINE (=$$+) #-}++-- | Continue processing after usage of '=$$+'. Connect a 'SealedConduitT' to+-- a sink and return the output of the sink together with a new+-- 'SealedConduitT'.+--+-- Since 1.0.17+(=$$++) :: Monad m => SealedConduitT i o m () -> ConduitT o Void m r -> ConduitT i Void m (SealedConduitT i o m (), r)+(=$$++) = connectResumeConduit+{-# INLINE (=$$++) #-}++-- | Same as @=$$++@, but doesn't include the updated+-- @SealedConduitT@.+--+-- /NOTE/ In previous versions, this would cause finalizers to+-- run. Since version 1.3.0, there are no finalizers in conduit.+--+-- Since 1.0.17+(=$$+-) :: Monad m => SealedConduitT i o m () -> ConduitT o Void m r -> ConduitT i Void m r+rsrc =$$+- sink = do+ (_, res) <- connectResumeConduit rsrc sink+ return res+{-# INLINE (=$$+-) #-}+++infixr 0 =$$++infixr 0 =$$+++infixr 0 =$$+-++-- | Provides an alternative @Applicative@ instance for @ConduitT@. In this instance,+-- every incoming value is provided to all @ConduitT@s, and output is coalesced together.+-- Leftovers from individual @ConduitT@s will be used within that component, and then discarded+-- at the end of their computation. Output and finalizers will both be handled in a left-biased manner.+--+-- As an example, take the following program:+--+-- @+-- main :: IO ()+-- main = do+-- let src = mapM_ yield [1..3 :: Int]+-- conduit1 = CL.map (+1)+-- conduit2 = CL.concatMap (replicate 2)+-- conduit = getZipConduit $ ZipConduit conduit1 <* ZipConduit conduit2+-- sink = CL.mapM_ print+-- src $$ conduit =$ sink+-- @+--+-- It will produce the output: 2, 1, 1, 3, 2, 2, 4, 3, 3+--+-- Since 1.0.17+newtype ZipConduit i o m r = ZipConduit { getZipConduit :: ConduitT i o m r }+ deriving Functor+instance Monad m => Applicative (ZipConduit i o m) where+ pure = ZipConduit . pure+ ZipConduit left <*> ZipConduit right = ZipConduit (zipConduitApp left right)++-- | Provide identical input to all of the @Conduit@s and combine their outputs+-- into a single stream.+--+-- Implemented on top of @ZipConduit@, see that data type for more details.+--+-- Since 1.0.17+sequenceConduits :: (Traversable f, Monad m) => f (ConduitT i o m r) -> ConduitT i o m (f r)+sequenceConduits = getZipConduit . sequenceA . fmap ZipConduit++-- | Fuse two @ConduitT@s together, and provide the return value of both. Note+-- that this will force the entire upstream @ConduitT@ to be run to produce the+-- result value, even if the downstream terminates early.+--+-- Since 1.1.5+fuseBoth :: Monad m => ConduitT a b m r1 -> ConduitT b c m r2 -> ConduitT a c m (r1, r2)+fuseBoth (ConduitT up) (ConduitT down) =+ ConduitT (pipeL (up Done) (withUpstream $ generalizeUpstream $ down Done) >>=)+{-# INLINE fuseBoth #-}++-- | Like 'fuseBoth', but does not force consumption of the @Producer@.+-- In the case that the @Producer@ terminates, the result value is+-- provided as a @Just@ value. If it does not terminate, then a+-- @Nothing@ value is returned.+--+-- One thing to note here is that "termination" here only occurs if the+-- @Producer@ actually yields a @Nothing@ value. For example, with the+-- @Producer@ @mapM_ yield [1..5]@, if five values are requested, the+-- @Producer@ has not yet terminated. Termination only occurs when the+-- sixth value is awaited for and the @Producer@ signals termination.+--+-- Since 1.2.4+fuseBothMaybe+ :: Monad m+ => ConduitT a b m r1+ -> ConduitT b c m r2+ -> ConduitT a c m (Maybe r1, r2)+fuseBothMaybe (ConduitT up) (ConduitT down) =+ ConduitT (pipeL (up Done) (go Nothing $ down Done) >>=)+ where+ go mup (Done r) = Done (mup, r)+ go mup (PipeM mp) = PipeM $ liftM (go mup) mp+ go mup (HaveOutput p o) = HaveOutput (go mup p) o+ go _ (NeedInput p c) = NeedInput+ (\i -> go Nothing (p i))+ (\u -> go (Just u) (c ()))+ go mup (Leftover p i) = Leftover (go mup p) i+{-# INLINABLE fuseBothMaybe #-}++-- | Same as @fuseBoth@, but ignore the return value from the downstream+-- @Conduit@. Same caveats of forced consumption apply.+--+-- Since 1.1.5+fuseUpstream :: Monad m => ConduitT a b m r -> Conduit b m c -> ConduitT a c m r+fuseUpstream up down = fmap fst (fuseBoth up down)+{-# INLINE fuseUpstream #-}++-- Rewrite rules++{- FIXME+{-# RULES "conduit: ConduitT: lift x >>= f" forall m f. lift m >>= f = ConduitT (PipeM (liftM (unConduitT . f) m)) #-}+{-# RULES "conduit: ConduitT: lift x >> f" forall m f. lift m >> f = ConduitT (PipeM (liftM (\_ -> unConduitT f) m)) #-}++{-# RULES "conduit: ConduitT: liftIO x >>= f" forall m (f :: MonadIO m => a -> ConduitT i o m r). liftIO m >>= f = ConduitT (PipeM (liftM (unConduitT . f) (liftIO m))) #-}+{-# RULES "conduit: ConduitT: liftIO x >> f" forall m (f :: MonadIO m => ConduitT i o m r). liftIO m >> f = ConduitT (PipeM (liftM (\_ -> unConduitT f) (liftIO m))) #-}++{-# RULES "conduit: ConduitT: liftBase x >>= f" forall m (f :: MonadBase b m => a -> ConduitT i o m r). liftBase m >>= f = ConduitT (PipeM (liftM (unConduitT . f) (liftBase m))) #-}+{-# RULES "conduit: ConduitT: liftBase x >> f" forall m (f :: MonadBase b m => ConduitT i o m r). liftBase m >> f = ConduitT (PipeM (liftM (\_ -> unConduitT f) (liftBase m))) #-}++{-# RULES+ "yield o >> p" forall o (p :: ConduitT i o m r). yield o >> p = ConduitT (HaveOutput (unConduitT p) o)+ ; "when yield next" forall b o p. when b (yield o) >> p =+ if b then ConduitT (HaveOutput (unConduitT p) o) else p+ ; "unless yield next" forall b o p. unless b (yield o) >> p =+ if b then p else ConduitT (HaveOutput (unConduitT p) o)+ ; "lift m >>= yield" forall m. lift m >>= yield = yieldM m+ #-}+{-# RULES "conduit: leftover l >> p" forall l (p :: ConduitT i o m r). leftover l >> p =+ ConduitT (Leftover (unConduitT p) l) #-}+ -}
+ src/Data/Conduit/Internal/Fusion.hs view
@@ -0,0 +1,220 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE Trustworthy #-}+module Data.Conduit.Internal.Fusion+ ( -- ** Types+ Step (..)+ , Stream (..)+ , ConduitWithStream+ , StreamConduitT+ , StreamConduit+ , StreamSource+ , StreamProducer+ , StreamSink+ , StreamConsumer+ -- ** Functions+ , streamConduit+ , streamSource+ , streamSourcePure+ , unstream+ ) where++import Data.Conduit.Internal.Conduit+import Data.Conduit.Internal.Pipe (Pipe (..))+import Data.Functor.Identity (Identity (runIdentity))+import Data.Void (Void, absurd)++-- | This is the same as stream fusion\'s Step. Constructors are renamed to+-- avoid confusion with conduit names.+data Step s o r+ = Emit s o+ | Skip s+ | Stop r+ deriving Functor++data Stream m o r = forall s. Stream+ (s -> m (Step s o r))+ (m s)++data ConduitWithStream i o m r = ConduitWithStream+ (ConduitT i o m r)+ (StreamConduitT i o m r)++type StreamConduitT i o m r = Stream m i () -> Stream m o r++type StreamConduit i m o = StreamConduitT i o m ()++type StreamSource m o = StreamConduitT () o m ()++type StreamProducer m o = forall i. StreamConduitT i o m ()++type StreamSink i m r = StreamConduitT i Void m r++type StreamConsumer i m r = forall o. StreamConduitT i o m r++unstream :: ConduitWithStream i o m r -> ConduitT i o m r+unstream (ConduitWithStream c _) = c+{-# INLINE [0] unstream #-}++fuseStream :: Monad m+ => ConduitWithStream a b m ()+ -> ConduitWithStream b c m r+ -> ConduitWithStream a c m r+fuseStream (ConduitWithStream a x) (ConduitWithStream b y) =+ ConduitWithStream (a .| b) (y . x)+{-# INLINE fuseStream #-}++{-# RULES "conduit: fuseStream" forall left right.+ unstream left .| unstream right = unstream (fuseStream left right)+ #-}++runStream :: Monad m+ => ConduitWithStream () Void m r+ -> m r+runStream (ConduitWithStream _ f) =+ run $ f $ Stream emptyStep (return ())+ where+ emptyStep _ = return $ Stop ()+ run (Stream step ms0) =+ ms0 >>= loop+ where+ loop s = do+ res <- step s+ case res of+ Stop r -> return r+ Skip s' -> loop s'+ Emit _ o -> absurd o+{-# INLINE runStream #-}++{-# RULES "conduit: runStream" forall stream.+ runConduit (unstream stream) = runStream stream+ #-}++{-+connectStream :: Monad m+ => ConduitWithStream () i m ()+ -> ConduitWithStream i Void m r+ -> m r+connectStream (ConduitWithStream _ stream) (ConduitWithStream _ f) =+ run $ f $ stream $ Stream emptyStep (return ())+ where+ emptyStep _ = return $ Stop ()+ run (Stream step ms0) =+ ms0 >>= loop+ where+ loop s = do+ res <- step s+ case res of+ Stop r -> return r+ Skip s' -> loop s'+ Emit _ o -> absurd o+{-# INLINE connectStream #-}+-}++{- Deprecated+{-# RULES "conduit: connectStream" forall left right.+ unstream left $$ unstream right = connectStream left right+ #-}++connectStream1 :: Monad m+ => ConduitWithStream () i m ()+ -> ConduitT i Void m r+ -> m r+connectStream1 (ConduitWithStream _ fstream) (ConduitT sink0) =+ case fstream $ Stream (const $ return $ Stop ()) (return ()) of+ Stream step ms0 ->+ let loop _ (Done r) _ = return r+ loop ls (PipeM mp) s = mp >>= flip (loop ls) s+ loop ls (Leftover p l) s = loop (l:ls) p s+ loop _ (HaveOutput _ o) _ = absurd o+ loop (l:ls) (NeedInput p _) s = loop ls (p l) s+ loop [] (NeedInput p c) s = do+ res <- step s+ case res of+ Stop () -> loop [] (c ()) s+ Skip s' -> loop [] (NeedInput p c) s'+ Emit s' i -> loop [] (p i) s'+ in ms0 >>= loop [] (sink0 Done)+{-# INLINE connectStream1 #-}+-}++{- Deprecated+{-# RULES "conduit: connectStream1" forall left right.+ unstream left $$ right = connectStream1 left right+ #-}+-}++{-++Not only will this rule not fire reliably, but due to finalizers, it can change+behavior unless implemented very carefully. Odds are that the careful+implementation won't be any faster, so leaving this commented out for now.++connectStream2 :: Monad m+ => ConduitT () i m ()+ -> ConduitWithStream i Void m r+ -> m r+connectStream2 (ConduitT src0) (ConduitWithStream _ fstream) =+ run $ fstream $ Stream step' $ return (return (), src0 Done)+ where+ step' (_, Done ()) = return $ Stop ()+ {-# INLINE step' #-}++ run (Stream step ms0) =+ ms0 >>= loop+ where+ loop s = do+ res <- step s+ case res of+ Stop r -> return r+ Emit _ o -> absurd o+ Skip s' -> loop s'+{-# INLINE connectStream2 #-}++{-# RULES "conduit: connectStream2" forall left right.+ left $$ unstream right = connectStream2 left right+ #-}+-}++streamConduit :: ConduitT i o m r+ -> (Stream m i () -> Stream m o r)+ -> ConduitWithStream i o m r+streamConduit = ConduitWithStream+{-# INLINE CONLIKE streamConduit #-}++streamSource+ :: Monad m+ => Stream m o ()+ -> ConduitWithStream i o m ()+streamSource str@(Stream step ms0) =+ ConduitWithStream con (const str)+ where+ con = ConduitT $ \rest -> PipeM $ do+ s0 <- ms0+ let loop s = do+ res <- step s+ case res of+ Stop () -> return $ rest ()+ Emit s' o -> return $ HaveOutput (PipeM $ loop s') o+ Skip s' -> loop s'+ loop s0+{-# INLINE streamSource #-}++streamSourcePure+ :: Monad m+ => Stream Identity o ()+ -> ConduitWithStream i o m ()+streamSourcePure (Stream step ms0) =+ ConduitWithStream con (const $ Stream (return . runIdentity . step) (return s0))+ where+ s0 = runIdentity ms0+ con = ConduitT $ \rest ->+ let loop s =+ case runIdentity $ step s of+ Stop () -> rest ()+ Emit s' o -> HaveOutput (loop s') o+ Skip s' -> loop s'+ in loop s0+{-# INLINE streamSourcePure #-}
+ src/Data/Conduit/Internal/List/Stream.hs view
@@ -0,0 +1,502 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE Trustworthy #-}+module Data.Conduit.Internal.List.Stream where++import Control.Monad (liftM)+import Data.Conduit.Internal.Fusion+import qualified Data.Foldable as F++--FIXME: Should streamSource / streamSourcePure be used for sources?++unfoldS :: Monad m+ => (b -> Maybe (a, b))+ -> b+ -> StreamProducer m a+unfoldS f s0 _ =+ Stream step (return s0)+ where+ step s = return $+ case f s of+ Nothing -> Stop ()+ Just (x, s') -> Emit s' x+{-# INLINE unfoldS #-}++unfoldEitherS :: Monad m+ => (b -> Either r (a, b))+ -> b+ -> StreamConduitT i a m r+unfoldEitherS f s0 _ =+ Stream step (return s0)+ where+ step s = return $+ case f s of+ Left r -> Stop r+ Right (x, s') -> Emit s' x+{-# INLINE unfoldEitherS #-}++unfoldMS :: Monad m+ => (b -> m (Maybe (a, b)))+ -> b+ -> StreamProducer m a+unfoldMS f s0 _ =+ Stream step (return s0)+ where+ step s = do+ ms' <- f s+ return $ case ms' of+ Nothing -> Stop ()+ Just (x, s') -> Emit s' x+{-# INLINE unfoldMS #-}++unfoldEitherMS :: Monad m+ => (b -> m (Either r (a, b)))+ -> b+ -> StreamConduitT i a m r+unfoldEitherMS f s0 _ =+ Stream step (return s0)+ where+ step s = do+ ms' <- f s+ return $ case ms' of+ Left r -> Stop r+ Right (x, s') -> Emit s' x+{-# INLINE unfoldEitherMS #-}+sourceListS :: Monad m => [a] -> StreamProducer m a+sourceListS xs0 _ =+ Stream (return . step) (return xs0)+ where+ step [] = Stop ()+ step (x:xs) = Emit xs x+{-# INLINE sourceListS #-}++enumFromToS :: (Enum a, Prelude.Ord a, Monad m)+ => a+ -> a+ -> StreamProducer m a+enumFromToS x0 y _ =+ Stream step (return x0)+ where+ step x = return $ if x Prelude.> y+ then Stop ()+ else Emit (Prelude.succ x) x+{-# INLINE [0] enumFromToS #-}++enumFromToS_int :: (Prelude.Integral a, Monad m)+ => a+ -> a+ -> StreamProducer m a+enumFromToS_int x0 y _ = x0 `seq` y `seq` Stream step (return x0)+ where+ step x | x <= y = return $ Emit (x Prelude.+ 1) x+ | otherwise = return $ Stop ()+{-# INLINE enumFromToS_int #-}++{-# RULES "conduit: enumFromTo<Int>" forall f t.+ enumFromToS f t = enumFromToS_int f t :: Monad m => StreamProducer m Int+ #-}++iterateS :: Monad m => (a -> a) -> a -> StreamProducer m a+iterateS f x0 _ =+ Stream (return . step) (return x0)+ where+ step x = Emit x' x+ where+ x' = f x+{-# INLINE iterateS #-}++replicateS :: Monad m => Int -> a -> StreamProducer m a+replicateS cnt0 a _ =+ Stream step (return cnt0)+ where+ step cnt+ | cnt <= 0 = return $ Stop ()+ | otherwise = return $ Emit (cnt - 1) a+{-# INLINE replicateS #-}++replicateMS :: Monad m => Int -> m a -> StreamProducer m a+replicateMS cnt0 ma _ =+ Stream step (return cnt0)+ where+ step cnt+ | cnt <= 0 = return $ Stop ()+ | otherwise = Emit (cnt - 1) `liftM` ma+{-# INLINE replicateMS #-}++foldS :: Monad m => (b -> a -> b) -> b -> StreamConsumer a m b+foldS f b0 (Stream step ms0) =+ Stream step' (liftM (b0, ) ms0)+ where+ step' (!b, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop b+ Skip s' -> Skip (b, s')+ Emit s' a -> Skip (f b a, s')+{-# INLINE foldS #-}++foldMS :: Monad m => (b -> a -> m b) -> b -> StreamConsumer a m b+foldMS f b0 (Stream step ms0) =+ Stream step' (liftM (b0, ) ms0)+ where+ step' (!b, s) = do+ res <- step s+ case res of+ Stop () -> return $ Stop b+ Skip s' -> return $ Skip (b, s')+ Emit s' a -> do+ b' <- f b a+ return $ Skip (b', s')+{-# INLINE foldMS #-}++mapM_S :: Monad m+ => (a -> m ())+ -> StreamConsumer a m ()+mapM_S f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip s'+ Emit s' x -> f x >> return (Skip s')+{-# INLINE [1] mapM_S #-}++dropS :: Monad m+ => Int+ -> StreamConsumer a m ()+dropS n0 (Stream step ms0) =+ Stream step' (liftM (, n0) ms0)+ where+ step' (_, n) | n <= 0 = return $ Stop ()+ step' (s, n) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip (s', n)+ Emit s' _ -> Skip (s', n - 1)+{-# INLINE dropS #-}++takeS :: Monad m+ => Int+ -> StreamConsumer a m [a]+takeS n0 (Stream step s0) =+ Stream step' (liftM (id, n0,) s0)+ where+ step' (output, n, _) | n <= 0 = return $ Stop (output [])+ step' (output, n, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop (output [])+ Skip s' -> Skip (output, n, s')+ Emit s' x -> Skip (output . (x:), n - 1, s')+{-# INLINE takeS #-}++headS :: Monad m => StreamConsumer a m (Maybe a)+headS (Stream step s0) =+ Stream step' s0+ where+ step' s = do+ res <- step s+ return $ case res of+ Stop () -> Stop Nothing+ Skip s' -> Skip s'+ Emit _ x -> Stop (Just x)+{-# INLINE headS #-}++mapS :: Monad m => (a -> b) -> StreamConduit a m b+mapS f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ return $ case res of+ Stop r -> Stop r+ Emit s' a -> Emit s' (f a)+ Skip s' -> Skip s'+{-# INLINE mapS #-}++mapMS :: Monad m => (a -> m b) -> StreamConduit a m b+mapMS f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ case res of+ Stop r -> return $ Stop r+ Emit s' a -> Emit s' `liftM` f a+ Skip s' -> return $ Skip s'+{-# INLINE mapMS #-}++iterMS :: Monad m => (a -> m ()) -> StreamConduit a m a+iterMS f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip s'+ Emit s' x -> f x >> return (Emit s' x)+{-# INLINE iterMS #-}++mapMaybeS :: Monad m => (a -> Maybe b) -> StreamConduit a m b+mapMaybeS f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip s'+ Emit s' x ->+ case f x of+ Just y -> Emit s' y+ Nothing -> Skip s'+{-# INLINE mapMaybeS #-}++mapMaybeMS :: Monad m => (a -> m (Maybe b)) -> StreamConduit a m b+mapMaybeMS f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip s'+ Emit s' x -> do+ my <- f x+ case my of+ Just y -> return $ Emit s' y+ Nothing -> return $ Skip s'+{-# INLINE mapMaybeMS #-}++catMaybesS :: Monad m => StreamConduit (Maybe a) m a+catMaybesS (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip s'+ Emit s' Nothing -> Skip s'+ Emit s' (Just x) -> Emit s' x+{-# INLINE catMaybesS #-}++concatS :: (Monad m, F.Foldable f) => StreamConduit (f a) m a+concatS (Stream step ms0) =+ Stream step' (liftM ([], ) ms0)+ where+ step' ([], s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip ([], s')+ Emit s' x -> Skip (F.toList x, s')+ step' ((x:xs), s) = return (Emit (xs, s) x)+{-# INLINE concatS #-}++concatMapS :: Monad m => (a -> [b]) -> StreamConduit a m b+concatMapS f (Stream step ms0) =+ Stream step' (liftM ([], ) ms0)+ where+ step' ([], s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip ([], s')+ Emit s' x -> Skip (f x, s')+ step' ((x:xs), s) = return (Emit (xs, s) x)+{-# INLINE concatMapS #-}++concatMapMS :: Monad m => (a -> m [b]) -> StreamConduit a m b+concatMapMS f (Stream step ms0) =+ Stream step' (liftM ([], ) ms0)+ where+ step' ([], s) = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip ([], s')+ Emit s' x -> do+ xs <- f x+ return $ Skip (xs, s')+ step' ((x:xs), s) = return (Emit (xs, s) x)+{-# INLINE concatMapMS #-}++concatMapAccumS :: Monad m => (a -> accum -> (accum, [b])) -> accum -> StreamConduit a m b+concatMapAccumS f initial (Stream step ms0) =+ Stream step' (liftM (initial, [], ) ms0)+ where+ step' (accum, [], s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip (accum, [], s')+ Emit s' x ->+ let (accum', xs) = f x accum+ in Skip (accum', xs, s')+ step' (accum, (x:xs), s) = return (Emit (accum, xs, s) x)+{-# INLINE concatMapAccumS #-}++mapAccumS :: Monad m => (a -> s -> (s, b)) -> s -> StreamConduitT a b m s+mapAccumS f initial (Stream step ms0) =+ Stream step' (liftM (initial, ) ms0)+ where+ step' (accum, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop accum+ Skip s' -> Skip (accum, s')+ Emit s' x ->+ let (accum', r) = f x accum+ in Emit (accum', s') r+{-# INLINE mapAccumS #-}++mapAccumMS :: Monad m => (a -> s -> m (s, b)) -> s -> StreamConduitT a b m s+mapAccumMS f initial (Stream step ms0) =+ Stream step' (liftM (initial, ) ms0)+ where+ step' (accum, s) = do+ res <- step s+ case res of+ Stop () -> return $ Stop accum+ Skip s' -> return $ Skip (accum, s')+ Emit s' x -> do+ (accum', r) <- f x accum+ return $ Emit (accum', s') r+{-# INLINE mapAccumMS #-}++concatMapAccumMS :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> StreamConduit a m b+concatMapAccumMS f initial (Stream step ms0) =+ Stream step' (liftM (initial, [], ) ms0)+ where+ step' (accum, [], s) = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip (accum, [], s')+ Emit s' x -> do+ (accum', xs) <- f x accum+ return $ Skip (accum', xs, s')+ step' (accum, (x:xs), s) = return (Emit (accum, xs, s) x)+{-# INLINE concatMapAccumMS #-}++mapFoldableS :: (Monad m, F.Foldable f) => (a -> f b) -> StreamConduit a m b+mapFoldableS f (Stream step ms0) =+ Stream step' (liftM ([], ) ms0)+ where+ step' ([], s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip ([], s')+ Emit s' x -> Skip (F.toList (f x), s')+ step' ((x:xs), s) = return (Emit (xs, s) x)+{-# INLINE mapFoldableS #-}++mapFoldableMS :: (Monad m, F.Foldable f) => (a -> m (f b)) -> StreamConduit a m b+mapFoldableMS f (Stream step ms0) =+ Stream step' (liftM ([], ) ms0)+ where+ step' ([], s) = do+ res <- step s+ case res of+ Stop () -> return $ Stop ()+ Skip s' -> return $ Skip ([], s')+ Emit s' x -> do+ y <- f x+ return $ Skip (F.toList y, s')+ step' ((x:xs), s) = return (Emit (xs, s) x)+{-# INLINE mapFoldableMS #-}++consumeS :: Monad m => StreamConsumer a m [a]+consumeS (Stream step ms0) =+ Stream step' (liftM (id,) ms0)+ where+ step' (front, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop (front [])+ Skip s' -> Skip (front, s')+ Emit s' a -> Skip (front . (a:), s')+{-# INLINE consumeS #-}++groupByS :: Monad m => (a -> a -> Bool) -> StreamConduit a m [a]+groupByS f = mapS (Prelude.uncurry (:)) . groupBy1S id f+{-# INLINE groupByS #-}++groupOn1S :: (Monad m, Eq b) => (a -> b) -> StreamConduit a m (a, [a])+groupOn1S f = groupBy1S f (==)+{-# INLINE groupOn1S #-}++data GroupByState a b s+ = GBStart s+ | GBLoop ([a] -> [a]) a b s+ | GBDone++groupBy1S :: Monad m => (a -> b) -> (b -> b -> Bool) -> StreamConduit a m (a, [a])+groupBy1S f eq (Stream step ms0) =+ Stream step' (liftM GBStart ms0)+ where+ step' (GBStart s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip (GBStart s')+ Emit s' x0 -> Skip (GBLoop id x0 (f x0) s')+ step' (GBLoop rest x0 fx0 s) = do+ res <- step s+ return $ case res of+ Stop () -> Emit GBDone (x0, rest [])+ Skip s' -> Skip (GBLoop rest x0 fx0 s')+ Emit s' x+ | fx0 `eq` f x -> Skip (GBLoop (rest . (x:)) x0 fx0 s')+ | otherwise -> Emit (GBLoop id x (f x) s') (x0, rest [])+ step' GBDone = return $ Stop ()+{-# INLINE groupBy1S #-}++isolateS :: Monad m => Int -> StreamConduit a m a+isolateS count (Stream step ms0) =+ Stream step' (liftM (count,) ms0)+ where+ step' (n, _) | n <= 0 = return $ Stop ()+ step' (n, s) = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip (n, s')+ Emit s' x -> Emit (n - 1, s') x+{-# INLINE isolateS #-}++filterS :: Monad m => (a -> Bool) -> StreamConduit a m a+filterS f (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip s'+ Emit s' x+ | f x -> Emit s' x+ | otherwise -> Skip s'++sinkNullS :: Monad m => StreamConsumer a m ()+sinkNullS (Stream step ms0) =+ Stream step' ms0+ where+ step' s = do+ res <- step s+ return $ case res of+ Stop () -> Stop ()+ Skip s' -> Skip s'+ Emit s' _ -> Skip s'+{-# INLINE sinkNullS #-}++sourceNullS :: Monad m => StreamProducer m a+sourceNullS _ = Stream (\_ -> return (Stop ())) (return ())+{-# INLINE sourceNullS #-}
+ src/Data/Conduit/Internal/Pipe.hs view
@@ -0,0 +1,589 @@+{-# OPTIONS_HADDOCK not-home #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE TypeFamilies #-}+module Data.Conduit.Internal.Pipe+ ( -- ** Types+ Pipe (..)+ -- ** Primitives+ , await+ , awaitE+ , awaitForever+ , yield+ , yieldM+ , leftover+ -- ** Finalization+ , bracketP+ -- ** Composition+ , idP+ , pipe+ , pipeL+ , runPipe+ , injectLeftovers+ , (>+>)+ , (<+<)+ -- ** Exceptions+ , catchP+ , handleP+ , tryP+ -- ** Utilities+ , transPipe+ , mapOutput+ , mapOutputMaybe+ , mapInput+ , sourceList+ , withUpstream+ , Data.Conduit.Internal.Pipe.enumFromTo+ , generalizeUpstream+ ) where++import Control.Applicative (Applicative (..))+import Control.Monad ((>=>), liftM, ap)+import Control.Monad.Error.Class(MonadError(..))+import Control.Monad.Reader.Class(MonadReader(..))+import Control.Monad.RWS.Class(MonadRWS())+import Control.Monad.Writer.Class(MonadWriter(..))+import Control.Monad.State.Class(MonadState(..))+import Control.Monad.Trans.Class (MonadTrans (lift))+import Control.Monad.IO.Unlift (MonadIO (liftIO), MonadUnliftIO, withRunInIO)+import Control.Monad.Primitive (PrimMonad, PrimState, primitive)+import Data.Void (Void, absurd)+import Data.Monoid (Monoid (mappend, mempty))+import Data.Semigroup (Semigroup ((<>)))+import Control.Monad.Trans.Resource+import qualified GHC.Exts+import qualified Control.Exception as E++-- | The underlying datatype for all the types in this package. In has six+-- type parameters:+--+-- * /l/ is the type of values that may be left over from this @Pipe@. A @Pipe@+-- with no leftovers would use @Void@ here, and one with leftovers would use+-- the same type as the /i/ parameter. Leftovers are automatically provided to+-- the next @Pipe@ in the monadic chain.+--+-- * /i/ is the type of values for this @Pipe@'s input stream.+--+-- * /o/ is the type of values for this @Pipe@'s output stream.+--+-- * /u/ is the result type from the upstream @Pipe@.+--+-- * /m/ is the underlying monad.+--+-- * /r/ is the result type.+--+-- A basic intuition is that every @Pipe@ produces a stream of output values+-- (/o/), and eventually indicates that this stream is terminated by sending a+-- result (/r/). On the receiving end of a @Pipe@, these become the /i/ and /u/+-- parameters.+--+-- Since 0.5.0+data Pipe l i o u m r =+ -- | Provide new output to be sent downstream. This constructor has two+ -- fields: the next @Pipe@ to be used and the output value.+ HaveOutput (Pipe l i o u m r) o+ -- | Request more input from upstream. The first field takes a new input+ -- value and provides a new @Pipe@. The second takes an upstream result+ -- value, which indicates that upstream is producing no more results.+ | NeedInput (i -> Pipe l i o u m r) (u -> Pipe l i o u m r)+ -- | Processing with this @Pipe@ is complete, providing the final result.+ | Done r+ -- | Require running of a monadic action to get the next @Pipe@.+ | PipeM (m (Pipe l i o u m r))+ -- | Return leftover input, which should be provided to future operations.+ | Leftover (Pipe l i o u m r) l++instance Monad m => Functor (Pipe l i o u m) where+ fmap = liftM+ {-# INLINE fmap #-}++instance Monad m => Applicative (Pipe l i o u m) where+ pure = Done+ {-# INLINE pure #-}+ (<*>) = ap+ {-# INLINE (<*>) #-}++instance Monad m => Monad (Pipe l i o u m) where+ return = pure+ {-# INLINE return #-}++ HaveOutput p o >>= fp = HaveOutput (p >>= fp) o+ NeedInput p c >>= fp = NeedInput (p >=> fp) (c >=> fp)+ Done x >>= fp = fp x+ PipeM mp >>= fp = PipeM ((>>= fp) `liftM` mp)+ Leftover p i >>= fp = Leftover (p >>= fp) i++instance MonadTrans (Pipe l i o u) where+ lift mr = PipeM (Done `liftM` mr)+ {-# INLINE [1] lift #-}++instance MonadIO m => MonadIO (Pipe l i o u m) where+ liftIO = lift . liftIO+ {-# INLINE liftIO #-}++instance MonadThrow m => MonadThrow (Pipe l i o u m) where+ throwM = lift . throwM+ {-# INLINE throwM #-}+++instance Monad m => Semigroup (Pipe l i o u m ()) where+ (<>) = (>>)+ {-# INLINE (<>) #-}++instance Monad m => Monoid (Pipe l i o u m ()) where+ mempty = return ()+ {-# INLINE mempty #-}+#if !(MIN_VERSION_base(4,11,0))+ mappend = (<>)+ {-# INLINE mappend #-}+#endif++instance PrimMonad m => PrimMonad (Pipe l i o u m) where+ type PrimState (Pipe l i o u m) = PrimState m+ primitive = lift . primitive++instance MonadResource m => MonadResource (Pipe l i o u m) where+ liftResourceT = lift . liftResourceT+ {-# INLINE liftResourceT #-}++instance MonadReader r m => MonadReader r (Pipe l i o u m) where+ ask = lift ask+ {-# INLINE ask #-}+ local f (HaveOutput p o) = HaveOutput (local f p) o+ local f (NeedInput p c) = NeedInput (\i -> local f (p i)) (\u -> local f (c u))+ local _ (Done x) = Done x+ local f (PipeM mp) = PipeM (liftM (local f) $ local f mp)+ local f (Leftover p i) = Leftover (local f p) i++-- Provided for doctest+#ifndef MIN_VERSION_mtl+#define MIN_VERSION_mtl(x, y, z) 0+#endif++instance MonadWriter w m => MonadWriter w (Pipe l i o u m) where+#if MIN_VERSION_mtl(2, 1, 0)+ writer = lift . writer+#endif++ tell = lift . tell++ listen (HaveOutput p o) = HaveOutput (listen p) o+ listen (NeedInput p c) = NeedInput (\i -> listen (p i)) (\u -> listen (c u))+ listen (Done x) = Done (x,mempty)+ listen (PipeM mp) =+ PipeM $+ do (p,w) <- listen mp+ return $ do (x,w') <- listen p+ return (x, w `mappend` w')+ listen (Leftover p i) = Leftover (listen p) i++ pass (HaveOutput p o) = HaveOutput (pass p) o+ pass (NeedInput p c) = NeedInput (\i -> pass (p i)) (\u -> pass (c u))+ pass (PipeM mp) = PipeM $ mp >>= (return . pass)+ pass (Done (x,_)) = Done x+ pass (Leftover p i) = Leftover (pass p) i++instance MonadState s m => MonadState s (Pipe l i o u m) where+ get = lift get+ put = lift . put+#if MIN_VERSION_mtl(2, 1, 0)+ state = lift . state+#endif++instance MonadRWS r w s m => MonadRWS r w s (Pipe l i o u m)++instance MonadError e m => MonadError e (Pipe l i o u m) where+ throwError = lift . throwError+ catchError (HaveOutput p o) f = HaveOutput (catchError p f) o+ catchError (NeedInput p c) f = NeedInput (\i -> catchError (p i) f) (\u -> catchError (c u) f)+ catchError (Done x) _ = Done x+ catchError (PipeM mp) f =+ PipeM $ catchError (liftM (flip catchError f) mp) (\e -> return (f e))+ catchError (Leftover p i) f = Leftover (catchError p f) i++-- | Wait for a single input value from upstream.+--+-- Since 0.5.0+await :: Pipe l i o u m (Maybe i)+await = NeedInput (Done . Just) (\_ -> Done Nothing)+{-# RULES "conduit: CI.await >>= maybe" forall x y. await >>= maybe x y = NeedInput y (const x) #-}+{-# INLINE [1] await #-}++-- | This is similar to @await@, but will return the upstream result value as+-- @Left@ if available.+--+-- Since 0.5.0+awaitE :: Pipe l i o u m (Either u i)+awaitE = NeedInput (Done . Right) (Done . Left)+{-# RULES "conduit: awaitE >>= either" forall x y. awaitE >>= either x y = NeedInput y x #-}+{-# INLINE [1] awaitE #-}++-- | Wait for input forever, calling the given inner @Pipe@ for each piece of+-- new input. Returns the upstream result type.+--+-- Since 0.5.0+awaitForever :: Monad m => (i -> Pipe l i o r m r') -> Pipe l i o r m r+awaitForever inner =+ self+ where+ self = awaitE >>= either return (\i -> inner i >> self)+{-# INLINE [1] awaitForever #-}++-- | Send a single output value downstream. If the downstream @Pipe@+-- terminates, this @Pipe@ will terminate as well.+--+-- Since 0.5.0+yield :: Monad m+ => o -- ^ output value+ -> Pipe l i o u m ()+yield = HaveOutput (Done ())+{-# INLINE [1] yield #-}++yieldM :: Monad m => m o -> Pipe l i o u m ()+yieldM = PipeM . liftM (HaveOutput (Done ()))+{-# INLINE [1] yieldM #-}++{-# RULES+ "CI.yield o >> p" forall o (p :: Pipe l i o u m r). yield o >> p = HaveOutput p o+ #-}++ -- Rule does not fire due to inlining of lift+ -- ; "lift m >>= CI.yield" forall m. lift m >>= yield = yieldM m++ -- FIXME: Too much inlining on mapM_, can't enforce; "mapM_ CI.yield" mapM_ yield = sourceList+ -- Maybe we can get a rewrite rule on foldr instead? Need a benchmark to back this up.++-- | Provide a single piece of leftover input to be consumed by the next pipe+-- 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 :: l -> Pipe l i o u m ()+leftover = Leftover (Done ())+{-# INLINE [1] leftover #-}+{-# RULES "conduit: leftover l >> p" forall l (p :: Pipe l i o u m r). leftover l >> p = Leftover p l #-}++-- | Bracket a pipe computation between allocation and release of a resource.+-- We guarantee, via the @MonadResource@ context, that the resource+-- finalization is exception safe. However, it will not necessarily be+-- /prompt/, in that running a finalizer may wait until the @ResourceT@ block+-- exits.+--+-- Since 0.5.0+bracketP :: MonadResource m+ => IO a+ -- ^ computation to run first (\"acquire resource\")+ -> (a -> IO ())+ -- ^ computation to run last (\"release resource\")+ -> (a -> Pipe l i o u m r)+ -- ^ computation to run in-between+ -> Pipe l i o u m r+ -- returns the value from the in-between computation+bracketP alloc free inside = do+ (key, seed) <- allocate alloc free+ res <- inside seed+ release key+ return res++-- | The identity @Pipe@.+--+-- Since 0.5.0+idP :: Monad m => Pipe l a a r m r+idP = NeedInput (HaveOutput idP) Done++-- | Compose a left and right pipe together into a complete pipe.+--+-- Since 0.5.0+pipe :: Monad m => Pipe l a b r0 m r1 -> Pipe Void b c r1 m r2 -> Pipe l a c r0 m r2+pipe =+ goRight+ where+ goRight left right =+ case right of+ HaveOutput p o -> HaveOutput (recurse p) o+ NeedInput rp rc -> goLeft rp rc left+ Done r2 -> Done r2+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover _ i -> absurd i+ where+ recurse = goRight left++ goLeft rp rc left =+ case left of+ HaveOutput left' o -> goRight left' (rp o)+ NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)+ Done r1 -> goRight (Done r1) (rc r1)+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover left' i -> Leftover (recurse left') i+ where+ recurse = goLeft rp rc++-- | Same as 'pipe', but automatically applies 'injectLeftovers' to the right @Pipe@.+--+-- Since 0.5.0+pipeL :: Monad m => Pipe l a b r0 m r1 -> Pipe b b c r1 m r2 -> Pipe l a c r0 m r2+-- Note: The following should be equivalent to the simpler:+--+-- pipeL l r = l `pipe` injectLeftovers r+--+-- However, this version tested as being significantly more efficient.+pipeL =+ goRight+ where+ goRight left right =+ case right of+ HaveOutput p o -> HaveOutput (recurse p) o+ NeedInput rp rc -> goLeft rp rc left+ Done r2 -> Done r2+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover right' i -> goRight (HaveOutput left i) right'+ where+ recurse = goRight left++ goLeft rp rc left =+ case left of+ HaveOutput left' o -> goRight left' (rp o)+ NeedInput left' lc -> NeedInput (recurse . left') (recurse . lc)+ Done r1 -> goRight (Done r1) (rc r1)+ PipeM mp -> PipeM (liftM recurse mp)+ Leftover left' i -> Leftover (recurse left') i+ where+ recurse = goLeft rp rc++-- | Run a pipeline until processing completes.+--+-- Since 0.5.0+runPipe :: Monad m => Pipe Void () Void () m r -> m r+runPipe (HaveOutput _ o) = absurd o+runPipe (NeedInput _ c) = runPipe (c ())+runPipe (Done r) = return r+runPipe (PipeM mp) = mp >>= runPipe+runPipe (Leftover _ i) = absurd i++-- | Transforms a @Pipe@ that provides leftovers to one which does not,+-- allowing it to be composed.+--+-- This function will provide any leftover values within this @Pipe@ to any+-- calls to @await@. If there are more leftover values than are demanded, the+-- remainder are discarded.+--+-- Since 0.5.0+injectLeftovers :: Monad m => Pipe i i o u m r -> Pipe l i o u m r+injectLeftovers =+ go []+ where+ go ls (HaveOutput p o) = HaveOutput (go ls p) o+ go (l:ls) (NeedInput p _) = go ls $ p l+ go [] (NeedInput p c) = NeedInput (go [] . p) (go [] . c)+ go _ (Done r) = Done r+ go ls (PipeM mp) = PipeM (liftM (go ls) mp)+ go ls (Leftover p l) = go (l:ls) p++-- | Transform the monad that a @Pipe@ 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>+--+-- This function is just a synonym for 'hoist'.+--+-- Since 0.4.0+transPipe :: Monad m => (forall a. m a -> n a) -> Pipe l i o u m r -> Pipe l i o u n r+transPipe f (HaveOutput p o) = HaveOutput (transPipe f p) o+transPipe f (NeedInput p c) = NeedInput (transPipe f . p) (transPipe f . c)+transPipe _ (Done r) = Done r+transPipe f (PipeM mp) =+ PipeM (f $ liftM (transPipe f) $ collapse mp)+ where+ -- Combine a series of monadic actions into a single action. Since we+ -- throw away side effects between different actions, an arbitrary break+ -- between actions will lead to a violation of the monad transformer laws.+ -- Example available at:+ --+ -- http://hpaste.org/75520+ collapse mpipe = do+ pipe' <- mpipe+ case pipe' of+ PipeM mpipe' -> collapse mpipe'+ _ -> return pipe'+transPipe f (Leftover p i) = Leftover (transPipe f p) i++-- | Apply a function to all the output values of a @Pipe@.+--+-- This mimics the behavior of `fmap` for a `Source` and `Conduit` in pre-0.4+-- days.+--+-- Since 0.4.1+mapOutput :: Monad m => (o1 -> o2) -> Pipe l i o1 u m r -> Pipe l i o2 u m r+mapOutput f =+ go+ where+ go (HaveOutput p o) = HaveOutput (go p) (f o)+ go (NeedInput p c) = NeedInput (go . p) (go . c)+ go (Done r) = Done r+ go (PipeM mp) = PipeM (liftM (go) mp)+ go (Leftover p i) = Leftover (go p) i+{-# INLINE mapOutput #-}++-- | Same as 'mapOutput', but use a function that returns @Maybe@ values.+--+-- Since 0.5.0+mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> Pipe l i o1 u m r -> Pipe l i o2 u m r+mapOutputMaybe f =+ go+ where+ go (HaveOutput p o) = maybe id (\o' p' -> HaveOutput p' o') (f o) (go p)+ go (NeedInput p c) = NeedInput (go . p) (go . c)+ go (Done r) = Done r+ go (PipeM mp) = PipeM (liftM (go) mp)+ go (Leftover p i) = Leftover (go p) i+{-# INLINE mapOutputMaybe #-}++-- | Apply a function to all the input values of a @Pipe@.+--+-- Since 0.5.0+mapInput :: Monad m+ => (i1 -> i2) -- ^ map initial input to new input+ -> (l2 -> Maybe l1) -- ^ map new leftovers to initial leftovers+ -> Pipe l2 i2 o u m r+ -> Pipe l1 i1 o u m r+mapInput f f' (HaveOutput p o) = HaveOutput (mapInput f f' p) o+mapInput f f' (NeedInput p c) = NeedInput (mapInput f f' . p . f) (mapInput f f' . c)+mapInput _ _ (Done r) = Done r+mapInput f f' (PipeM mp) = PipeM (liftM (mapInput f f') mp)+mapInput f f' (Leftover p i) = maybe id (flip Leftover) (f' i) $ mapInput f f' p++enumFromTo :: (Enum o, Eq o, Monad m)+ => o+ -> o+ -> Pipe l i o u m ()+enumFromTo start stop =+ loop start+ where+ loop i+ | i == stop = HaveOutput (Done ()) i+ | otherwise = HaveOutput (loop (succ i)) i+{-# INLINE enumFromTo #-}++-- | Convert a list into a source.+--+-- Since 0.3.0+sourceList :: Monad m => [a] -> Pipe l i a u m ()+sourceList =+ go+ where+ go [] = Done ()+ go (o:os) = HaveOutput (go os) o+{-# INLINE [1] sourceList #-}++-- | The equivalent of @GHC.Exts.build@ for @Pipe@.+--+-- Since 0.4.2+build :: Monad m => (forall b. (o -> b -> b) -> b -> b) -> Pipe l i o u m ()+build g = g (\o p -> HaveOutput p o) (return ())++{-# RULES+ "sourceList/build" forall (f :: (forall b. (a -> b -> b) -> b -> b)). sourceList (GHC.Exts.build f) = build f #-}++-- | Returns a tuple of the upstream and downstream results. Note that this+-- will force consumption of the entire input stream.+--+-- Since 0.5.0+withUpstream :: Monad m+ => Pipe l i o u m r+ -> Pipe l i o u m (u, r)+withUpstream down =+ down >>= go+ where+ go r =+ loop+ where+ loop = awaitE >>= either (\u -> return (u, r)) (\_ -> loop)++infixr 9 <+<+infixl 9 >+>++-- | Fuse together two @Pipe@s, connecting the output from the left to the+-- input of the right.+--+-- Notice that the /leftover/ parameter for the @Pipe@s must be @Void@. This+-- ensures that there is no accidental data loss of leftovers during fusion. If+-- you have a @Pipe@ with leftovers, you must first call 'injectLeftovers'.+--+-- Since 0.5.0+(>+>) :: Monad m => Pipe l a b r0 m r1 -> Pipe Void b c r1 m r2 -> Pipe l a c r0 m r2+(>+>) = pipe+{-# INLINE (>+>) #-}++-- | Same as '>+>', but reverse the order of the arguments.+--+-- Since 0.5.0+(<+<) :: Monad m => Pipe Void b c r1 m r2 -> Pipe l a b r0 m r1 -> Pipe l a c r0 m r2+(<+<) = flip pipe+{-# INLINE (<+<) #-}++-- | See 'catchC' for more details.+--+-- Since 1.0.11+catchP :: (MonadUnliftIO m, E.Exception e)+ => Pipe l i o u m r+ -> (e -> Pipe l i o u m r)+ -> Pipe l i o u m r+catchP p0 onErr =+ go p0+ where+ go (Done r) = Done r+ go (PipeM mp) = PipeM $ withRunInIO $ \run ->+ E.catch (run (liftM go mp)) (return . onErr)+ go (Leftover p i) = Leftover (go p) i+ go (NeedInput x y) = NeedInput (go . x) (go . y)+ go (HaveOutput p o) = HaveOutput (go p) o+{-# INLINABLE catchP #-}++-- | The same as @flip catchP@.+--+-- Since 1.0.11+handleP :: (MonadUnliftIO m, E.Exception e)+ => (e -> Pipe l i o u m r)+ -> Pipe l i o u m r+ -> Pipe l i o u m r+handleP = flip catchP+{-# INLINE handleP #-}++-- | See 'tryC' for more details.+--+-- Since 1.0.11+tryP :: (MonadUnliftIO m, E.Exception e)+ => Pipe l i o u m r+ -> Pipe l i o u m (Either e r)+tryP p = (fmap Right p) `catchP` (return . Left)+{-# INLINABLE tryP #-}++-- | Generalize the upstream return value for a @Pipe@ from unit to any type.+--+-- Since 1.1.5+generalizeUpstream :: Monad m => Pipe l i o () m r -> Pipe l i o u m r+generalizeUpstream =+ go+ where+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput x y) = NeedInput (go . x) (\_ -> go (y ()))+ go (Done r) = Done r+ go (PipeM mp) = PipeM (liftM go mp)+ go (Leftover p l) = Leftover (go p) l+{-# INLINE generalizeUpstream #-}++{- Rules don't fire due to inlining of lift+{-# RULES "conduit: Pipe: lift x >>= f" forall m f. lift m >>= f = PipeM (liftM f m) #-}+{-# RULES "conduit: Pipe: lift x >> f" forall m f. lift m >> f = PipeM (liftM (\_ -> f) m) #-}+-}
+ src/Data/Conduit/Lift.hs view
@@ -0,0 +1,518 @@+{-# LANGUAGE RankNTypes #-}+-- | Allow monad transformers to be run\/eval\/exec in a section of conduit+-- rather then needing to run across the whole conduit. The circumvents many+-- of the problems with breaking the monad transformer laws. For more+-- information, see the announcement blog post:+-- <http://www.yesodweb.com/blog/2014/01/conduit-transformer-exception>+--+-- This module was added in conduit 1.0.11.+module Data.Conduit.Lift (+ -- * ExceptT+ exceptC,+ runExceptC,+ catchExceptC,++ -- * CatchC+ runCatchC,+ catchCatchC,++ -- * MaybeT+ maybeC,+ runMaybeC,++ -- * ReaderT+ readerC,+ runReaderC,++ -- * StateT, lazy+ stateLC,+ runStateLC,+ evalStateLC,+ execStateLC,++ -- ** Strict+ stateC,+ runStateC,+ evalStateC,+ execStateC,++ -- * WriterT, lazy+ writerLC,+ runWriterLC,+ execWriterLC,++ -- ** Strict+ writerC,+ runWriterC,+ execWriterC,++ -- * RWST, lazy+ rwsLC,+ runRWSLC,+ evalRWSLC,+ execRWSLC,++ -- ** Strict+ rwsC,+ runRWSC,+ evalRWSC,+ execRWSC+ ) where++import Data.Conduit+import Data.Conduit.Internal (ConduitT (..), Pipe (..))++import Control.Monad.Trans.Class (MonadTrans(..))++import Data.Monoid (Monoid(..))+++import qualified Control.Monad.Trans.Except as Ex+import qualified Control.Monad.Trans.Maybe as M+import qualified Control.Monad.Trans.Reader as R++import qualified Control.Monad.Trans.State.Strict as SS+import qualified Control.Monad.Trans.Writer.Strict as WS+import qualified Control.Monad.Trans.RWS.Strict as RWSS++import qualified Control.Monad.Trans.State.Lazy as SL+import qualified Control.Monad.Trans.Writer.Lazy as WL+import qualified Control.Monad.Trans.RWS.Lazy as RWSL++import Control.Monad.Catch.Pure (CatchT (runCatchT))+import Control.Exception (SomeException)++-- | Wrap the base monad in 'Ex.ExceptT'+--+-- Since 1.2.12+exceptC+ :: Monad m =>+ ConduitT i o m (Either e a) -> ConduitT i o (Ex.ExceptT e m) a+exceptC p = do+ x <- transPipe lift p+ lift $ Ex.ExceptT (return x)++-- | Run 'Ex.ExceptT' in the base monad+--+-- Since 1.2.12+runExceptC+ :: Monad m =>+ ConduitT i o (Ex.ExceptT e m) r -> ConduitT i o m (Either e r)+runExceptC (ConduitT c0) =+ ConduitT $ \rest ->+ let go (Done r) = rest (Right r)+ go (PipeM mp) = PipeM $ do+ eres <- Ex.runExceptT mp+ return $ case eres of+ Left e -> rest $ Left e+ Right p -> go p+ go (Leftover p i) = Leftover (go p) i+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput x y) = NeedInput (go . x) (go . y)+ in go (c0 Done)+{-# INLINABLE runExceptC #-}++-- | Catch an error in the base monad+--+-- Since 1.2.12+catchExceptC+ :: Monad m =>+ ConduitT i o (Ex.ExceptT e m) r+ -> (e -> ConduitT i o (Ex.ExceptT e m) r)+ -> ConduitT i o (Ex.ExceptT e m) r+catchExceptC c0 h =+ ConduitT $ \rest ->+ let go (Done r) = rest r+ go (PipeM mp) = PipeM $ do+ eres <- lift $ Ex.runExceptT mp+ return $ case eres of+ Left e -> unConduitT (h e) rest+ Right p -> go p+ go (Leftover p i) = Leftover (go p) i+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput x y) = NeedInput (go . x) (go . y)+ in go $ unConduitT c0 Done+ where+{-# INLINABLE catchExceptC #-}++-- | Run 'CatchT' in the base monad+--+-- Since 1.1.0+runCatchC+ :: Monad m =>+ ConduitT i o (CatchT m) r -> ConduitT i o m (Either SomeException r)+runCatchC c0 =+ ConduitT $ \rest ->+ let go (Done r) = rest (Right r)+ go (PipeM mp) = PipeM $ do+ eres <- runCatchT mp+ return $ case eres of+ Left e -> rest $ Left e+ Right p -> go p+ go (Leftover p i) = Leftover (go p) i+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput x y) = NeedInput (go . x) (go . y)+ in go $ unConduitT c0 Done+{-# INLINABLE runCatchC #-}++-- | Catch an exception in the base monad+--+-- Since 1.1.0+catchCatchC+ :: Monad m+ => ConduitT i o (CatchT m) r+ -> (SomeException -> ConduitT i o (CatchT m) r)+ -> ConduitT i o (CatchT m) r+catchCatchC (ConduitT c0) h =+ ConduitT $ \rest ->+ let go (Done r) = rest r+ go (PipeM mp) = PipeM $ do+ eres <- lift $ runCatchT mp+ return $ case eres of+ Left e -> unConduitT (h e) rest+ Right p -> go p+ go (Leftover p i) = Leftover (go p) i+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput x y) = NeedInput (go . x) (go . y)+ in go (c0 Done)+{-# INLINABLE catchCatchC #-}++-- | Wrap the base monad in 'M.MaybeT'+--+-- Since 1.0.11+maybeC+ :: Monad m =>+ ConduitT i o m (Maybe a) -> ConduitT i o (M.MaybeT m) a+maybeC p = do+ x <- transPipe lift p+ lift $ M.MaybeT (return x)+{-# INLINABLE maybeC #-}++-- | Run 'M.MaybeT' in the base monad+--+-- Since 1.0.11+runMaybeC+ :: Monad m =>+ ConduitT i o (M.MaybeT m) r -> ConduitT i o m (Maybe r)+runMaybeC (ConduitT c0) =+ ConduitT $ \rest ->+ let go (Done r) = rest (Just r)+ go (PipeM mp) = PipeM $ do+ mres <- M.runMaybeT mp+ return $ case mres of+ Nothing -> rest Nothing+ Just p -> go p+ go (Leftover p i) = Leftover (go p) i+ go (HaveOutput p o) = HaveOutput (go p) o+ go (NeedInput x y) = NeedInput (go . x) (go . y)+ in go (c0 Done)+{-# INLINABLE runMaybeC #-}++-- | Wrap the base monad in 'R.ReaderT'+--+-- Since 1.0.11+readerC+ :: Monad m =>+ (r -> ConduitT i o m a) -> ConduitT i o (R.ReaderT r m) a+readerC k = do+ i <- lift R.ask+ transPipe lift (k i)+{-# INLINABLE readerC #-}++-- | Run 'R.ReaderT' in the base monad+--+-- Since 1.0.11+runReaderC+ :: Monad m =>+ r -> ConduitT i o (R.ReaderT r m) res -> ConduitT i o m res+runReaderC r = transPipe (`R.runReaderT` r)+{-# INLINABLE runReaderC #-}+++-- | Wrap the base monad in 'SL.StateT'+--+-- Since 1.0.11+stateLC+ :: Monad m =>+ (s -> ConduitT i o m (a, s)) -> ConduitT i o (SL.StateT s m) a+stateLC k = do+ s <- lift SL.get+ (r, s') <- transPipe lift (k s)+ lift (SL.put s')+ return r+{-# INLINABLE stateLC #-}++thread :: Monad m+ => (r -> s -> res)+ -> (forall a. t m a -> s -> m (a, s))+ -> s+ -> ConduitT i o (t m) r+ -> ConduitT i o m res+thread toRes runM s0 (ConduitT c0) =+ ConduitT $ \rest ->+ let go s (Done r) = rest (toRes r s)+ go s (PipeM mp) = PipeM $ do+ (p, s') <- runM mp s+ return $ go s' p+ go s (Leftover p i) = Leftover (go s p) i+ go s (NeedInput x y) = NeedInput (go s . x) (go s . y)+ go s (HaveOutput p o) = HaveOutput (go s p) o+ in go s0 (c0 Done)+{-# INLINABLE thread #-}++-- | Run 'SL.StateT' in the base monad+--+-- Since 1.0.11+runStateLC+ :: Monad m =>+ s -> ConduitT i o (SL.StateT s m) r -> ConduitT i o m (r, s)+runStateLC = thread (,) SL.runStateT+{-# INLINABLE runStateLC #-}++-- | Evaluate 'SL.StateT' in the base monad+--+-- Since 1.0.11+evalStateLC+ :: Monad m =>+ s -> ConduitT i o (SL.StateT s m) r -> ConduitT i o m r+evalStateLC s p = fmap fst $ runStateLC s p+{-# INLINABLE evalStateLC #-}++-- | Execute 'SL.StateT' in the base monad+--+-- Since 1.0.11+execStateLC+ :: Monad m =>+ s -> ConduitT i o (SL.StateT s m) r -> ConduitT i o m s+execStateLC s p = fmap snd $ runStateLC s p+{-# INLINABLE execStateLC #-}+++-- | Wrap the base monad in 'SS.StateT'+--+-- Since 1.0.11+stateC+ :: Monad m =>+ (s -> ConduitT i o m (a, s)) -> ConduitT i o (SS.StateT s m) a+stateC k = do+ s <- lift SS.get+ (r, s') <- transPipe lift (k s)+ lift (SS.put s')+ return r+{-# INLINABLE stateC #-}++-- | Run 'SS.StateT' in the base monad+--+-- Since 1.0.11+runStateC+ :: Monad m =>+ s -> ConduitT i o (SS.StateT s m) r -> ConduitT i o m (r, s)+runStateC = thread (,) SS.runStateT+{-# INLINABLE runStateC #-}++-- | Evaluate 'SS.StateT' in the base monad+--+-- Since 1.0.11+evalStateC+ :: Monad m =>+ s -> ConduitT i o (SS.StateT s m) r -> ConduitT i o m r+evalStateC s p = fmap fst $ runStateC s p+{-# INLINABLE evalStateC #-}++-- | Execute 'SS.StateT' in the base monad+--+-- Since 1.0.11+execStateC+ :: Monad m =>+ s -> ConduitT i o (SS.StateT s m) r -> ConduitT i o m s+execStateC s p = fmap snd $ runStateC s p+{-# INLINABLE execStateC #-}+++-- | Wrap the base monad in 'WL.WriterT'+--+-- Since 1.0.11+writerLC+ :: (Monad m, Monoid w) =>+ ConduitT i o m (b, w) -> ConduitT i o (WL.WriterT w m) b+writerLC p = do+ (r, w) <- transPipe lift p+ lift $ WL.tell w+ return r+{-# INLINABLE writerLC #-}++-- | Run 'WL.WriterT' in the base monad+--+-- Since 1.0.11+runWriterLC+ :: (Monad m, Monoid w) =>+ ConduitT i o (WL.WriterT w m) r -> ConduitT i o m (r, w)+runWriterLC = thread (,) run mempty+ where+ run m w = do+ (a, w') <- WL.runWriterT m+ return (a, w `mappend` w')+{-# INLINABLE runWriterLC #-}++-- | Execute 'WL.WriterT' in the base monad+--+-- Since 1.0.11+execWriterLC+ :: (Monad m, Monoid w) =>+ ConduitT i o (WL.WriterT w m) r -> ConduitT i o m w+execWriterLC p = fmap snd $ runWriterLC p+{-# INLINABLE execWriterLC #-}+++-- | Wrap the base monad in 'WS.WriterT'+--+-- Since 1.0.11+writerC+ :: (Monad m, Monoid w) =>+ ConduitT i o m (b, w) -> ConduitT i o (WS.WriterT w m) b+writerC p = do+ (r, w) <- transPipe lift p+ lift $ WS.tell w+ return r+{-# INLINABLE writerC #-}++-- | Run 'WS.WriterT' in the base monad+--+-- Since 1.0.11+runWriterC+ :: (Monad m, Monoid w) =>+ ConduitT i o (WS.WriterT w m) r -> ConduitT i o m (r, w)+runWriterC = thread (,) run mempty+ where+ run m w = do+ (a, w') <- WS.runWriterT m+ return (a, w `mappend` w')+{-# INLINABLE runWriterC #-}++-- | Execute 'WS.WriterT' in the base monad+--+-- Since 1.0.11+execWriterC+ :: (Monad m, Monoid w) =>+ ConduitT i o (WS.WriterT w m) r -> ConduitT i o m w+execWriterC p = fmap snd $ runWriterC p+{-# INLINABLE execWriterC #-}+++-- | Wrap the base monad in 'RWSL.RWST'+--+-- Since 1.0.11+rwsLC+ :: (Monad m, Monoid w) =>+ (r -> s -> ConduitT i o m (a, s, w)) -> ConduitT i o (RWSL.RWST r w s m) a+rwsLC k = do+ i <- lift RWSL.ask+ s <- lift RWSL.get+ (r, s', w) <- transPipe lift (k i s)+ lift $ do+ RWSL.put s'+ RWSL.tell w+ return r+{-# INLINABLE rwsLC #-}++-- | Run 'RWSL.RWST' in the base monad+--+-- Since 1.0.11+runRWSLC+ :: (Monad m, Monoid w) =>+ r+ -> s+ -> ConduitT i o (RWSL.RWST r w s m) res+ -> ConduitT i o m (res, s, w)+runRWSLC r s0 = thread toRes run (s0, mempty)+ where+ toRes a (s, w) = (a, s, w)+ run m (s, w) = do+ (res, s', w') <- RWSL.runRWST m r s+ return (res, (s', w `mappend` w'))+{-# INLINABLE runRWSLC #-}++-- | Evaluate 'RWSL.RWST' in the base monad+--+-- Since 1.0.11+evalRWSLC+ :: (Monad m, Monoid w) =>+ r+ -> s+ -> ConduitT i o (RWSL.RWST r w s m) res+ -> ConduitT i o m (res, w)+evalRWSLC i s p = fmap f $ runRWSLC i s p+ where f x = let (r, _, w) = x in (r, w)+{-# INLINABLE evalRWSLC #-}++-- | Execute 'RWSL.RWST' in the base monad+--+-- Since 1.0.11+execRWSLC+ :: (Monad m, Monoid w) =>+ r+ -> s+ -> ConduitT i o (RWSL.RWST r w s m) res+ -> ConduitT i o m (s, w)+execRWSLC i s p = fmap f $ runRWSLC i s p+ where f x = let (_, s2, w2) = x in (s2, w2)+{-# INLINABLE execRWSLC #-}++-- | Wrap the base monad in 'RWSS.RWST'+--+-- Since 1.0.11+rwsC+ :: (Monad m, Monoid w) =>+ (r -> s -> ConduitT i o m (a, s, w)) -> ConduitT i o (RWSS.RWST r w s m) a+rwsC k = do+ i <- lift RWSS.ask+ s <- lift RWSS.get+ (r, s', w) <- transPipe lift (k i s)+ lift $ do+ RWSS.put s'+ RWSS.tell w+ return r+{-# INLINABLE rwsC #-}++-- | Run 'RWSS.RWST' in the base monad+--+-- Since 1.0.11+runRWSC+ :: (Monad m, Monoid w) =>+ r+ -> s+ -> ConduitT i o (RWSS.RWST r w s m) res+ -> ConduitT i o m (res, s, w)+runRWSC r s0 = thread toRes run (s0, mempty)+ where+ toRes a (s, w) = (a, s, w)+ run m (s, w) = do+ (res, s', w') <- RWSS.runRWST m r s+ return (res, (s', w `mappend` w'))+{-# INLINABLE runRWSC #-}++-- | Evaluate 'RWSS.RWST' in the base monad+--+-- Since 1.0.11+evalRWSC+ :: (Monad m, Monoid w) =>+ r+ -> s+ -> ConduitT i o (RWSS.RWST r w s m) res+ -> ConduitT i o m (res, w)+evalRWSC i s p = fmap f $ runRWSC i s p+ where f x = let (r, _, w) = x in (r, w)+{-# INLINABLE evalRWSC #-}++-- | Execute 'RWSS.RWST' in the base monad+--+-- Since 1.0.11+execRWSC+ :: (Monad m, Monoid w) =>+ r+ -> s+ -> ConduitT i o (RWSS.RWST r w s m) res+ -> ConduitT i o m (s, w)+execRWSC i s p = fmap f $ runRWSC i s p+ where f x = let (_, s2, w2) = x in (s2, w2)+{-# INLINABLE execRWSC #-}
+ src/Data/Conduit/List.hs view
@@ -0,0 +1,844 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE Trustworthy #-}+-- | /NOTE/ It is recommended to start using "Data.Conduit.Combinators" instead+-- of this module.+--+-- Higher-level functions to interact with the elements of a stream. Most of+-- these are based on list functions.+--+-- For many purposes, it's recommended to use the conduit-combinators library,+-- which provides a more complete set of functions.+--+-- Note that these functions all deal with individual elements of a stream as a+-- sort of \"black box\", where there is no introspection of the contained+-- elements. Values such as @ByteString@ and @Text@ will likely need to be+-- treated specially to deal with their contents properly (@Word8@ and @Char@,+-- respectively). See the "Data.Conduit.Binary" and "Data.Conduit.Text"+-- modules.+module Data.Conduit.List+ ( -- * Sources+ sourceList+ , sourceNull+ , unfold+ , unfoldEither+ , unfoldM+ , unfoldEitherM+ , enumFromTo+ , iterate+ , replicate+ , replicateM+ -- * Sinks+ -- ** Pure+ , fold+ , foldMap+ , take+ , drop+ , head+ , peek+ , consume+ , sinkNull+ -- ** Monadic+ , foldMapM+ , foldM+ , mapM_+ -- * Conduits+ -- ** Pure+ , map+ , mapMaybe+ , mapFoldable+ , catMaybes+ , concat+ , concatMap+ , concatMapAccum+ , scanl+ , scan+ , mapAccum+ , chunksOf+ , groupBy+ , groupOn1+ , isolate+ , filter+ -- ** Monadic+ , mapM+ , iterM+ , scanlM+ , scanM+ , mapAccumM+ , mapMaybeM+ , mapFoldableM+ , concatMapM+ , concatMapAccumM+ -- * Misc+ , sequence+ ) where++import qualified Prelude+import Prelude+ ( ($), return, (==), (-), Int+ , (.), id, Maybe (..), Monad+ , Either (..)+ , Bool (..)+ , (>>)+ , (>>=)+ , seq+ , otherwise+ , Enum, Eq+ , maybe+ , (<=)+ , (>)+ )+import Data.Monoid (Monoid, mempty, mappend)+import qualified Data.Foldable as F+import Data.Conduit+import Data.Conduit.Internal.Fusion+import Data.Conduit.Internal.List.Stream+import qualified Data.Conduit.Internal as CI+import Control.Monad (when, (<=<), liftM, void)+import Control.Monad.Trans.Class (lift)++-- Defines INLINE_RULE0, INLINE_RULE, STREAMING0, and STREAMING.+#include "fusion-macros.h"++-- | Generate a source from a seed value.+--+-- Subject to fusion+--+-- Since 0.4.2+unfold, unfoldC :: Monad m+ => (b -> Maybe (a, b))+ -> b+ -> ConduitT i a m ()+unfoldC f =+ go+ where+ go seed =+ case f seed of+ Just (a, seed') -> yield a >> go seed'+ Nothing -> return ()+{-# INLINE unfoldC #-}+STREAMING(unfold, unfoldC, unfoldS, f x)++-- | Generate a source from a seed value with a return value.+--+-- Subject to fusion+--+-- @since 1.2.11+unfoldEither, unfoldEitherC :: Monad m+ => (b -> Either r (a, b))+ -> b+ -> ConduitT i a m r+unfoldEitherC f =+ go+ where+ go seed =+ case f seed of+ Right (a, seed') -> yield a >> go seed'+ Left r -> return r+{-# INLINE unfoldEitherC #-}+STREAMING(unfoldEither, unfoldEitherC, unfoldEitherS, f x)++-- | A monadic unfold.+--+-- Subject to fusion+--+-- Since 1.1.2+unfoldM, unfoldMC :: Monad m+ => (b -> m (Maybe (a, b)))+ -> b+ -> ConduitT i a m ()+unfoldMC f =+ go+ where+ go seed = do+ mres <- lift $ f seed+ case mres of+ Just (a, seed') -> yield a >> go seed'+ Nothing -> return ()+STREAMING(unfoldM, unfoldMC, unfoldMS, f seed)++-- | A monadic unfoldEither.+--+-- Subject to fusion+--+-- @since 1.2.11+unfoldEitherM, unfoldEitherMC :: Monad m+ => (b -> m (Either r (a, b)))+ -> b+ -> ConduitT i a m r+unfoldEitherMC f =+ go+ where+ go seed = do+ mres <- lift $ f seed+ case mres of+ Right (a, seed') -> yield a >> go seed'+ Left r -> return r+STREAMING(unfoldEitherM, unfoldEitherMC, unfoldEitherMS, f seed)++-- | Yield the values from the list.+--+-- Subject to fusion+sourceList, sourceListC :: Monad m => [a] -> ConduitT i a m ()+sourceListC = Prelude.mapM_ yield+{-# INLINE sourceListC #-}+STREAMING(sourceList, sourceListC, sourceListS, xs)++-- | Enumerate from a value to a final value, inclusive, via 'succ'.+--+-- This is generally more efficient than using @Prelude@\'s @enumFromTo@ and+-- combining with @sourceList@ since this avoids any intermediate data+-- structures.+--+-- Subject to fusion+--+-- Since 0.4.2+enumFromTo, enumFromToC :: (Enum a, Prelude.Ord a, Monad m)+ => a+ -> a+ -> ConduitT i a m ()+enumFromToC x0 y =+ loop x0+ where+ loop x+ | x Prelude.> y = return ()+ | otherwise = yield x >> loop (Prelude.succ x)+{-# INLINE enumFromToC #-}+STREAMING(enumFromTo, enumFromToC, enumFromToS, x0 y)++-- | Produces an infinite stream of repeated applications of f to x.+--+-- Subject to fusion+--+iterate, iterateC :: Monad m => (a -> a) -> a -> ConduitT i a m ()+iterateC f =+ go+ where+ go a = yield a >> go (f a)+{-# INLINE iterateC #-}+STREAMING(iterate, iterateC, iterateS, f a)++-- | Replicate a single value the given number of times.+--+-- Subject to fusion+--+-- Since 1.2.0+replicate, replicateC :: Monad m => Int -> a -> ConduitT i a m ()+replicateC cnt0 a =+ loop cnt0+ where+ loop i+ | i <= 0 = return ()+ | otherwise = yield a >> loop (i - 1)+{-# INLINE replicateC #-}+STREAMING(replicate, replicateC, replicateS, cnt0 a)++-- | Replicate a monadic value the given number of times.+--+-- Subject to fusion+--+-- Since 1.2.0+replicateM, replicateMC :: Monad m => Int -> m a -> ConduitT i a m ()+replicateMC cnt0 ma =+ loop cnt0+ where+ loop i+ | i <= 0 = return ()+ | otherwise = lift ma >>= yield >> loop (i - 1)+{-# INLINE replicateMC #-}+STREAMING(replicateM, replicateMC, replicateMS, cnt0 ma)++-- | A strict left fold.+--+-- Subject to fusion+--+-- Since 0.3.0+fold, foldC :: Monad m+ => (b -> a -> b)+ -> b+ -> ConduitT a o m b+foldC f =+ loop+ where+ loop !accum = await >>= maybe (return accum) (loop . f accum)+{-# INLINE foldC #-}+STREAMING(fold, foldC, foldS, f accum)++-- | A monadic strict left fold.+--+-- Subject to fusion+--+-- Since 0.3.0+foldM, foldMC :: Monad m+ => (b -> a -> m b)+ -> b+ -> ConduitT a o m b+foldMC f =+ loop+ where+ loop accum = do+ await >>= maybe (return accum) go+ where+ go a = do+ accum' <- lift $ f accum a+ accum' `seq` loop accum'+{-# INLINE foldMC #-}+STREAMING(foldM, foldMC, foldMS, f accum)++-----------------------------------------------------------------+-- These are for cases where- for whatever reason- stream fusion cannot be+-- applied.+connectFold :: Monad m => ConduitT () a m () -> (b -> a -> b) -> b -> m b+connectFold (CI.ConduitT src0) f =+ go (src0 CI.Done)+ where+ go (CI.Done ()) b = return b+ go (CI.HaveOutput src a) b = go src Prelude.$! f b a+ go (CI.NeedInput _ c) b = go (c ()) b+ go (CI.Leftover src ()) b = go src b+ go (CI.PipeM msrc) b = do+ src <- msrc+ go src b+{-# INLINE connectFold #-}+{-# RULES "conduit: $$ fold" forall src f b. runConduit (src .| fold f b) = connectFold src f b #-}++connectFoldM :: Monad m => ConduitT () a m () -> (b -> a -> m b) -> b -> m b+connectFoldM (CI.ConduitT src0) f =+ go (src0 CI.Done)+ where+ go (CI.Done ()) b = return b+ go (CI.HaveOutput src a) b = do+ !b' <- f b a+ go src b'+ go (CI.NeedInput _ c) b = go (c ()) b+ go (CI.Leftover src ()) b = go src b+ go (CI.PipeM msrc) b = do+ src <- msrc+ go src b+{-# INLINE connectFoldM #-}+{-# RULES "conduit: $$ foldM" forall src f b. runConduit (src .| foldM f b) = connectFoldM src f b #-}+-----------------------------------------------------------------++-- | A monoidal strict left fold.+--+-- Subject to fusion+--+-- Since 0.5.3+foldMap :: (Monad m, Monoid b)+ => (a -> b)+ -> ConduitT a o m b+INLINE_RULE(foldMap, f, let combiner accum = mappend accum . f in fold combiner mempty)++-- | A monoidal strict left fold in a Monad.+--+-- Since 1.0.8+foldMapM :: (Monad m, Monoid b)+ => (a -> m b)+ -> ConduitT a o m b+INLINE_RULE(foldMapM, f, let combiner accum = liftM (mappend accum) . f in foldM combiner mempty)++-- | Apply the action to all values in the stream.+--+-- Subject to fusion+--+-- Since 0.3.0+mapM_, mapM_C :: Monad m+ => (a -> m ())+ -> ConduitT a o m ()+mapM_C f = awaitForever $ lift . f+{-# INLINE mapM_C #-}+STREAMING(mapM_, mapM_C, mapM_S, f)++srcMapM_ :: Monad m => ConduitT () a m () -> (a -> m ()) -> m ()+srcMapM_ (CI.ConduitT src) f =+ go (src CI.Done)+ where+ go (CI.Done ()) = return ()+ go (CI.PipeM mp) = mp >>= go+ go (CI.Leftover p ()) = go p+ go (CI.HaveOutput p o) = f o >> go p+ go (CI.NeedInput _ c) = go (c ())+{-# INLINE srcMapM_ #-}+{-# RULES "conduit: connect to mapM_" [2] forall f src. runConduit (src .| mapM_ f) = srcMapM_ src f #-}++-- | Ignore a certain number of values in the stream. This function is+-- semantically equivalent to:+--+-- > drop i = take i >> return ()+--+-- However, @drop@ is more efficient as it does not need to hold values in+-- memory.+--+-- Subject to fusion+--+-- Since 0.3.0+drop, dropC :: Monad m+ => Int+ -> ConduitT a o m ()+dropC =+ loop+ where+ loop i | i <= 0 = return ()+ loop count = await >>= maybe (return ()) (\_ -> loop (count - 1))+{-# INLINE dropC #-}+STREAMING(drop, dropC, dropS, i)++-- | Take some values from the stream and return as a list. If you want to+-- instead create a conduit that pipes data to another sink, see 'isolate'.+-- This function is semantically equivalent to:+--+-- > take i = isolate i =$ consume+--+-- Subject to fusion+--+-- Since 0.3.0+take, takeC :: Monad m+ => Int+ -> ConduitT a o m [a]+takeC =+ loop id+ where+ loop front count | count <= 0 = return $ front []+ loop front count = await >>= maybe+ (return $ front [])+ (\x -> loop (front . (x:)) (count - 1))+{-# INLINE takeC #-}+STREAMING(take, takeC, takeS, i)++-- | Take a single value from the stream, if available.+--+-- Subject to fusion+--+-- Since 0.3.0+head, headC :: Monad m => ConduitT a o m (Maybe a)+headC = await+{-# INLINE headC #-}+STREAMING0(head, headC, headS)++-- | Look at the next value in the stream, if available. This function will not+-- change the state of the stream.+--+-- Since 0.3.0+peek :: Monad m => ConduitT a o m (Maybe a)+peek = await >>= maybe (return Nothing) (\x -> leftover x >> return (Just x))++-- | Apply a transformation to all values in a stream.+--+-- Subject to fusion+--+-- Since 0.3.0+map, mapC :: Monad m => (a -> b) -> ConduitT a b m ()+mapC f = awaitForever $ yield . f+{-# INLINE mapC #-}+STREAMING(map, mapC, mapS, f)++-- Since a Source never has any leftovers, fusion rules on it are safe.+{-+{-# RULES "conduit: source/map fusion .|" forall f src. src .| map f = mapFuseRight src f #-}++mapFuseRight :: Monad m => Source m a -> (a -> b) -> Source m b+mapFuseRight src f = CIC.mapOutput f src+{-# INLINE mapFuseRight #-}+-}++{-++It might be nice to include these rewrite rules, but they may have subtle+differences based on leftovers.++{-# RULES "conduit: map-to-mapOutput pipeL" forall f src. pipeL src (map f) = mapOutput f src #-}+{-# RULES "conduit: map-to-mapOutput $=" forall f src. src $= (map f) = mapOutput f src #-}+{-# RULES "conduit: map-to-mapOutput pipe" forall f src. pipe src (map f) = mapOutput f src #-}+{-# RULES "conduit: map-to-mapOutput >+>" forall f src. src >+> (map f) = mapOutput f src #-}++{-# RULES "conduit: map-to-mapInput pipeL" forall f sink. pipeL (map f) sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}+{-# RULES "conduit: map-to-mapInput =$" forall f sink. map f =$ sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}+{-# RULES "conduit: map-to-mapInput pipe" forall f sink. pipe (map f) sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}+{-# RULES "conduit: map-to-mapInput >+>" forall f sink. map f >+> sink = mapInput f (Prelude.const Prelude.Nothing) sink #-}++{-# RULES "conduit: map-to-mapOutput .|" forall f con. con .| map f = mapOutput f con #-}+{-# RULES "conduit: map-to-mapInput .|" forall f con. map f .| con = mapInput f (Prelude.const Prelude.Nothing) con #-}++{-# INLINE [1] map #-}++-}++-- | Apply a monadic transformation to all values in a stream.+--+-- If you do not need the transformed values, and instead just want the monadic+-- side-effects of running the action, see 'mapM_'.+--+-- Subject to fusion+--+-- Since 0.3.0+mapM, mapMC :: Monad m => (a -> m b) -> ConduitT a b m ()+mapMC f = awaitForever $ \a -> lift (f a) >>= yield+{-# INLINE mapMC #-}+STREAMING(mapM, mapMC, mapMS, f)++-- | Apply a monadic action on all values in a stream.+--+-- This @Conduit@ can be used to perform a monadic side-effect for every+-- value, whilst passing the value through the @Conduit@ as-is.+--+-- > iterM f = mapM (\a -> f a >>= \() -> return a)+--+-- Subject to fusion+--+-- Since 0.5.6+iterM, iterMC :: Monad m => (a -> m ()) -> ConduitT a a m ()+iterMC f = awaitForever $ \a -> lift (f a) >> yield a+{-# INLINE iterMC #-}+STREAMING(iterM, iterMC, iterMS, f)++-- | Apply a transformation that may fail to all values in a stream, discarding+-- the failures.+--+-- Subject to fusion+--+-- Since 0.5.1+mapMaybe, mapMaybeC :: Monad m => (a -> Maybe b) -> ConduitT a b m ()+mapMaybeC f = awaitForever $ maybe (return ()) yield . f+{-# INLINE mapMaybeC #-}+STREAMING(mapMaybe, mapMaybeC, mapMaybeS, f)++-- | Apply a monadic transformation that may fail to all values in a stream,+-- discarding the failures.+--+-- Subject to fusion+--+-- Since 0.5.1+mapMaybeM, mapMaybeMC :: Monad m => (a -> m (Maybe b)) -> ConduitT a b m ()+mapMaybeMC f = awaitForever $ maybe (return ()) yield <=< lift . f+{-# INLINE mapMaybeMC #-}+STREAMING(mapMaybeM, mapMaybeMC, mapMaybeMS, f)++-- | Filter the @Just@ values from a stream, discarding the @Nothing@ values.+--+-- Subject to fusion+--+-- Since 0.5.1+catMaybes, catMaybesC :: Monad m => ConduitT (Maybe a) a m ()+catMaybesC = awaitForever $ maybe (return ()) yield+{-# INLINE catMaybesC #-}+STREAMING0(catMaybes, catMaybesC, catMaybesS)++-- | Generalization of 'catMaybes'. It puts all values from+-- 'F.Foldable' into stream.+--+-- Subject to fusion+--+-- Since 1.0.6+concat, concatC :: (Monad m, F.Foldable f) => ConduitT (f a) a m ()+concatC = awaitForever $ F.mapM_ yield+{-# INLINE concatC #-}+STREAMING0(concat, concatC, concatS)++-- | Apply a transformation to all values in a stream, concatenating the output+-- values.+--+-- Subject to fusion+--+-- Since 0.3.0+concatMap, concatMapC :: Monad m => (a -> [b]) -> ConduitT a b m ()+concatMapC f = awaitForever $ sourceList . f+{-# INLINE concatMapC #-}+STREAMING(concatMap, concatMapC, concatMapS, f)++-- | Apply a monadic transformation to all values in a stream, concatenating+-- the output values.+--+-- Subject to fusion+--+-- Since 0.3.0+concatMapM, concatMapMC :: Monad m => (a -> m [b]) -> ConduitT a b m ()+concatMapMC f = awaitForever $ sourceList <=< lift . f+{-# INLINE concatMapMC #-}+STREAMING(concatMapM, concatMapMC, concatMapMS, f)++-- | 'concatMap' with a strict accumulator.+--+-- Subject to fusion+--+-- Since 0.3.0+concatMapAccum, concatMapAccumC :: Monad m => (a -> accum -> (accum, [b])) -> accum -> ConduitT a b m ()+concatMapAccumC f x0 = void (mapAccum f x0) .| concat+{-# INLINE concatMapAccumC #-}+STREAMING(concatMapAccum, concatMapAccumC, concatMapAccumS, f x0)++-- | Deprecated synonym for @mapAccum@+--+-- Since 1.0.6+scanl :: Monad m => (a -> s -> (s, b)) -> s -> ConduitT a b m ()+scanl f s = void $ mapAccum f s+{-# DEPRECATED scanl "Use mapAccum instead" #-}++-- | Deprecated synonym for @mapAccumM@+--+-- Since 1.0.6+scanlM :: Monad m => (a -> s -> m (s, b)) -> s -> ConduitT a b m ()+scanlM f s = void $ mapAccumM f s+{-# DEPRECATED scanlM "Use mapAccumM instead" #-}++-- | Analog of @mapAccumL@ for lists. Note that in contrast to @mapAccumL@, the function argument+-- takes the accumulator as its second argument, not its first argument, and the accumulated value+-- is strict.+--+-- Subject to fusion+--+-- Since 1.1.1+mapAccum, mapAccumC :: Monad m => (a -> s -> (s, b)) -> s -> ConduitT a b m s+mapAccumC f =+ loop+ where+ loop !s = await >>= maybe (return s) go+ where+ go a = case f a s of+ (s', b) -> yield b >> loop s'+STREAMING(mapAccum, mapAccumC, mapAccumS, f s)++-- | Monadic `mapAccum`.+--+-- Subject to fusion+--+-- Since 1.1.1+mapAccumM, mapAccumMC :: Monad m => (a -> s -> m (s, b)) -> s -> ConduitT a b m s+mapAccumMC f =+ loop+ where+ loop !s = await >>= maybe (return s) go+ where+ go a = do (s', b) <- lift $ f a s+ yield b+ loop s'+{-# INLINE mapAccumMC #-}+STREAMING(mapAccumM, mapAccumMC, mapAccumMS, f s)++-- | Analog of 'Prelude.scanl' for lists.+--+-- Subject to fusion+--+-- Since 1.1.1+scan :: Monad m => (a -> b -> b) -> b -> ConduitT a b m b+INLINE_RULE(scan, f, mapAccum (\a b -> let r = f a b in (r, r)))++-- | Monadic @scanl@.+--+-- Subject to fusion+--+-- Since 1.1.1+scanM :: Monad m => (a -> b -> m b) -> b -> ConduitT a b m b+INLINE_RULE(scanM, f, mapAccumM (\a b -> f a b >>= \r -> return (r, r)))++-- | 'concatMapM' with a strict accumulator.+--+-- Subject to fusion+--+-- Since 0.3.0+concatMapAccumM, concatMapAccumMC :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> ConduitT a b m ()+concatMapAccumMC f x0 = void (mapAccumM f x0) .| concat+{-# INLINE concatMapAccumMC #-}+STREAMING(concatMapAccumM, concatMapAccumMC, concatMapAccumMS, f x0)++-- | Generalization of 'mapMaybe' and 'concatMap'. It applies function+-- to all values in a stream and send values inside resulting+-- 'Foldable' downstream.+--+-- Subject to fusion+--+-- Since 1.0.6+mapFoldable, mapFoldableC :: (Monad m, F.Foldable f) => (a -> f b) -> ConduitT a b m ()+mapFoldableC f = awaitForever $ F.mapM_ yield . f+{-# INLINE mapFoldableC #-}+STREAMING(mapFoldable, mapFoldableC, mapFoldableS, f)++-- | Monadic variant of 'mapFoldable'.+--+-- Subject to fusion+--+-- Since 1.0.6+mapFoldableM, mapFoldableMC :: (Monad m, F.Foldable f) => (a -> m (f b)) -> ConduitT a b m ()+mapFoldableMC f = awaitForever $ F.mapM_ yield <=< lift . f+{-# INLINE mapFoldableMC #-}+STREAMING(mapFoldableM, mapFoldableMC, mapFoldableMS, f)++-- | Consume all values from the stream and return as a list. Note that this+-- will pull all values into memory.+--+-- Subject to fusion+--+-- Since 0.3.0+consume, consumeC :: Monad m => ConduitT a o m [a]+consumeC =+ loop id+ where+ loop front = await >>= maybe (return $ front []) (\x -> loop $ front . (x:))+{-# INLINE consumeC #-}+STREAMING0(consume, consumeC, consumeS)++-- | Group a stream into chunks of a given size. The last chunk may contain+-- fewer than n elements.+--+-- Subject to fusion+--+-- Since 1.2.9+chunksOf :: Monad m => Int -> ConduitT a [a] m ()+chunksOf n =+ start+ where+ start = await >>= maybe (return ()) (\x -> loop n (x:))++ loop !count rest =+ await >>= maybe (yield (rest [])) go+ where+ go y+ | count > 1 = loop (count - 1) (rest . (y:))+ | otherwise = yield (rest []) >> loop n (y:)++-- | Grouping input according to an equality function.+--+-- Subject to fusion+--+-- Since 0.3.0+groupBy, groupByC :: Monad m => (a -> a -> Bool) -> ConduitT a [a] m ()+groupByC f =+ start+ where+ start = await >>= maybe (return ()) (loop id)++ loop rest x =+ await >>= maybe (yield (x : rest [])) go+ where+ go y+ | f x y = loop (rest . (y:)) x+ | otherwise = yield (x : rest []) >> loop id y+STREAMING(groupBy, groupByC, groupByS, f)++-- | 'groupOn1' is similar to @groupBy id@+--+-- returns a pair, indicating there are always 1 or more items in the grouping.+-- This is designed to be converted into a NonEmpty structure+-- but it avoids a dependency on another package+--+-- > import Data.List.NonEmpty+-- >+-- > groupOn1 :: (Monad m, Eq b) => (a -> b) -> Conduit a m (NonEmpty a)+-- > groupOn1 f = CL.groupOn1 f .| CL.map (uncurry (:|))+--+-- Subject to fusion+--+-- Since 1.1.7+groupOn1, groupOn1C :: (Monad m, Eq b)+ => (a -> b)+ -> ConduitT a (a, [a]) m ()+groupOn1C f =+ start+ where+ start = await >>= maybe (return ()) (loop id)++ loop rest x =+ await >>= maybe (yield (x, rest [])) go+ where+ go y+ | f x == f y = loop (rest . (y:)) x+ | otherwise = yield (x, rest []) >> loop id y+STREAMING(groupOn1, groupOn1C, groupOn1S, f)++-- | Ensure that the inner sink consumes no more than the given number of+-- values. Note this this does /not/ ensure that the sink consumes all of those+-- values. To get the latter behavior, combine with 'sinkNull', e.g.:+--+-- > src $$ do+-- > x <- isolate count =$ do+-- > x <- someSink+-- > sinkNull+-- > return x+-- > someOtherSink+-- > ...+--+-- Subject to fusion+--+-- Since 0.3.0+isolate, isolateC :: Monad m => Int -> ConduitT a a m ()+isolateC =+ loop+ where+ loop count | count <= 0 = return ()+ loop count = await >>= maybe (return ()) (\x -> yield x >> loop (count - 1))+STREAMING(isolate, isolateC, isolateS, count)++-- | Keep only values in the stream passing a given predicate.+--+-- Subject to fusion+--+-- Since 0.3.0+filter, filterC :: Monad m => (a -> Bool) -> ConduitT a a m ()+filterC f = awaitForever $ \i -> when (f i) (yield i)+STREAMING(filter, filterC, filterS, f)++filterFuseRight+ :: Monad m+ => ConduitT i o m ()+ -> (o -> Bool)+ -> ConduitT i o m ()+filterFuseRight (CI.ConduitT src) f = CI.ConduitT $ \rest -> let+ go (CI.Done ()) = rest ()+ go (CI.PipeM mp) = CI.PipeM (liftM go mp)+ go (CI.Leftover p i) = CI.Leftover (go p) i+ go (CI.HaveOutput p o)+ | f o = CI.HaveOutput (go p) o+ | otherwise = go p+ go (CI.NeedInput p c) = CI.NeedInput (go . p) (go . c)+ in go (src CI.Done)+-- Intermediate finalizers are dropped, but this is acceptable: the next+-- yielded value would be demanded by downstream in any event, and that new+-- finalizer will always override the existing finalizer.+{-# RULES "conduit: source/filter fusion .|" forall f src. src .| filter f = filterFuseRight src f #-}+{-# INLINE filterFuseRight #-}++-- | Ignore the remainder of values in the source. Particularly useful when+-- combined with 'isolate'.+--+-- Subject to fusion+--+-- Since 0.3.0+sinkNull, sinkNullC :: Monad m => ConduitT i o m ()+sinkNullC = awaitForever $ \_ -> return ()+{-# INLINE sinkNullC #-}+STREAMING0(sinkNull, sinkNullC, sinkNullS)++srcSinkNull :: Monad m => ConduitT () o m () -> m ()+srcSinkNull (CI.ConduitT src) =+ go (src CI.Done)+ where+ go (CI.Done ()) = return ()+ go (CI.PipeM mp) = mp >>= go+ go (CI.Leftover p ()) = go p+ go (CI.HaveOutput p _) = go p+ go (CI.NeedInput _ c) = go (c ())+{-# INLINE srcSinkNull #-}+{-# RULES "conduit: connect to sinkNull" forall src. runConduit (src .| sinkNull) = srcSinkNull src #-}++-- | A source that outputs no values. Note that this is just a type-restricted+-- synonym for 'mempty'.+--+-- Subject to fusion+--+-- Since 0.3.0+sourceNull, sourceNullC :: Monad m => ConduitT i o m ()+sourceNullC = return ()+{-# INLINE sourceNullC #-}+STREAMING0(sourceNull, sourceNullC, sourceNullS)++-- | Run a @Pipe@ repeatedly, and output its result value downstream. Stops+-- when no more input is available from upstream.+--+-- Since 0.5.0+sequence :: Monad m+ => ConduitT i o m o -- ^ @Pipe@ to run repeatedly+ -> ConduitT i o m ()+sequence sink =+ self+ where+ self = awaitForever $ \i -> leftover i >> sink >>= yield
+ src/Data/Streaming/FileRead.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE CPP #-}+-- | The standard @openFile@ call on Windows causing problematic file locking+-- in some cases. This module provides a cross-platform file reading API+-- without the file locking problems on Windows.+--+-- This module /always/ opens files in binary mode.+--+-- @readChunk@ will return an empty @ByteString@ on EOF.+module Data.Streaming.FileRead+ ( ReadHandle+ , openFile+ , closeFile+ , readChunk+ ) where++#if WINDOWS++import System.Win32File++#else++import qualified System.IO as IO+import qualified Data.ByteString as S+import Data.ByteString.Lazy.Internal (defaultChunkSize)++newtype ReadHandle = ReadHandle IO.Handle++openFile :: FilePath -> IO ReadHandle+openFile fp = ReadHandle `fmap` IO.openBinaryFile fp IO.ReadMode++closeFile :: ReadHandle -> IO ()+closeFile (ReadHandle h) = IO.hClose h++readChunk :: ReadHandle -> IO S.ByteString+readChunk (ReadHandle h) = S.hGetSome h defaultChunkSize++#endif
+ src/Data/Streaming/Filesystem.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ScopedTypeVariables #-}+-- | Streaming functions for interacting with the filesystem.+module Data.Streaming.Filesystem+ ( DirStream+ , openDirStream+ , readDirStream+ , closeDirStream+ , FileType (..)+ , getFileType+ ) where++import Data.Typeable (Typeable)++#if WINDOWS++import qualified System.Win32 as Win32+import System.FilePath ((</>))+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import System.Directory (doesFileExist, doesDirectoryExist)++data DirStream = DirStream !Win32.HANDLE !Win32.FindData !(IORef Bool)+ deriving Typeable++openDirStream :: FilePath -> IO DirStream+openDirStream fp = do+ (h, fdat) <- Win32.findFirstFile $ fp </> "*"+ imore <- newIORef True -- always at least two records, "." and ".."+ return $! DirStream h fdat imore++closeDirStream :: DirStream -> IO ()+closeDirStream (DirStream h _ _) = Win32.findClose h++readDirStream :: DirStream -> IO (Maybe FilePath)+readDirStream ds@(DirStream h fdat imore) = do+ more <- readIORef imore+ if more+ then do+ filename <- Win32.getFindDataFileName fdat+ Win32.findNextFile h fdat >>= writeIORef imore+ if filename == "." || filename == ".."+ then readDirStream ds+ else return $ Just filename+ else return Nothing++isSymlink :: FilePath -> IO Bool+isSymlink _ = return False++getFileType :: FilePath -> IO FileType+getFileType fp = do+ isFile <- doesFileExist fp+ if isFile+ then return FTFile+ else do+ isDir <- doesDirectoryExist fp+ return $ if isDir then FTDirectory else FTOther++#else++import System.Posix.Directory (DirStream, openDirStream, closeDirStream)+import qualified System.Posix.Directory as Posix+import qualified System.Posix.Files as PosixF+import Control.Exception (try, IOException)++readDirStream :: DirStream -> IO (Maybe FilePath)+readDirStream ds = do+ fp <- Posix.readDirStream ds+ case fp of+ "" -> return Nothing+ "." -> readDirStream ds+ ".." -> readDirStream ds+ _ -> return $ Just fp++getFileType :: FilePath -> IO FileType+getFileType fp = do+ s <- PosixF.getSymbolicLinkStatus fp+ case () of+ ()+ | PosixF.isRegularFile s -> return FTFile+ | PosixF.isDirectory s -> return FTDirectory+ | PosixF.isSymbolicLink s -> do+ es' <- try $ PosixF.getFileStatus fp+ case es' of+ Left (_ :: IOException) -> return FTOther+ Right s'+ | PosixF.isRegularFile s' -> return FTFileSym+ | PosixF.isDirectory s' -> return FTDirectorySym+ | otherwise -> return FTOther+ | otherwise -> return FTOther++#endif++data FileType+ = FTFile+ | FTFileSym -- ^ symlink to file+ | FTDirectory+ | FTDirectorySym -- ^ symlink to a directory+ | FTOther+ deriving (Show, Read, Eq, Ord, Typeable)
+ src/System/Win32File.hsc view
@@ -0,0 +1,100 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module System.Win32File+ ( openFile+ , readChunk+ , closeFile+ , ReadHandle+ ) where++import Foreign.C.String (CString)+import Foreign.Ptr (castPtr)+import Foreign.Marshal.Alloc (mallocBytes, free)+import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)+#if __GLASGOW_HASKELL__ >= 704+import Foreign.C.Types (CInt (..))+#else+import Foreign.C.Types (CInt)+#endif+import Foreign.C.Error (throwErrnoIfMinus1Retry)+import Foreign.Ptr (Ptr)+import Data.Bits (Bits, (.|.))+import qualified Data.ByteString as S+import qualified Data.ByteString.Unsafe as BU+import qualified Data.ByteString.Internal as BI+import Data.Text (pack)+import Data.Text.Encoding (encodeUtf16LE)+import Data.Word (Word8)+import Prelude hiding (read)+import GHC.ForeignPtr (mallocPlainForeignPtrBytes)+import Data.ByteString.Lazy.Internal (defaultChunkSize)+++#include <fcntl.h>+#include <Share.h>+#include <SYS/Stat.h>+#include <errno.h>++newtype OFlag = OFlag CInt+ deriving (Num, Bits, Show, Eq)++#{enum OFlag, OFlag+ , oBinary = _O_BINARY+ , oRdonly = _O_RDONLY+ , oWronly = _O_WRONLY+ , oCreat = _O_CREAT+ }++newtype SHFlag = SHFlag CInt+ deriving (Num, Bits, Show, Eq)++#{enum SHFlag, SHFlag+ , shDenyno = _SH_DENYNO+ }++newtype PMode = PMode CInt+ deriving (Num, Bits, Show, Eq)++#{enum PMode, PMode+ , pIread = _S_IREAD+ , pIwrite = _S_IWRITE+ }++foreign import ccall "_wsopen"+ c_wsopen :: CString -> OFlag -> SHFlag -> PMode -> IO CInt++foreign import ccall "_read"+ c_read :: ReadHandle -> Ptr Word8 -> CInt -> IO CInt++foreign import ccall "_write"+ c_write :: ReadHandle -> Ptr Word8 -> CInt -> IO CInt++foreign import ccall "_close"+ closeFile :: ReadHandle -> IO ()++newtype ReadHandle = ReadHandle CInt++openFile :: FilePath -> IO ReadHandle+openFile fp = do+ -- need to append a null char+ -- note that useAsCString is not sufficient, as we need to have two+ -- null octets to account for UTF16 encoding+ let bs = encodeUtf16LE $ pack $ fp ++ "\0"+ h <- BU.unsafeUseAsCString bs $ \str ->+ throwErrnoIfMinus1Retry "Data.Streaming.FileRead.openFile" $+ c_wsopen+ str+ (oBinary .|. oRdonly)+ shDenyno+ pIread+ return $ ReadHandle h++readChunk :: ReadHandle -> IO S.ByteString+readChunk fd = do+ fp <- mallocPlainForeignPtrBytes defaultChunkSize+ withForeignPtr fp $ \p -> do+ len <- throwErrnoIfMinus1Retry "System.Win32File.read" $ c_read fd p+ (fromIntegral defaultChunkSize)+ if len == 0+ then return $! S.empty+ else return $! BI.PS fp 0 (fromIntegral len)
test/Data/Conduit/Extra/ZipConduitSpec.hs view
@@ -12,7 +12,7 @@ conduit2 = CL.concatMap (replicate 2) conduit = getZipConduit $ ZipConduit conduit1 <* ZipConduit conduit2 sink = CL.consume- res <- src $$ conduit =$ sink+ res <- runConduit $ src .| conduit .| sink res `shouldBe` [2, 1, 1, 3, 2, 2, 4, 3, 3] it "sequenceConduits" $ do let src = mapM_ yield [1..3 :: Int]@@ -22,7 +22,7 @@ x <- sequenceConduits [conduit1, conduit2] yield $ length x + 10 sink = CL.consume- res <- src $$ conduit =$ sink+ res <- runConduit $ src .| conduit .| sink res `shouldBe` [2, 1, 1, 3, 2, 2, 4, 3, 3, 12] it "ZipConduitMonad" $ do let src = mapM_ yield [1..3 :: Int]@@ -30,5 +30,5 @@ conduit2 = CL.map id conduit = getZipConduit $ ZipConduit conduit1 <* ZipConduit conduit2 sink = CL.consume- res <- src $$ conduit =$ sink+ res <- runConduit $ src .| conduit .| sink res `shouldBe` [2, 1, 3, 2, 4, 3]
test/Data/Conduit/StreamSpec.hs view
@@ -146,19 +146,19 @@ Prelude.map f qit "mapM" $ \(getBlind -> (f :: Int -> M Int)) ->- mapM f `checkConduitM`+ mapM f `checkConduitT` Prelude.mapM f qit "mapMS" $ \(getBlind -> (f :: Int -> M Int)) ->- mapMS f `checkStreamConduitM`+ mapMS f `checkStreamConduitT` Prelude.mapM f qit "iterM" $ \(getBlind -> (f :: Int -> M ())) ->- iterM f `checkConduitM`+ iterM f `checkConduitT` iterML f qit "iterMS" $ \(getBlind -> (f :: Int -> M ())) ->- iterMS f `checkStreamConduitM`+ iterMS f `checkStreamConduitT` iterML f qit "mapMaybe" $ \(getBlind -> (f :: Int -> Maybe Int)) ->@@ -170,11 +170,11 @@ Data.Maybe.mapMaybe f qit "mapMaybeM" $ \(getBlind -> (f :: Int -> M (Maybe Int))) ->- mapMaybeM f `checkConduitM`+ mapMaybeM f `checkConduitT` mapMaybeML f qit "mapMaybeMS" $ \(getBlind -> (f :: Int -> M (Maybe Int))) ->- mapMaybeMS f `checkStreamConduitM`+ mapMaybeMS f `checkStreamConduitT` mapMaybeML f qit "catMaybes" $ \() ->@@ -202,11 +202,11 @@ (Prelude.concatMap f :: [Int] -> [Int]) qit "concatMapM" $ \(getBlind -> (f :: Int -> M [Int])) ->- concatMapM f `checkConduitM`+ concatMapM f `checkConduitT` concatMapML f qit "concatMapMS" $ \(getBlind -> (f :: Int -> M [Int])) ->- concatMapMS f `checkStreamConduitM`+ concatMapMS f `checkStreamConduitT` concatMapML f qit "concatMapAccum" $ \(getBlind -> (f :: Int -> Int -> (Int, [Int])), initial :: Int) ->@@ -250,11 +250,11 @@ mapFoldableL f qit "mapFoldableM" $ \(getBlind -> (f :: Int -> M [Int])) ->- mapFoldableM f `checkConduitM`+ mapFoldableM f `checkConduitT` mapFoldableML f qit "mapFoldableMS" $ \(getBlind -> (f :: Int -> M [Int])) ->- mapFoldableMS f `checkStreamConduitM`+ mapFoldableMS f `checkStreamConduitT` mapFoldableML f qit "consume" $ \() ->@@ -312,67 +312,67 @@ -------------------------------------------------------------------------------- -- Quickcheck utilities for pure conduits / streams -checkProducer :: (Show a, Eq a) => Source Identity a -> [a] -> Property+checkProducer :: (Show a, Eq a) => ConduitT () a Identity () -> [a] -> Property checkProducer c l = checkProducerM' runIdentity c (return l) -checkStreamProducer :: (Show a, Eq a) => StreamSource Identity a -> [a] -> Property+checkStreamProducer :: (Show a, Eq a) => StreamConduitT () a Identity () -> [a] -> Property checkStreamProducer s l = checkStreamProducerM' runIdentity s (return l) -checkInfiniteProducer :: (Show a, Eq a) => Source Identity a -> [a] -> Property+checkInfiniteProducer :: (Show a, Eq a) => ConduitT () a Identity () -> [a] -> Property checkInfiniteProducer c l = checkInfiniteProducerM' runIdentity c (return l) -checkInfiniteStreamProducer :: (Show a, Eq a) => StreamSource Identity a -> [a] -> Property+checkInfiniteStreamProducer :: (Show a, Eq a) => StreamConduitT () a Identity () -> [a] -> Property checkInfiniteStreamProducer s l = checkInfiniteStreamProducerM' runIdentity s (return l) -checkConsumer :: (Show b, Eq b) => Consumer Int Identity b -> ([Int] -> b) -> Property+checkConsumer :: (Show b, Eq b) => ConduitT Int Void Identity b -> ([Int] -> b) -> Property checkConsumer c l = checkConsumerM' runIdentity c (return . l) checkStreamConsumer :: (Show b, Eq b) => StreamConsumer Int Identity b -> ([Int] -> b) -> Property checkStreamConsumer c l = checkStreamConsumerM' runIdentity c (return . l) -checkConduit :: (Show a, Arbitrary a, Show b, Eq b) => Conduit a Identity b -> ([a] -> [b]) -> Property-checkConduit c l = checkConduitM' runIdentity c (return . l)+checkConduit :: (Show a, Arbitrary a, Show b, Eq b) => ConduitT a b Identity () -> ([a] -> [b]) -> Property+checkConduit c l = checkConduitT' runIdentity c (return . l) -checkStreamConduit :: (Show a, Arbitrary a, Show b, Eq b) => StreamConduit a Identity b -> ([a] -> [b]) -> Property-checkStreamConduit c l = checkStreamConduitM' runIdentity c (return . l)+checkStreamConduit :: (Show a, Arbitrary a, Show b, Eq b) => StreamConduitT a b Identity () -> ([a] -> [b]) -> Property+checkStreamConduit c l = checkStreamConduitT' runIdentity c (return . l) --- checkConduitResult :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => ConduitM a b Identity r -> ([a] -> ([b], r)) -> Property+-- checkConduitResult :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => ConduitT a b Identity r -> ([a] -> ([b], r)) -> Property -- checkConduitResult c l = checkConduitResultM' runIdentity c (return . l) -checkStreamConduitResult :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => StreamConduitM a b Identity r -> ([a] -> ([b], r)) -> Property+checkStreamConduitResult :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => StreamConduitT a b Identity r -> ([a] -> ([b], r)) -> Property checkStreamConduitResult c l = checkStreamConduitResultM' runIdentity c (return . l) -------------------------------------------------------------------------------- -- Quickcheck utilities for conduits / streams in the M monad. -checkProducerM :: (Show a, Eq a) => Source M a -> M [a] -> Property+checkProducerM :: (Show a, Eq a) => ConduitT () a M () -> M [a] -> Property checkProducerM = checkProducerM' runM checkStreamProducerM :: (Show a, Eq a) => StreamSource M a -> M [a] -> Property checkStreamProducerM = checkStreamProducerM' runM -checkInfiniteProducerM :: (Show a, Eq a) => Source M a -> M [a] -> Property+checkInfiniteProducerM :: (Show a, Eq a) => ConduitT () a M () -> M [a] -> Property checkInfiniteProducerM = checkInfiniteProducerM' (fst . runM) checkInfiniteStreamProducerM :: (Show a, Eq a) => StreamSource M a -> M [a] -> Property checkInfiniteStreamProducerM = checkInfiniteStreamProducerM' (fst . runM) -checkConsumerM :: (Show b, Eq b) => Consumer Int M b -> ([Int] -> M b) -> Property+checkConsumerM :: (Show b, Eq b) => ConduitT Int Void M b -> ([Int] -> M b) -> Property checkConsumerM = checkConsumerM' runM checkStreamConsumerM :: (Show b, Eq b) => StreamConsumer Int M b -> ([Int] -> M b) -> Property checkStreamConsumerM = checkStreamConsumerM' runM -checkConduitM :: (Show a, Arbitrary a, Show b, Eq b) => Conduit a M b -> ([a] -> M [b]) -> Property-checkConduitM = checkConduitM' runM+checkConduitT :: (Show a, Arbitrary a, Show b, Eq b) => ConduitT a b M () -> ([a] -> M [b]) -> Property+checkConduitT = checkConduitT' runM -checkStreamConduitM :: (Show a, Arbitrary a, Show b, Eq b) => StreamConduit a M b -> ([a] -> M [b]) -> Property-checkStreamConduitM = checkStreamConduitM' runM+checkStreamConduitT :: (Show a, Arbitrary a, Show b, Eq b) => StreamConduit a M b -> ([a] -> M [b]) -> Property+checkStreamConduitT = checkStreamConduitT' runM --- checkConduitResultM :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => ConduitM a b M r -> ([a] -> M ([b], r)) -> Property+-- checkConduitResultM :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => ConduitT a b M r -> ([a] -> M ([b], r)) -> Property -- checkConduitResultM = checkConduitResultM' runM -checkStreamConduitResultM :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => StreamConduitM a b M r -> ([a] -> M ([b], r)) -> Property+checkStreamConduitResultM :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => StreamConduitT a b M r -> ([a] -> M ([b], r)) -> Property checkStreamConduitResultM = checkStreamConduitResultM' runM --------------------------------------------------------------------------------@@ -381,11 +381,11 @@ checkProducerM' :: (Show a, Monad m, Show b, Eq b) => (m [a] -> b)- -> Source m a+ -> ConduitT () a m () -> m [a] -> Property checkProducerM' f c l =- f (preventFusion c $$ consume)+ f (runConduit (preventFusion c .| consume)) === f l @@ -401,12 +401,12 @@ checkInfiniteProducerM' :: (Show a, Monad m, Show b, Eq b) => (m [a] -> b)- -> Source m a+ -> ConduitT () a m () -> m [a] -> Property checkInfiniteProducerM' f s l = checkProducerM' f- (preventFusion s $= isolate 10)+ (preventFusion s .| isolate 10) (liftM (Prelude.take 10) l) checkInfiniteStreamProducerM' :: (Show a, Monad m, Show b, Eq b)@@ -421,11 +421,11 @@ checkConsumerM' :: (Show a, Monad m, Show b, Eq b) => (m a -> b)- -> Consumer Int m a+ -> ConduitT Int Void m a -> ([Int] -> m a) -> Property checkConsumerM' f c l = forAll arbitrary $ \xs ->- f (sourceList xs $$ preventFusion c)+ f (runConduit (sourceList xs .| preventFusion c)) === f (l xs) @@ -439,22 +439,22 @@ === f (l xs) -checkConduitM' :: (Show a, Arbitrary a, Monad m, Show c, Eq c)+checkConduitT' :: (Show a, Arbitrary a, Monad m, Show c, Eq c) => (m [b] -> c)- -> Conduit a m b+ -> ConduitT a b m () -> ([a] -> m [b]) -> Property-checkConduitM' f c l = forAll arbitrary $ \xs ->- f (sourceList xs $= preventFusion c $$ consume)+checkConduitT' f c l = forAll arbitrary $ \xs ->+ f (runConduit (sourceList xs .| preventFusion c .| consume)) === f (l xs) -checkStreamConduitM' :: (Show a, Arbitrary a, Monad m, Show c, Eq c)+checkStreamConduitT' :: (Show a, Arbitrary a, Monad m, Show c, Eq c) => (m [b] -> c) -> StreamConduit a m b -> ([a] -> m [b]) -> Property-checkStreamConduitM' f s l = forAll arbitrary $ \xs ->+checkStreamConduitT' f s l = forAll arbitrary $ \xs -> f (liftM fst $ evalStream $ s $ sourceListS xs emptyStream) === f (l xs)@@ -464,17 +464,17 @@ -- -- checkConduitResultM' :: (Show a, Arbitrary a, Monad m, Show c, Eq c) -- => (m ([b], r) -> c)--- -> ConduitM a b m r+-- -> ConduitT a b m r -- -> ([a] -> m ([b], r)) -- -> Property -- checkConduitResultM' f c l = FIXME forAll arbitrary $ \xs ->--- f (sourceList xs $= preventFusion c $$ consume)+-- f (sourceList xs .| preventFusion c $$ consume) -- === -- f (l xs) checkStreamConduitResultM' :: (Show a, Arbitrary a, Monad m, Show c, Eq c) => (m ([b], r) -> c)- -> StreamConduitM a b m r+ -> StreamConduitT a b m r -> ([a] -> m ([b], r)) -> Property checkStreamConduitResultM' f s l = forAll arbitrary $ \xs ->
+ test/Spec.hs view
@@ -0,0 +1,679 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-type-defaults #-}+module Spec (spec) where++import Conduit+import Prelude hiding (FilePath)+import Data.Maybe (listToMaybe)+import Data.Conduit.Combinators (slidingWindow, chunksOfE, chunksOfExactlyE)+import Data.List (intersperse, sort, find, mapAccumL)+import Safe (tailSafe)+import System.FilePath (takeExtension)+import Test.Hspec+import Test.Hspec.QuickCheck+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import Data.IORef+import qualified Data.Vector as V+import qualified Data.Vector.Unboxed as VU+import qualified Data.Vector.Storable as VS+import Control.Monad (liftM)+import Control.Monad.ST (runST)+import Control.Monad.Trans.Writer+import qualified System.IO as IO+#if ! MIN_VERSION_base(4,8,0)+import Data.Monoid (Monoid (..))+import Control.Applicative ((<$>), (<*>))+#endif+#if MIN_VERSION_mono_traversable(1,0,0)+import Data.Sequences (LazySequence (..), Utf8 (..))+#else+import Data.Sequences.Lazy+import Data.Textual.Encoding+#endif+import qualified Data.NonNull as NN+import System.IO.Silently (hCapture)+import GHC.IO.Handle (hDuplicateTo)+import qualified Data.ByteString as S+import Data.ByteString.Builder (byteString, toLazyByteString)+import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy.Char8 as L8+import qualified StreamSpec+import UnliftIO.Exception (pureTry)++spec :: Spec+spec = do+ describe "yieldMany" $ do+ it "list" $+ runConduitPure (yieldMany [1..10] .| sinkList)+ `shouldBe` [1..10]+ it "Text" $+ runConduitPure (yieldMany ("Hello World" :: T.Text) .| sinkList)+ `shouldBe` "Hello World"+ it "unfold" $+ let f 11 = Nothing+ f i = Just (show i, i + 1)+ in runConduitPure (unfoldC f 1 .| sinkList)+ `shouldBe` map show [1..10]+ it "enumFromTo" $+ runConduitPure (enumFromToC 1 10 .| sinkList) `shouldBe` [1..10]+ it "iterate" $+ let f i = i + 1+ src = iterateC f seed+ seed = 1+ count = 10+ res = runConduitPure $ src .| takeC count .| sinkList+ in res `shouldBe` take count (iterate f seed)+ it "repeat" $+ let src = repeatC seed+ seed = 1+ count = 10+ res = runConduitPure $ src .| takeC count .| sinkList+ in res `shouldBe` take count (repeat seed)+ it "replicate" $+ let src = replicateC count seed+ seed = 1+ count = 10+ res = runConduitPure $ src .| sinkList+ in res `shouldBe` replicate count seed+ it "sourceLazy" $+ let tss = ["foo", "bar", "baz"]+ tl = TL.fromChunks tss+ res = runConduitPure $ sourceLazy tl .| sinkList+ in res `shouldBe` tss+ it "repeatM" $+ let src = repeatMC (return seed)+ seed = 1+ count = 10+ res = runConduitPure $ src .| takeC count .| sinkList+ in res `shouldBe` take count (repeat seed)+ it "repeatWhileM" $ do+ ref <- newIORef 0+ let f = atomicModifyIORef ref $ \i -> (succ i, succ i)+ src = repeatWhileMC f (< 11)+ res <- runConduit $ src .| sinkList+ res `shouldBe` [1..10]+ it "replicateM" $ do+ ref <- newIORef 0+ let f = atomicModifyIORef ref $ \i -> (succ i, succ i)+ src = replicateMC 10 f+ res <- runConduit $ src .| sinkList+ res `shouldBe` [1..10]+ it "sourceFile" $ do+ let contents = concat $ replicate 10000 $ "this is some content\n"+ fp = "tmp"+ writeFile fp contents+ res <- runConduitRes $ sourceFile fp .| sinkLazy+ nocrBL res `shouldBe` TL.encodeUtf8 (TL.pack contents)+ it "sourceHandle" $ do+ let contents = concat $ replicate 10000 $ "this is some content\n"+ fp = "tmp"+ writeFile fp contents+ res <- IO.withBinaryFile "tmp" IO.ReadMode $ \h ->+ runConduit $ sourceHandle h .| sinkLazy+ nocrBL res `shouldBe` TL.encodeUtf8 (TL.pack contents)+ it "sourceIOHandle" $ do+ let contents = concat $ replicate 10000 $ "this is some content\n"+ fp = "tmp"+ writeFile fp contents+ let open = IO.openBinaryFile "tmp" IO.ReadMode+ res <- runConduitRes $ sourceIOHandle open .| sinkLazy+ nocrBL res `shouldBe` TL.encodeUtf8 (TL.pack contents)+ prop "stdin" $ \(S.pack -> content) -> do+ S.writeFile "tmp" content+ IO.withBinaryFile "tmp" IO.ReadMode $ \h -> do+ hDuplicateTo h IO.stdin+ x <- runConduit $ stdinC .| foldC+ x `shouldBe` content+ let hasExtension' ext fp = takeExtension fp == ext+ it "sourceDirectory" $ do+ res <- runConduitRes+ $ sourceDirectory "test" .| filterC (not . hasExtension' ".swp") .| sinkList+ sort res `shouldBe`+ [ "test/Data"+ , "test/Spec.hs"+ , "test/StreamSpec.hs"+ , "test/doctests.hs"+ , "test/main.hs"+ , "test/subdir"+ ]+ it "sourceDirectoryDeep" $ do+ res1 <- runConduitRes+ $ sourceDirectoryDeep False "test" .| filterC (not . hasExtension' ".swp") .| sinkList+ res2 <- runConduitRes+ $ sourceDirectoryDeep True "test" .| filterC (not . hasExtension' ".swp") .| sinkList+ sort res1 `shouldBe`+ [ "test/Data/Conduit/Extra/ZipConduitSpec.hs"+ , "test/Data/Conduit/StreamSpec.hs"+ , "test/Spec.hs"+ , "test/StreamSpec.hs"+ , "test/doctests.hs"+ , "test/main.hs"+ , "test/subdir/dummyfile.txt"+ ]+ sort res1 `shouldBe` sort res2+ prop "drop" $ \(T.pack -> input) count ->+ runConduitPure (yieldMany input .| (dropC count >>= \() -> sinkList))+ `shouldBe` T.unpack (T.drop count input)+ prop "dropE" $ \(T.pack -> input) ->+ runConduitPure (yield input .| (dropCE 5 >>= \() -> foldC))+ `shouldBe` T.drop 5 input+ prop "dropWhile" $ \(T.pack -> input) sep ->+ runConduitPure (yieldMany input .| (dropWhileC (<= sep) >>= \() -> sinkList))+ `shouldBe` T.unpack (T.dropWhile (<= sep) input)+ prop "dropWhileE" $ \(T.pack -> input) sep ->+ runConduitPure (yield input .| (dropWhileCE (<= sep) >>= \() -> foldC))+ `shouldBe` T.dropWhile (<= sep) input+ it "fold" $+ let list = [[1..10], [11..20]]+ src = yieldMany list+ res = runConduitPure $ src .| foldC+ in res `shouldBe` concat list+ it "foldE" $+ let list = [[1..10], [11..20]]+ src = yieldMany $ Identity list+ res = runConduitPure $ src .| foldCE+ in res `shouldBe` concat list+ it "foldl" $+ let res = runConduitPure $ yieldMany [1..10] .| foldlC (+) 0+ in res `shouldBe` sum [1..10]+ it "foldlE" $+ let res = runConduitPure $ yield [1..10] .| foldlCE (+) 0+ in res `shouldBe` sum [1..10]+ it "foldMap" $+ let src = yieldMany [1..10]+ res = runConduitPure $ src .| foldMapC return+ in res `shouldBe` [1..10]+ it "foldMapE" $+ let src = yield [1..10]+ res = runConduitPure $ src .| foldMapCE return+ in res `shouldBe` [1..10]+ prop "all" $ \ (input :: [Int]) -> runConduitPure (yieldMany input .| allC even) `shouldBe` all evenInt input+ prop "allE" $ \ (input :: [Int]) -> runConduitPure (yield input .| allCE even) `shouldBe` all evenInt input+ prop "any" $ \ (input :: [Int]) -> runConduitPure (yieldMany input .| anyC even) `shouldBe` any evenInt input+ prop "anyE" $ \ (input :: [Int]) -> runConduitPure (yield input .| anyCE even) `shouldBe` any evenInt input+ prop "and" $ \ (input :: [Bool]) -> runConduitPure (yieldMany input .| andC) `shouldBe` and input+ prop "andE" $ \ (input :: [Bool]) -> runConduitPure (yield input .| andCE) `shouldBe` and input+ prop "or" $ \ (input :: [Bool]) -> runConduitPure (yieldMany input .| orC) `shouldBe` or input+ prop "orE" $ \ (input :: [Bool]) -> runConduitPure (yield input .| orCE) `shouldBe` or input+ prop "elem" $ \x xs -> runConduitPure (yieldMany xs .| elemC x) `shouldBe` elemInt x xs+ prop "elemE" $ \x xs -> runConduitPure (yield xs .| elemCE x) `shouldBe` elemInt x xs+ prop "notElem" $ \x xs -> runConduitPure (yieldMany xs .| notElemC x) `shouldBe` notElemInt x xs+ prop "notElemE" $ \x xs -> runConduitPure (yield xs .| notElemCE x) `shouldBe` notElemInt x xs+ prop "sinkVector regular" $ \xs -> do+ res <- runConduit $ yieldMany xs .| sinkVector+ res `shouldBe` V.fromList (xs :: [Int])+ prop "sinkVector unboxed" $ \xs -> do+ res <- runConduit $ yieldMany xs .| sinkVector+ res `shouldBe` VU.fromList (xs :: [Int])+ prop "sinkVector storable" $ \xs -> do+ res <- runConduit $ yieldMany xs .| sinkVector+ res `shouldBe` VS.fromList (xs :: [Int])+ prop "sinkVectorN regular" $ \xs' -> do+ let maxSize = 20+ xs = take maxSize xs'+ res <- runConduit $ yieldMany xs' .| sinkVectorN maxSize+ res `shouldBe` V.fromList (xs :: [Int])+ prop "sinkVectorN unboxed" $ \xs' -> do+ let maxSize = 20+ xs = take maxSize xs'+ res <- runConduit $ yieldMany xs' .| sinkVectorN maxSize+ res `shouldBe` VU.fromList (xs :: [Int])+ prop "sinkVectorN storable" $ \xs' -> do+ let maxSize = 20+ xs = take maxSize xs'+ res <- runConduit $ yieldMany xs' .| sinkVectorN maxSize+ res `shouldBe` VS.fromList (xs :: [Int])+ prop "sinkBuilder" $ \(map S.pack -> inputs) ->+ let builder = runConduitPure $ yieldMany inputs .| foldMapC byteString+ ltext = toLazyByteString builder+ in ltext `shouldBe` fromChunks inputs+ prop "sinkLazyBuilder" $ \(map S.pack -> inputs) ->+ let lbs = runConduitPure (yieldMany (map byteString inputs) .| sinkLazyBuilder)+ in lbs `shouldBe` fromChunks inputs+ prop "sinkNull" $ \xs toSkip -> do+ res <- runConduit $ yieldMany xs .| do+ takeC toSkip .| sinkNull+ sinkList+ res `shouldBe` drop toSkip (xs :: [Int])+ prop "awaitNonNull" $ \xs ->+ fmap NN.toNullable (runConduitPure $ yieldMany xs .| awaitNonNull)+ `shouldBe` listToMaybe (filter (not . null) (xs :: [[Int]]))+ prop "headE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| ((,) <$> headCE <*> foldC))+ `shouldBe` (listToMaybe $ concat xs, drop 1 $ concat xs)+ prop "peek" $ \xs ->+ runConduitPure (yieldMany xs .| ((,) <$> peekC <*> sinkList))+ `shouldBe` (listToMaybe xs, xs :: [Int])+ prop "peekE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| ((,) <$> peekCE <*> foldC))+ `shouldBe` (listToMaybe $ concat xs, concat xs)+ prop "last" $ \xs ->+ runConduitPure (yieldMany xs .| lastC)+ `shouldBe` listToMaybe (reverse (xs :: [Int]))+ prop "lastE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| lastCE)+ `shouldBe` listToMaybe (reverse (concat xs))+ prop "length" $ \xs ->+ runConduitPure (yieldMany xs .| lengthC)+ `shouldBe` length (xs :: [Int])+ prop "lengthE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| lengthCE)+ `shouldBe` length (concat xs)+ prop "lengthIf" $ \x xs ->+ runConduitPure (yieldMany xs .| lengthIfC (< x))+ `shouldBe` length (filter (< x) xs :: [Int])+ prop "lengthIfE" $ \x (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| lengthIfCE (< x))+ `shouldBe` length (filter (< x) (concat xs))+ prop "maximum" $ \xs ->+ runConduitPure (yieldMany xs .| maximumC)+ `shouldBe` (if null (xs :: [Int]) then Nothing else Just (maximum xs))+ prop "maximumE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| maximumCE)+ `shouldBe` (if null (concat xs) then Nothing else Just (maximum $ concat xs))+ prop "minimum" $ \xs ->+ runConduitPure (yieldMany xs .| minimumC)+ `shouldBe` (if null (xs :: [Int]) then Nothing else Just (minimum xs))+ prop "minimumE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| minimumCE)+ `shouldBe` (if null (concat xs) then Nothing else Just (minimum $ concat xs))+ prop "null" $ \xs ->+ runConduitPure (yieldMany xs .| nullC)+ `shouldBe` null (xs :: [Int])+ prop "nullE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| ((,) <$> nullCE <*> foldC))+ `shouldBe` (null (concat xs), concat xs)+ prop "sum" $ \xs ->+ runConduitPure (yieldMany xs .| sumC)+ `shouldBe` sum (xs :: [Int])+ prop "sumE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| sumCE)+ `shouldBe` sum (concat xs)+ prop "product" $ \xs ->+ runConduitPure (yieldMany xs .| productC)+ `shouldBe` product (xs :: [Int])+ prop "productE" $ \ (xs :: [[Int]]) ->+ runConduitPure (yieldMany xs .| productCE)+ `shouldBe` product (concat xs)+ prop "find" $ \x xs ->+ runConduitPure (yieldMany xs .| findC (< x))+ `shouldBe` find (< x) (xs :: [Int])+ prop "mapM_" $ \xs ->+ let res = execWriter $ runConduit $ yieldMany xs .| mapM_C (tell . return)+ in res `shouldBe` (xs :: [Int])+ prop "mapM_E" $ \xs ->+ let res = execWriter $ runConduit $ yield xs .| mapM_CE (tell . return)+ in res `shouldBe` (xs :: [Int])+ prop "foldM" $ \ (xs :: [Int]) -> do+ res <- runConduit $ yieldMany xs .| foldMC addM 0+ res `shouldBe` sum xs+ prop "foldME" $ \ (xs :: [Int]) -> do+ res <- runConduit $ yield xs .| foldMCE addM 0+ res `shouldBe` sum xs+ it "foldMapM" $+ let src = yieldMany [1..10]+ res = runConduitPure $ src .| foldMapMC (return . return)+ in res `shouldBe` [1..10]+ it "foldMapME" $+ let src = yield [1..10]+ res = runConduitPure $ src .| foldMapMCE (return . return)+ in res `shouldBe` [1..10]+ it "sinkFile" $ do+ let contents = mconcat $ replicate 1000 $ "this is some content\n"+ fp = "tmp"+ runConduitRes $ yield contents .| sinkFile fp+ res <- S.readFile fp+ res `shouldBe` contents+ it "sinkHandle" $ do+ let contents = mconcat $ replicate 1000 $ "this is some content\n"+ fp = "tmp"+ IO.withBinaryFile "tmp" IO.WriteMode $ \h -> runConduit $ yield contents .| sinkHandle h+ res <- S.readFile fp+ res `shouldBe` contents+ it "sinkIOHandle" $ do+ let contents = mconcat $ replicate 1000 $ "this is some content\n"+ fp = "tmp"+ open = IO.openBinaryFile "tmp" IO.WriteMode+ runConduitRes $ yield contents .| sinkIOHandle open+ res <- S.readFile fp+ res `shouldBe` contents+ prop "print" $ \vals -> do+ let expected = Prelude.unlines $ map showInt vals+ (actual, ()) <- hCapture [IO.stdout] $ runConduit $ yieldMany vals .| printC+ actual `shouldBe` expected+#ifndef WINDOWS+ prop "stdout" $ \ (vals :: [String]) -> do+ let expected = concat vals+ (actual, ()) <- hCapture [IO.stdout] $ runConduit $ yieldMany (map T.pack vals) .| encodeUtf8C .| stdoutC+ actual `shouldBe` expected+ prop "stderr" $ \ (vals :: [String]) -> do+ let expected = concat vals+ (actual, ()) <- hCapture [IO.stderr] $ runConduit $ yieldMany (map T.pack vals) .| encodeUtf8C .| stderrC+ actual `shouldBe` expected+#endif+ prop "map" $ \input ->+ runConduitPure (yieldMany input .| mapC succChar .| sinkList)+ `shouldBe` map succChar input+ prop "mapE" $ \(map V.fromList -> inputs) ->+ runConduitPure (yieldMany inputs .| mapCE succChar .| foldC)+ `shouldBe` V.map succChar (V.concat inputs)+ prop "omapE" $ \(map T.pack -> inputs) ->+ runConduitPure (yieldMany inputs .| omapCE succChar .| foldC)+ `shouldBe` T.map succChar (T.concat inputs)+ prop "concatMap" $ \ (input :: [Int]) ->+ runConduitPure (yieldMany input .| concatMapC showInt .| sinkList)+ `shouldBe` concatMap showInt input+ prop "concatMapE" $ \ (input :: [Int]) ->+ runConduitPure (yield input .| concatMapCE showInt .| foldC)+ `shouldBe` concatMap showInt input+ prop "take" $ \(T.pack -> input) count ->+ runConduitPure (yieldMany input .| (takeC count >>= \() -> mempty) .| sinkList)+ `shouldBe` T.unpack (T.take count input)+ prop "takeE" $ \(T.pack -> input) count ->+ runConduitPure (yield input .| (takeCE count >>= \() -> mempty) .| foldC)+ `shouldBe` T.take count input+ prop "takeWhile" $ \(T.pack -> input) sep ->+ runConduitPure (yieldMany input .| do+ x <- (takeWhileC (<= sep) >>= \() -> mempty) .| sinkList+ y <- sinkList+ return (x, y))+ `shouldBe` span (<= sep) (T.unpack input)+ prop "takeWhileE" $ \(T.pack -> input) sep ->+ runConduitPure (yield input .| do+ x <- (takeWhileCE (<= sep) >>= \() -> mempty) .| foldC+ y <- foldC+ return (x, y))+ `shouldBe` T.span (<= sep) input+ it "takeExactly" $+ let src = yieldMany [1..10]+ sink = do+ x <- takeExactlyC 5 $ return 1+ y <- sinkList+ return (x, y)+ res = runConduitPure $ src .| sink+ in res `shouldBe` (1, [6..10])+ it "takeExactlyE" $+ let src = yield ("Hello World" :: T.Text)+ sink = do+ takeExactlyCE 5 (mempty :: ConduitT T.Text Void Identity ())+ y <- sinkLazy+ return y+ res = runConduitPure $ src .| sink+ in res `shouldBe` " World"+ it "takeExactlyE Vector" $ do+ let src = yield (V.fromList $ T.unpack "Hello World")+ sink = do+ x <- takeExactlyCE 5 $ return 1+ y <- foldC+ return (x, y)+ res <- runConduit $ src .| sink+ res `shouldBe` (1, V.fromList $ T.unpack " World")+ it "takeExactlyE 2" $+ let src = yield ("Hello World" :: T.Text)+ sink = do+ x <- takeExactlyCE 5 $ return 1+ y <- sinkLazy+ return (x, y)+ res = runConduitPure $ src .| sink+ -- FIXME type signature on next line is necessary in GHC 7.6.3 to+ -- avoid a crash:+ --+ -- test: internal error: ARR_WORDS object entered!+ -- (GHC version 7.6.3 for x86_64_unknown_linux)+ -- Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug+ -- Aborted (core dumped)+ --+ -- Report upstream when packages are released+ in res `shouldBe` (1, " World" :: TL.Text)+ prop "concat" $ \input ->+ runConduitPure (yield (T.pack input) .| concatC .| sinkList)+ `shouldBe` input+ prop "filter" $ \input ->+ runConduitPure (yieldMany input .| filterC evenInt .| sinkList)+ `shouldBe` filter evenInt input+ prop "filterE" $ \input ->+ runConduitPure (yield input .| filterCE evenInt .| foldC)+ `shouldBe` filter evenInt input+ prop "mapWhile" $ \input (min 20 -> highest) ->+ let f i | i < highest = Just (i + 2 :: Int)+ | otherwise = Nothing+ res = runConduitPure $ yieldMany input .| do+ x <- (mapWhileC f >>= \() -> mempty) .| sinkList+ y <- sinkList+ return (x, y)+ (taken, dropped) = span (< highest) input+ in res `shouldBe` (map (+ 2) taken, dropped)+ prop "conduitVector" $ \(take 200 -> input) size' -> do+ let size = min 30 $ succ $ abs size'+ res <- runConduit $ yieldMany input .| conduitVector size .| sinkList+ res `shouldSatisfy` all (\v -> V.length v <= size)+ drop 1 (reverse res) `shouldSatisfy` all (\v -> V.length v == size)+ V.concat res `shouldBe` V.fromList (input :: [Int])+ prop "scanl" $ \input seed ->+ let f a b = a + b :: Int+ res = runConduitPure $ yieldMany input .| scanlC f seed .| sinkList+ in res `shouldBe` scanl f seed input+ prop "mapAccumWhile" $ \input (min 20 -> highest) ->+ let f i accum | i < highest = Right (i + accum, 2 * i :: Int)+ | otherwise = Left accum+ res = runConduitPure $ yieldMany input .| do+ (s, x) <- fuseBoth (mapAccumWhileC f 0) sinkList+ y <- sinkList+ return (s, x, y)+ (taken, dropped) = span (< highest) input+ in res `shouldBe` (sum taken, map (* 2) taken, tailSafe dropped)+ prop "concatMapAccum" $ \(input :: [Int]) ->+ let f a accum = (a + accum, [a, accum])+ res = runConduitPure $ yieldMany input .| concatMapAccumC f 0 .| sinkList+ expected = concat $ snd $ mapAccumL (flip f) 0 input+ in res `shouldBe` expected+ prop "intersperse" $ \xs x ->+ runConduitPure (yieldMany xs .| intersperseC x .| sinkList)+ `shouldBe` intersperse (x :: Int) xs+ prop "mapM" $ \input ->+ runConduitPure (yieldMany input .| mapMC (return . succChar) .| sinkList)+ `shouldBe` map succChar input+ prop "mapME" $ \(map V.fromList -> inputs) ->+ runConduitPure (yieldMany inputs .| mapMCE (return . succChar) .| foldC)+ `shouldBe` V.map succChar (V.concat inputs)+ prop "omapME" $ \(map T.pack -> inputs) ->+ runConduitPure (yieldMany inputs .| omapMCE (return . succChar) .| foldC)+ `shouldBe` T.map succChar (T.concat inputs)+ prop "concatMapM" $ \ (input :: [Int]) ->+ runConduitPure (yieldMany input .| concatMapMC (return . showInt) .| sinkList)+ `shouldBe` concatMap showInt input+ prop "filterM" $ \input ->+ runConduitPure (yieldMany input .| filterMC (return . evenInt) .| sinkList)+ `shouldBe` filter evenInt input+ prop "filterME" $ \input ->+ runConduitPure (yield input .| filterMCE (return . evenInt) .| foldC)+ `shouldBe` filter evenInt input+ prop "iterM" $ \input -> do+ (x, y) <- runWriterT $ runConduit $ yieldMany input .| iterMC (tell . return) .| sinkList+ x `shouldBe` (input :: [Int])+ y `shouldBe` input+ prop "scanlM" $ \input seed ->+ let f a b = a + b :: Int+ fm a b = return $ a + b+ res = runConduitPure $ yieldMany input .| scanlMC fm seed .| sinkList+ in res `shouldBe` scanl f seed input+ prop "mapAccumWhileM" $ \input (min 20 -> highest) ->+ let f i accum | i < highest = Right (i + accum, 2 * i :: Int)+ | otherwise = Left accum+ res = runConduitPure $ yieldMany input .| do+ (s, x) <- fuseBoth (mapAccumWhileMC ((return.).f) 0) sinkList+ y <- sinkList+ return (s, x, y)+ (taken, dropped) = span (< highest) input+ in res `shouldBe` (sum taken, map (* 2) taken, tailSafe dropped)+ prop "concatMapAccumM" $ \(input :: [Int]) ->+ let f a accum = (a + accum, [a, accum])+ res = runConduitPure $ yieldMany input .| concatMapAccumMC ((return.).f) 0 .| sinkList+ expected = concat $ snd $ mapAccumL (flip f) 0 input+ in res `shouldBe` expected+ prop "encode UTF8" $ \(map T.pack -> inputs) -> do+ let expected = encodeUtf8 $ fromChunks inputs+ actual <- runConduit+ $ yieldMany inputs+ .| encodeUtf8C+ .| sinkLazy+ actual `shouldBe` expected+ prop "encode/decode UTF8" $ \(map T.pack -> inputs) (min 50 . max 1 . abs -> chunkSize) -> do+ let expected = fromChunks inputs+ actual <- runConduit+ $ yieldMany inputs+ .| encodeUtf8C+ .| concatC+ .| conduitVector chunkSize+ .| mapC (S.pack . V.toList)+ .| decodeUtf8C+ .| sinkLazy+ actual `shouldBe` expected+ it "invalid UTF8 is an exception" $+ case runConduit $ yield "\129" .| decodeUtf8C .| sinkLazy of+ Left _ -> return () :: IO ()+ Right x -> error $ "this should have failed, got: " ++ show x+ prop "encode/decode UTF8 lenient" $ \(map T.pack -> inputs) (min 50 . max 1 . abs -> chunkSize) -> do+ let expected = fromChunks inputs+ actual <- runConduit+ $ yieldMany inputs+ .| encodeUtf8C+ .| concatC+ .| conduitVector chunkSize+ .| mapC (S.pack . V.toList)+ .| decodeUtf8LenientC+ .| sinkLazy+ actual `shouldBe` expected+ prop "line" $ \(map T.pack -> input) size ->+ let src = yieldMany input+ sink = do+ x <- lineC $ takeCE size .| foldC+ y <- foldC+ return (x, y)+ res = runConduitPure $ src .| sink+ expected =+ let (x, y) = T.break (== '\n') (T.concat input)+ in (T.take size x, T.drop 1 y)+ in res `shouldBe` expected+ prop "lineAscii" $ \(map S.pack -> input) size ->+ let src = yieldMany input+ sink = do+ x <- lineAsciiC $ takeCE size .| foldC+ y <- foldC+ return (x, y)+ res = runConduitPure $ src .| sink+ expected =+ let (x, y) = S.break (== 10) (S.concat input)+ in (S.take size x, S.drop 1 y)+ in res `shouldBe` expected+ prop "unlines" $ \(map T.pack -> input) ->+ runConduitPure (yieldMany input .| unlinesC .| foldC)+ `shouldBe` T.unlines input+ prop "unlinesAscii" $ \(map S.pack -> input) ->+ runConduitPure (yieldMany input .| unlinesAsciiC .| foldC)+ `shouldBe` S8.unlines input+ prop "linesUnbounded" $ \(map T.pack -> input) ->+ runConduitPure (yieldMany input .| (linesUnboundedC >>= \() -> mempty) .| sinkList)+ `shouldBe` T.lines (T.concat input)+ prop "linesUnboundedAscii" $ \(map S.pack -> input) ->+ runConduitPure (yieldMany input .| (linesUnboundedAsciiC >>= \() -> mempty) .| sinkList)+ `shouldBe` S8.lines (S.concat input)+ it "slidingWindow 0" $+ let res = runConduitPure $ yieldMany [1..5] .| slidingWindow 0 .| sinkList+ in res `shouldBe` [[1],[2],[3],[4],[5]]+ it "slidingWindow 1" $+ let res = runConduitPure $ yieldMany [1..5] .| slidingWindow 1 .| sinkList+ in res `shouldBe` [[1],[2],[3],[4],[5]]+ it "slidingWindow 2" $+ let res = runConduitPure $ yieldMany [1..5] .| slidingWindow 2 .| sinkList+ in res `shouldBe` [[1,2],[2,3],[3,4],[4,5]]+ it "slidingWindow 3" $+ let res = runConduitPure $ yieldMany [1..5] .| slidingWindow 3 .| sinkList+ in res `shouldBe` [[1,2,3],[2,3,4],[3,4,5]]+ it "slidingWindow 4" $+ let res = runConduitPure $ yieldMany [1..5] .| slidingWindow 4 .| sinkList+ in res `shouldBe` [[1,2,3,4],[2,3,4,5]]+ it "slidingWindow 5" $+ let res = runConduitPure $ yieldMany [1..5] .| slidingWindow 5 .| sinkList+ in res `shouldBe` [[1,2,3,4,5]]+ it "slidingWindow 6" $+ let res = runConduitPure $ yieldMany [1..5] .| slidingWindow 6 .| sinkList+ in res `shouldBe` [[1,2,3,4,5]]+ it "chunksOfE 1" $+ let res = runConduitPure $ yieldMany [[1,2], [3,4], [5,6]] .| chunksOfE 3 .| sinkList+ in res `shouldBe` [[1,2,3], [4,5,6]]+ it "chunksOfE 2 (last smaller)" $+ let res = runConduitPure $ yieldMany [[1,2], [3,4], [5,6,7]] .| chunksOfE 3 .| sinkList+ in res `shouldBe` [[1,2,3], [4,5,6], [7]]+ it "chunksOfE (ByteString)" $+ let res = runConduitPure $ yieldMany [S8.pack "01234", "56789ab", "cdef", "h"] .| chunksOfE 4 .| sinkList+ in res `shouldBe` ["0123", "4567", "89ab", "cdef", "h"]+ it "chunksOfExactlyE 1" $+ let res = runConduitPure $ yieldMany [[1,2], [3,4], [5,6]] .| chunksOfExactlyE 3 .| sinkList+ in res `shouldBe` [[1,2,3], [4,5,6]]+ it "chunksOfExactlyE 2 (last smaller; thus not yielded)" $+ let res = runConduitPure $ yieldMany [[1,2], [3,4], [5,6,7]] .| chunksOfExactlyE 3 .| sinkList+ in res `shouldBe` [[1,2,3], [4,5,6]]+ prop "vectorBuilder" $ \(values :: [[Int]]) ((+1) . (`mod` 30) . abs -> size) -> do+ let res = runST $ runConduit+ $ yieldMany values+ .| vectorBuilderC size mapM_CE+ .| sinkList+ expected =+ loop $ concat values+ where+ loop [] = []+ loop x =+ VU.fromList y : loop z+ where+ (y, z) = splitAt size x+ res `shouldBe` expected+ prop "mapAccumS" $ \input ->+ let ints = [1..]+ f a s = liftM (:s) $ mapC (* a) .| takeC a .| sinkList+ res = reverse $ runConduitPure $ yieldMany input+ .| mapAccumS f [] (yieldMany ints)+ expected = loop input ints+ where loop [] _ = []+ loop (a:as) xs = let (y, ys) = Prelude.splitAt a xs+ in map (* a) y : loop as ys+ in res `shouldBe` expected+ prop "peekForever" $ \(strs' :: [String]) -> do+ let strs = filter (not . null) strs'+ res1 <- runConduit $ yieldMany strs .| linesUnboundedC .| sinkList+ res2 <- runConduit $ yieldMany strs .| peekForever (lineC $ foldC >>= yield) .| sinkList+ res2 `shouldBe` res1+ prop "peekForeverE" $ \(strs :: [String]) -> do+ res1 <- runConduit $ yieldMany strs .| linesUnboundedC .| sinkList+ res2 <- runConduit $ yieldMany strs .| peekForeverE (lineC $ foldC >>= yield) .| sinkList+ res2 `shouldBe` res1+ StreamSpec.spec++evenInt :: Int -> Bool+evenInt = even++elemInt :: Int -> [Int] -> Bool+elemInt = elem++notElemInt :: Int -> [Int] -> Bool+notElemInt = notElem++addM :: Monad m => Int -> Int -> m Int+addM x y = return (x + y)++succChar :: Char -> Char+succChar c =+ case pureTry (succ c) of+ Left _ -> 'X' -- QuickCheck may generate characters out of range+ Right x -> x++showInt :: Int -> String+showInt = Prelude.show++nocrBL :: L8.ByteString -> L8.ByteString+nocrBL = L8.filter (/= '\r')
+ test/StreamSpec.hs view
@@ -0,0 +1,509 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module StreamSpec where++import Control.Arrow (first)+import Control.Applicative+import qualified Control.Monad+import Control.Monad (liftM)+import Control.Monad.Identity (Identity, runIdentity)+import Control.Monad.State (StateT(..), get, put)+import Data.Conduit+import Data.Conduit.Combinators+import Data.Conduit.Combinators.Stream+import Data.Conduit.Internal.Fusion+import Data.Conduit.Internal.List.Stream (takeS, sourceListS, mapS)+import qualified Data.List+import Data.MonoTraversable+import Data.Monoid (Monoid(..))+import qualified Data.NonNull as NonNull+import Data.Sequence (Seq)+import qualified Data.Sequences as Seq+import Data.Vector (Vector)+import qualified Prelude+import Prelude+ ((.), ($), (>>=), (=<<), return, id, Maybe(..), Either(..), Monad,+ Bool(..), Int, Eq, Show, String, Functor, fst, snd, either)+import qualified Safe+import qualified System.IO as IO+import System.IO.Unsafe+import Test.Hspec+import Test.QuickCheck++spec :: Spec+spec = do+ describe "Comparing list function to" $ do+ qit "yieldMany" $+ \(mono :: Seq Int) ->+ yieldMany mono `checkProducer`+ otoList mono+ qit "sourceListS" $+ \(mono :: Seq Int) ->+ yieldManyS mono `checkStreamProducer`+ otoList mono+ qit "repeatM" $+ \(getBlind -> (f :: M Int)) ->+ repeatM f `checkInfiniteProducerM`+ repeatML f+ qit "repeatMS" $+ \(getBlind -> (f :: M Int)) ->+ repeatMS f `checkInfiniteStreamProducerM`+ repeatML f+ qit "repeatWhileM" $+ \(getBlind -> (f :: M Int), getBlind -> g) ->+ repeatWhileM f g `checkInfiniteProducerM`+ repeatWhileML f g+ qit "repeatWhileMS" $+ \(getBlind -> (f :: M Int), getBlind -> g) ->+ repeatWhileMS f g `checkInfiniteStreamProducerM`+ repeatWhileML f g+ qit "foldl1" $+ \(getBlind -> f) ->+ foldl1 f `checkConsumer`+ foldl1L f+ qit "foldl1S" $+ \(getBlind -> f) ->+ foldl1S f `checkStreamConsumer`+ foldl1L f+ qit "all" $+ \(getBlind -> f) ->+ all f `checkConsumer`+ Prelude.all f+ qit "allS" $+ \(getBlind -> f) ->+ allS f `checkStreamConsumer`+ Prelude.all f+ qit "any" $+ \(getBlind -> f) ->+ any f `checkConsumer`+ Prelude.any f+ qit "anyS" $+ \(getBlind -> f) ->+ anyS f `checkStreamConsumer`+ Prelude.any f+ qit "last" $+ \() ->+ last `checkConsumer`+ Safe.lastMay+ qit "lastS" $+ \() ->+ lastS `checkStreamConsumer`+ Safe.lastMay+ qit "lastE" $+ \(getBlind -> f) ->+ let g x = Seq.replicate (Prelude.abs (getSmall (f x))) x :: Seq Int+ in (map g .| lastE) `checkConsumer`+ (lastEL . Prelude.map g :: [Int] -> Maybe Int)+ qit "lastES" $+ \(getBlind -> f) ->+ let g x = Seq.replicate (Prelude.abs (getSmall (f x))) x :: Seq Int+ in (lastES . mapS g) `checkStreamConsumer`+ (lastEL . Prelude.map g :: [Int] -> Maybe Int)+ qit "find" $+ \(getBlind -> f) ->+ find f `checkConsumer`+ Data.List.find f+ qit "findS" $+ \(getBlind -> f) ->+ findS f `checkStreamConsumer`+ Data.List.find f+ qit "concatMap" $+ \(getBlind -> (f :: Int -> Seq Int)) ->+ concatMap f `checkConduit`+ concatMapL f+ qit "concatMapS" $+ \(getBlind -> (f :: Int -> Seq Int)) ->+ concatMapS f `checkStreamConduit`+ concatMapL f+ qit "concatMapM" $+ \(getBlind -> (f :: Int -> M (Seq Int))) ->+ concatMapM f `checkConduitT`+ concatMapML f+ qit "concatMapMS" $+ \(getBlind -> (f :: Int -> M (Seq Int))) ->+ concatMapMS f `checkStreamConduitT`+ concatMapML f+ qit "concat" $+ \() ->+ concat `checkConduit`+ (concatL :: [Seq Int] -> [Int])+ qit "concatS" $+ \() ->+ concatS `checkStreamConduit`+ (concatL :: [Seq Int] -> [Int])+ qit "scanl" $+ \(getBlind -> (f :: Int -> Int -> Int), initial) ->+ scanl f initial `checkConduit`+ Prelude.scanl f initial+ qit "scanlS" $+ \(getBlind -> (f :: Int -> Int -> Int), initial) ->+ scanlS f initial `checkStreamConduit`+ Prelude.scanl f initial+ qit "scanlM" $+ \(getBlind -> (f :: Int -> Int -> M Int), initial) ->+ scanlM f initial `checkConduitT`+ scanlML f initial+ qit "scanlMS" $+ \(getBlind -> (f :: Int -> Int -> M Int), initial) ->+ scanlMS f initial `checkStreamConduitT`+ scanlML f initial+ qit "mapAccumWhileS" $+ \(getBlind -> ( f :: Int -> [Int] -> Either [Int] ([Int], Int))+ , initial :: [Int]) ->+ mapAccumWhileS f initial `checkStreamConduitResult`+ mapAccumWhileL f initial+ qit "mapAccumWhileMS" $+ \(getBlind -> ( f :: Int -> [Int] -> M (Either [Int] ([Int], Int)))+ , initial :: [Int]) ->+ mapAccumWhileMS f initial `checkStreamConduitResultM`+ mapAccumWhileML f initial+ qit "intersperse" $+ \(sep :: Int) ->+ intersperse sep `checkConduit`+ Data.List.intersperse sep+ qit "intersperseS" $+ \(sep :: Int) ->+ intersperseS sep `checkStreamConduit`+ Data.List.intersperse sep+ qit "filterM" $+ \(getBlind -> (f :: Int -> M Bool)) ->+ filterM f `checkConduitT`+ Control.Monad.filterM f+ qit "filterMS" $+ \(getBlind -> (f :: Int -> M Bool)) ->+ filterMS f `checkStreamConduitT`+ Control.Monad.filterM f+ describe "comparing normal conduit function to" $ do+ qit "slidingWindowS" $+ \(getSmall -> n) ->+ slidingWindowS n `checkStreamConduit`+ (\xs -> runConduitPure $+ yieldMany xs .| preventFusion (slidingWindow n) .| sinkList+ :: [Seq Int])+ qit "splitOnUnboundedES" $+ \(getBlind -> (f :: Int -> Bool)) ->+ splitOnUnboundedES f `checkStreamConduit`+ (\xs -> runConduitPure $+ yieldMany xs .| preventFusion (splitOnUnboundedE f) .| sinkList+ :: [Seq Int])+ qit "sinkVectorS" $+ \() -> checkStreamConsumerM'+ unsafePerformIO+ (sinkVectorS :: forall o. StreamConduitT Int o IO.IO (Vector Int))+ (\xs -> runConduit $ yieldMany xs .| preventFusion sinkVector)+ qit "sinkVectorNS" $+ \(getSmall . getNonNegative -> n) -> checkStreamConsumerM'+ unsafePerformIO+ (sinkVectorNS n :: forall o. StreamConduitT Int o IO.IO (Vector Int))+ (\xs -> runConduit $ yieldMany xs .| preventFusion (sinkVectorN n))++#if !MIN_VERSION_QuickCheck(2,8,2)+instance Arbitrary a => Arbitrary (Seq a) where+ arbitrary = Seq.fromList <$> arbitrary+#endif++repeatML :: Monad m => m a -> m [a]+repeatML = Prelude.sequence . Prelude.repeat++repeatWhileML :: Monad m => m a -> (a -> Bool) -> m [a]+repeatWhileML m f = go+ where+ go = do+ x <- m+ if f x+ then liftM (x:) go+ else return []++foldl1L :: (a -> a -> a) -> [a] -> Maybe a+foldl1L _ [] = Nothing+foldl1L f xs = Just $ Prelude.foldl1 f xs++lastEL :: Seq.IsSequence seq+ => [seq] -> Maybe (Element seq)+lastEL = Prelude.foldl go Nothing+ where+ go _ (NonNull.fromNullable -> Just l) = Just (NonNull.last l)+ go mlast _ = mlast++concatMapL :: MonoFoldable mono+ => (a -> mono) -> [a] -> [Element mono]+concatMapL f = Prelude.concatMap (otoList . f)++concatMapML :: (Monad m, MonoFoldable mono)+ => (a -> m mono) -> [a] -> m [Element mono]+concatMapML f = liftM (Prelude.concatMap otoList) . Prelude.mapM f++concatL :: MonoFoldable mono+ => [mono] -> [Element mono]+concatL = Prelude.concatMap otoList++scanlML :: Monad m => (a -> b -> m a) -> a -> [b] -> m [a]+scanlML f = go+ where+ go l [] = return [l]+ go l (r:rs) = do+ l' <- f l r+ liftM (l:) (go l' rs)++mapAccumWhileL :: (a -> s -> Either s (s, b)) -> s -> [a] -> ([b], s)+mapAccumWhileL f = (runIdentity.) . mapAccumWhileML ((return.) . f)++mapAccumWhileML :: Monad m =>+ (a -> s -> m (Either s (s, b))) -> s -> [a] -> m ([b], s)+mapAccumWhileML f = go+ where go s [] = return ([], s)+ go s (a:as) = f a s >>= either+ (return . ([], ))+ (\(s', b) -> liftM (first (b:)) $ go s' as)++--FIXME: the following code is directly copied from the conduit test+--suite. How to share this code??++qit :: (Arbitrary a, Testable prop, Show a)+ => String -> (a -> prop) -> Spec+qit n f = it n $ property $ forAll arbitrary f++--------------------------------------------------------------------------------+-- Quickcheck utilities for pure conduits / streams++checkProducer :: (Show a, Eq a) => ConduitT () a Identity () -> [a] -> Property+checkProducer c l = checkProducerM' runIdentity c (return l)++checkStreamProducer :: (Show a, Eq a) => StreamSource Identity a -> [a] -> Property+checkStreamProducer s l = checkStreamProducerM' runIdentity s (return l)++checkInfiniteProducer :: (Show a, Eq a) => ConduitT () a Identity () -> [a] -> Property+checkInfiniteProducer c l = checkInfiniteProducerM' runIdentity c (return l)++checkInfiniteStreamProducer :: (Show a, Eq a) => StreamSource Identity a -> [a] -> Property+checkInfiniteStreamProducer s l = checkInfiniteStreamProducerM' runIdentity s (return l)++checkConsumer :: (Show b, Eq b) => ConduitT Int Void Identity b -> ([Int] -> b) -> Property+checkConsumer c l = checkConsumerM' runIdentity c (return . l)++checkStreamConsumer :: (Show b, Eq b) => StreamConduitT Int o Identity b -> ([Int] -> b) -> Property+checkStreamConsumer c l = checkStreamConsumerM' runIdentity c (return . l)++checkConduit :: (Show a, Arbitrary a, Show b, Eq b) => ConduitT a b Identity () -> ([a] -> [b]) -> Property+checkConduit c l = checkConduitT' runIdentity c (return . l)++checkStreamConduit :: (Show a, Arbitrary a, Show b, Eq b) => StreamConduit a Identity b -> ([a] -> [b]) -> Property+checkStreamConduit c l = checkStreamConduitT' runIdentity c (return . l)++-- checkConduitResult :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => ConduitT a b Identity r -> ([a] -> ([b], r)) -> Property+-- checkConduitResult c l = checkConduitResultM' runIdentity c (return . l)++checkStreamConduitResult :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => StreamConduitT a b Identity r -> ([a] -> ([b], r)) -> Property+checkStreamConduitResult c l = checkStreamConduitResultM' runIdentity c (return . l)++--------------------------------------------------------------------------------+-- Quickcheck utilities for conduits / streams in the M monad.++checkProducerM :: (Show a, Eq a) => ConduitT () a M () -> M [a] -> Property+checkProducerM = checkProducerM' runM++checkStreamProducerM :: (Show a, Eq a) => StreamSource M a -> M [a] -> Property+checkStreamProducerM = checkStreamProducerM' runM++checkInfiniteProducerM :: (Show a, Eq a) => ConduitT () a M () -> M [a] -> Property+checkInfiniteProducerM = checkInfiniteProducerM' (fst . runM)++checkInfiniteStreamProducerM :: (Show a, Eq a) => StreamSource M a -> M [a] -> Property+checkInfiniteStreamProducerM = checkInfiniteStreamProducerM' (fst . runM)++checkConsumerM :: (Show b, Eq b) => ConduitT Int Void M b -> ([Int] -> M b) -> Property+checkConsumerM = checkConsumerM' runM++checkStreamConsumerM :: (Show b, Eq b) => StreamConduitT Int o M b -> ([Int] -> M b) -> Property+checkStreamConsumerM = checkStreamConsumerM' runM++checkConduitT :: (Show a, Arbitrary a, Show b, Eq b) => ConduitT a b M () -> ([a] -> M [b]) -> Property+checkConduitT = checkConduitT' runM++checkStreamConduitT :: (Show a, Arbitrary a, Show b, Eq b) => StreamConduitT a b M () -> ([a] -> M [b]) -> Property+checkStreamConduitT = checkStreamConduitT' runM++-- checkConduitResultM :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => ConduitT a b M r -> ([a] -> M ([b], r)) -> Property+-- checkConduitResultM = checkConduitResultM' runM++checkStreamConduitResultM :: (Show a, Arbitrary a, Show b, Eq b, Show r, Eq r) => StreamConduitT a b M r -> ([a] -> M ([b], r)) -> Property+checkStreamConduitResultM = checkStreamConduitResultM' runM++--------------------------------------------------------------------------------+-- Quickcheck utilities for monadic streams / conduits+-- These are polymorphic in which Monad is used.++checkProducerM' :: (Show a, Monad m, Show b, Eq b)+ => (m [a] -> b)+ -> ConduitT () a m ()+ -> m [a]+ -> Property+checkProducerM' f c l =+ f (runConduit $ preventFusion c .| sinkList)+ ===+ f l++checkStreamProducerM' :: (Show a, Monad m, Show b, Eq b)+ => (m [a] -> b)+ -> StreamConduitT () a m ()+ -> m [a]+ -> Property+checkStreamProducerM' f s l =+ f (liftM fst $ evalStream $ s emptyStream)+ ===+ f l++checkInfiniteProducerM' :: (Show a, Monad m, Show b, Eq b)+ => (m [a] -> b)+ -> ConduitT () a m ()+ -> m [a]+ -> Property+checkInfiniteProducerM' f s l =+ checkProducerM' f+ (preventFusion s .| take 10)+ (liftM (Prelude.take 10) l)++checkInfiniteStreamProducerM' :: (Show a, Monad m, Show b, Eq b)+ => (m [a] -> b)+ -> StreamConduitT () a m ()+ -> m [a]+ -> Property+checkInfiniteStreamProducerM' f s l =+ f (liftM snd $ evalStream $ takeS 10 $ s emptyStream)+ ===+ f (liftM (Prelude.take 10) l)++checkConsumerM' :: (Show a, Monad m, Show b, Eq b)+ => (m a -> b)+ -> ConduitT Int Void m a+ -> ([Int] -> m a)+ -> Property+checkConsumerM' f c l = forAll arbitrary $ \xs ->+ f (runConduit $ yieldMany xs .| preventFusion c)+ ===+ f (l xs)++checkStreamConsumerM' :: (Show a, Monad m, Show b, Eq b)+ => (m a -> b)+ -> StreamConduitT Int o m a+ -> ([Int] -> m a)+ -> Property+checkStreamConsumerM' f s l = forAll (arbitrary) $ \xs ->+ f (liftM snd $ evalStream $ s $ sourceListS xs emptyStream)+ ===+ f (l xs)++checkConduitT' :: (Show a, Arbitrary a, Monad m, Show c, Eq c)+ => (m [b] -> c)+ -> ConduitT a b m ()+ -> ([a] -> m [b])+ -> Property+checkConduitT' f c l = forAll arbitrary $ \xs ->+ f (runConduit $ yieldMany xs .| preventFusion c .| sinkList)+ ===+ f (l xs)++checkStreamConduitT' :: (Show a, Arbitrary a, Monad m, Show c, Eq c)+ => (m [b] -> c)+ -> StreamConduit a m b+ -> ([a] -> m [b])+ -> Property+checkStreamConduitT' f s l = forAll arbitrary $ \xs ->+ f (liftM fst $ evalStream $ s $ sourceListS xs emptyStream)+ ===+ f (l xs)++-- TODO: Fixing this would allow comparing conduit sinkListrs against+-- their list versions.+--+-- checkConduitResultM' :: (Show a, Arbitrary a, Monad m, Show c, Eq c)+-- => (m ([b], r) -> c)+-- -> ConduitT a b m r+-- -> ([a] -> m ([b], r))+-- -> Property+-- checkConduitResultM' f c l = FIXME forAll arbitrary $ \xs ->+-- f (runConduit $ yieldMany xs .| preventFusion c .| sinkList)+-- ===+-- f (l xs)++checkStreamConduitResultM' :: (Show a, Arbitrary a, Monad m, Show c, Eq c)+ => (m ([b], r) -> c)+ -> StreamConduitT a b m r+ -> ([a] -> m ([b], r))+ -> Property+checkStreamConduitResultM' f s l = forAll arbitrary $ \xs ->+ f (evalStream $ s $ sourceListS xs emptyStream)+ ===+ f (l xs)++emptyStream :: Monad m => Stream m () ()+emptyStream = Stream (\_ -> return $ Stop ()) (return ())++evalStream :: Monad m => Stream m o r -> m ([o], r)+evalStream (Stream step s0) = go =<< s0+ where+ go s = do+ res <- step s+ case res of+ Stop r -> return ([], r)+ Skip s' -> go s'+ Emit s' x -> liftM (\(l, r) -> (x:l, r)) (go s')++--------------------------------------------------------------------------------+-- Misc utilities++-- Prefer this to creating an orphan instance for Data.Monoid.Sum:++newtype Sum a = Sum a+ deriving (Eq, Show, Arbitrary)++instance Prelude.Num a => Monoid (Sum a) where+ mempty = Sum 0+ mappend (Sum x) (Sum y) = Sum $ x Prelude.+ y++preventFusion :: a -> a+preventFusion = id+{-# INLINE [0] preventFusion #-}++newtype M a = M (StateT Int Identity a)+ deriving (Functor, Applicative, Monad)++instance Arbitrary a => Arbitrary (M a) where+ arbitrary = do+ f <- arbitrary+ return $ do+ s <- M get+ let (x, s') = f s+ M (put s')+ return x++runM :: M a -> (a, Int)+runM (M m) = runIdentity $ runStateT m 0++--------------------------------------------------------------------------------+-- Utilities from QuickCheck-2.7 (absent in earlier versions)++#if !MIN_VERSION_QuickCheck(2,7,0)+getBlind :: Blind a -> a+getBlind (Blind x) = x++-- | @Small x@: generates values of @x@ drawn from a small range.+-- The opposite of 'Large'.+newtype Small a = Small {getSmall :: a}+ deriving (Prelude.Ord, Prelude.Eq, Prelude.Enum, Prelude.Show, Prelude.Num)++instance Prelude.Integral a => Arbitrary (Small a) where+ arbitrary = Prelude.fmap Small arbitrarySizedIntegral+ shrink (Small x) = Prelude.map Small (shrinkIntegral x)++(===) :: (Show a, Eq a) => a -> a -> Property+x === y = whenFail+ (Prelude.fail $ Prelude.show x Prelude.++ " should match " Prelude.++ Prelude.show y)+ (x Prelude.== y)+#endif
+ test/doctests.hs view
@@ -0,0 +1,6 @@+module Main where++import Test.DocTest++main :: IO ()+main = doctest ["Data/Conduit.hs"]
test/main.hs view
@@ -7,13 +7,16 @@ import Test.Hspec.QuickCheck (prop) import Test.QuickCheck.Monadic (assert, monadicIO, run) +import Data.Conduit (runConduit, (.|), ConduitT, runConduitPure, runConduitRes) import qualified Data.Conduit as C import qualified Data.Conduit.Lift as C import qualified Data.Conduit.Internal as CI import qualified Data.Conduit.List as CL import Data.Typeable (Typeable) import Control.Exception (throw)-import Control.Monad.Trans.Resource as C (runResourceT)+import Control.Monad.Trans.Resource (runResourceT)+import Control.Monad.Trans.Maybe (MaybeT (MaybeT))+import Control.Monad.State.Strict (modify) import Data.Maybe (fromMaybe,catMaybes,fromJust) import qualified Data.List as DL import qualified Data.List.Split as DLS (chunksOf)@@ -22,11 +25,10 @@ import qualified Data.IORef as I import Control.Monad.Trans.Resource (allocate, resourceForkIO) import Control.Concurrent (threadDelay, killThread)-import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Writer (execWriter, tell, runWriterT)-import Control.Monad.Trans.State (evalStateT, get, put, modify)-import Control.Monad.Trans.Maybe (MaybeT (..))+import Control.Monad.Trans.State (evalStateT, get, put) import qualified Control.Monad.Writer as W import Control.Applicative (pure, (<$>), (<*>)) import qualified Control.Monad.Catch as Catch@@ -34,41 +36,43 @@ import Control.Monad (forever, void) import Data.Void (Void) import qualified Control.Concurrent.MVar as M-import Control.Monad.Error (catchError, throwError, Error)+import Control.Monad.Except (catchError, throwError) import qualified Data.Map as Map import qualified Data.Conduit.Extra.ZipConduitSpec as ZipConduit import qualified Data.Conduit.StreamSpec as Stream+import qualified Spec (@=?) :: (Eq a, Show a) => a -> a -> IO () (@=?) = flip shouldBe -- Quickcheck property for testing equivalence of list processing -- functions and their conduit counterparts-equivToList :: Eq b => ([a] -> [b]) -> CI.Conduit a Identity b -> [a] -> Bool+equivToList :: Eq b => ([a] -> [b]) -> ConduitT a b Identity () -> [a] -> Bool equivToList f conduit xs =- f xs == runIdentity (CL.sourceList xs C.$$ conduit C.=$= CL.consume)+ f xs == runConduitPure (CL.sourceList xs .| conduit .| CL.consume) main :: IO () main = hspec $ do+ describe "Combinators" Spec.spec describe "data loss rules" $ do it "consumes the source to quickly" $ do- x <- runResourceT $ CL.sourceList [1..10 :: Int] C.$$ do- strings <- CL.map show C.=$ CL.take 5+ x <- runConduitRes $ CL.sourceList [1..10 :: Int] .| do+ strings <- CL.map show .| CL.take 5 liftIO $ putStr $ unlines strings CL.fold (+) 0 40 `shouldBe` x it "correctly consumes a chunked resource" $ do- x <- runResourceT $ (CL.sourceList [1..5 :: Int] `mappend` CL.sourceList [6..10]) C.$$ do- strings <- CL.map show C.=$ CL.take 5+ x <- runConduitRes $ (CL.sourceList [1..5 :: Int] `mappend` CL.sourceList [6..10]) .| do+ strings <- CL.map show .| CL.take 5 liftIO $ putStr $ unlines strings CL.fold (+) 0 40 `shouldBe` x describe "filter" $ do it "even" $ do- x <- runResourceT $ CL.sourceList [1..10] C.$$ CL.filter even C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList [1..10] .| CL.filter even .| CL.consume x `shouldBe` filter even [1..10 :: Int] prop "concat" $ equivToList (concat :: [[Int]]->[Int]) CL.concat@@ -119,28 +123,28 @@ describe "sum" $ do it "works for 1..10" $ do- x <- runResourceT $ CL.sourceList [1..10] C.$$ CL.fold (+) (0 :: Int)+ x <- runConduitRes $ CL.sourceList [1..10] .| CL.fold (+) (0 :: Int) x `shouldBe` sum [1..10] prop "is idempotent" $ \list ->- (runST $ CL.sourceList list C.$$ CL.fold (+) (0 :: Int))+ (runST $ runConduit $ CL.sourceList list .| CL.fold (+) (0 :: Int)) == sum list describe "foldMap" $ do it "sums 1..10" $ do- Sum x <- CL.sourceList [1..(10 :: Int)] C.$$ CL.foldMap Sum+ Sum x <- runConduit $ CL.sourceList [1..(10 :: Int)] .| CL.foldMap Sum x `shouldBe` sum [1..10] it "preserves order" $ do- x <- CL.sourceList [[4],[2],[3],[1]] C.$$ CL.foldMap (++[(9 :: Int)])+ x <- runConduit $ CL.sourceList [[4],[2],[3],[1]] .| CL.foldMap (++[(9 :: Int)]) x `shouldBe` [4,9,2,9,3,9,1,9] describe "foldMapM" $ do it "sums 1..10" $ do- Sum x <- CL.sourceList [1..(10 :: Int)] C.$$ CL.foldMapM (return . Sum)+ Sum x <- runConduit $ CL.sourceList [1..(10 :: Int)] .| CL.foldMapM (return . Sum) x `shouldBe` sum [1..10] it "preserves order" $ do- x <- CL.sourceList [[4],[2],[3],[1]] C.$$ CL.foldMapM (return . (++[(9 :: Int)]))+ x <- runConduit $ CL.sourceList [[4],[2],[3],[1]] .| CL.foldMapM (return . (++[(9 :: Int)])) x `shouldBe` [4,9,2,9,3,9,1,9] describe "unfold" $ do@@ -148,7 +152,7 @@ let f 0 = Nothing f i = Just (show i, i - 1) seed = 10 :: Int- x <- CL.unfold f seed C.$$ CL.consume+ x <- runConduit $ CL.unfold f seed .| CL.consume let y = DL.unfoldr f seed x `shouldBe` y @@ -157,54 +161,54 @@ let f 0 = Nothing f i = Just (show i, i - 1) seed = 10 :: Int- x <- CL.unfoldM (return . f) seed C.$$ CL.consume+ x <- runConduit $ CL.unfoldM (return . f) seed .| CL.consume let y = DL.unfoldr f seed x `shouldBe` y describe "Monoid instance for Source" $ do it "mappend" $ do- x <- runResourceT $ (CL.sourceList [1..5 :: Int] `mappend` CL.sourceList [6..10]) C.$$ CL.fold (+) 0+ x <- runConduitRes $ (CL.sourceList [1..5 :: Int] `mappend` CL.sourceList [6..10]) .| CL.fold (+) 0 x `shouldBe` sum [1..10] it "mconcat" $ do- x <- runResourceT $ mconcat+ x <- runConduitRes $ mconcat [ CL.sourceList [1..5 :: Int] , CL.sourceList [6..10] , CL.sourceList [11..20]- ] C.$$ CL.fold (+) 0+ ] .| CL.fold (+) 0 x `shouldBe` sum [1..20] describe "zipping" $ do it "zipping two small lists" $ do- res <- runResourceT $ CI.zipSources (CL.sourceList [1..10]) (CL.sourceList [11..12]) C.$$ CL.consume+ res <- runConduitRes $ CI.zipSources (CL.sourceList [1..10]) (CL.sourceList [11..12]) .| CL.consume res @=? zip [1..10 :: Int] [11..12 :: Int] describe "zipping sinks" $ do it "take all" $ do- res <- runResourceT $ CL.sourceList [1..10] C.$$ CI.zipSinks CL.consume CL.consume+ res <- runConduitRes $ CL.sourceList [1..10] .| CI.zipSinks CL.consume CL.consume res @=? ([1..10 :: Int], [1..10 :: Int]) it "take fewer on left" $ do- res <- runResourceT $ CL.sourceList [1..10] C.$$ CI.zipSinks (CL.take 4) CL.consume+ res <- runConduitRes $ CL.sourceList [1..10] .| CI.zipSinks (CL.take 4) CL.consume res @=? ([1..4 :: Int], [1..10 :: Int]) it "take fewer on right" $ do- res <- runResourceT $ CL.sourceList [1..10] C.$$ CI.zipSinks CL.consume (CL.take 4)+ res <- runConduitRes $ CL.sourceList [1..10] .| CI.zipSinks CL.consume (CL.take 4) res @=? ([1..10 :: Int], [1..4 :: Int]) describe "Monad instance for Sink" $ do it "binding" $ do- x <- runResourceT $ CL.sourceList [1..10] C.$$ do+ x <- runConduitRes $ CL.sourceList [1..10] .| do _ <- CL.take 5 CL.fold (+) (0 :: Int) x `shouldBe` sum [6..10] describe "Applicative instance for Sink" $ do it "<$> and <*>" $ do- x <- runResourceT $ CL.sourceList [1..10] C.$$+ x <- runConduitRes $ CL.sourceList [1..10] .| (+) <$> pure 5 <*> CL.fold (+) (0 :: Int) x `shouldBe` sum [1..10] + 5 describe "resumable sources" $ do it "simple" $ do- (x, y, z) <- runResourceT $ do+ (x, y, z) <- runConduitRes $ do let src1 = CL.sourceList [1..10 :: Int] (src2, x) <- src1 C.$$+ CL.take 5 (src3, y) <- src2 C.$$++ CL.fold (+) 0@@ -216,25 +220,25 @@ describe "conduits" $ do it "map, left" $ do- x <- runResourceT $+ x <- runConduitRes $ CL.sourceList [1..10]- C.$= CL.map (* 2)- C.$$ CL.fold (+) 0+ .| CL.map (* 2)+ .| CL.fold (+) 0 x `shouldBe` 2 * sum [1..10 :: Int] it "map, left >+>" $ do- x <- runResourceT $- CI.ConduitM- ((CI.unConduitM (CL.sourceList [1..10]) CI.Done- CI.>+> CI.injectLeftovers (flip CI.unConduitM CI.Done $ CL.map (* 2))) >>=)- C.$$ CL.fold (+) 0+ x <- runConduitRes $+ CI.ConduitT+ ((CI.unConduitT (CL.sourceList [1..10]) CI.Done+ CI.>+> CI.injectLeftovers (flip CI.unConduitT CI.Done $ CL.map (* 2))) >>=)+ .| CL.fold (+) 0 x `shouldBe` 2 * sum [1..10 :: Int] it "map, right" $ do- x <- runResourceT $+ x <- runConduitRes $ CL.sourceList [1..10]- C.$$ CL.map (* 2)- C.=$ CL.fold (+) 0+ .| CL.map (* 2)+ .| CL.fold (+) 0 x `shouldBe` 2 * sum [1..10 :: Int] prop "chunksOf" $ equivToList@@ -245,98 +249,98 @@ it "groupBy" $ do let input = [1::Int, 1, 2, 3, 3, 3, 4, 5, 5]- x <- runResourceT $ CL.sourceList input- C.$$ CL.groupBy (==)- C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList input+ .| CL.groupBy (==)+ .| CL.consume x `shouldBe` DL.groupBy (==) input it "groupBy (nondup begin/end)" $ do let input = [1::Int, 2, 3, 3, 3, 4, 5]- x <- runResourceT $ CL.sourceList input- C.$$ CL.groupBy (==)- C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList input+ .| CL.groupBy (==)+ .| CL.consume x `shouldBe` DL.groupBy (==) input it "groupOn1" $ do let input = [1::Int, 1, 2, 3, 3, 3, 4, 5, 5]- x <- runResourceT $ CL.sourceList input- C.$$ CL.groupOn1 id- C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList input+ .| CL.groupOn1 id+ .| CL.consume x `shouldBe` [(1,[1]), (2, []), (3,[3,3]), (4,[]), (5, [5])] it "groupOn1 (nondup begin/end)" $ do let input = [1::Int, 2, 3, 3, 3, 4, 5]- x <- runResourceT $ CL.sourceList input- C.$$ CL.groupOn1 id- C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList input+ .| CL.groupOn1 id+ .| CL.consume x `shouldBe` [(1,[]), (2, []), (3,[3,3]), (4,[]), (5, [])] it "mapMaybe" $ do let input = [Just (1::Int), Nothing, Just 2, Nothing, Just 3]- x <- runResourceT $ CL.sourceList input- C.$$ CL.mapMaybe ((+2) <$>)- C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList input+ .| CL.mapMaybe ((+2) <$>)+ .| CL.consume x `shouldBe` [3, 4, 5] it "mapMaybeM" $ do let input = [Just (1::Int), Nothing, Just 2, Nothing, Just 3]- x <- runResourceT $ CL.sourceList input- C.$$ CL.mapMaybeM (return . ((+2) <$>))- C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList input+ .| CL.mapMaybeM (return . ((+2) <$>))+ .| CL.consume x `shouldBe` [3, 4, 5] it "catMaybes" $ do let input = [Just (1::Int), Nothing, Just 2, Nothing, Just 3]- x <- runResourceT $ CL.sourceList input- C.$$ CL.catMaybes- C.=$ CL.consume+ x <- runConduitRes $ CL.sourceList input+ .| CL.catMaybes+ .| CL.consume x `shouldBe` [1, 2, 3] it "concatMap" $ do let input = [1, 11, 21]- x <- runResourceT $ CL.sourceList input- C.$$ CL.concatMap (\i -> enumFromTo i (i + 9))- C.=$ CL.fold (+) (0 :: Int)+ x <- runConduitRes $ CL.sourceList input+ .| CL.concatMap (\i -> enumFromTo i (i + 9))+ .| CL.fold (+) (0 :: Int) x `shouldBe` sum [1..30] it "bind together" $ do- let conduit = CL.map (+ 5) C.=$= CL.map (* 2)- x <- runResourceT $ CL.sourceList [1..10] C.$= conduit C.$$ CL.fold (+) 0+ let conduit = CL.map (+ 5) .| CL.map (* 2)+ x <- runConduitRes $ CL.sourceList [1..10] .| conduit .| CL.fold (+) 0 x `shouldBe` sum (map (* 2) $ map (+ 5) [1..10 :: Int]) #if !FAST describe "isolate" $ do it "bound to resumable source" $ do- (x, y) <- runResourceT $ do+ (x, y) <- runConduitRes $ do let src1 = CL.sourceList [1..10 :: Int]- (src2, x) <- src1 C.$= CL.isolate 5 C.$$+ CL.consume+ (src2, x) <- src1 .| CL.isolate 5 C.$$+ CL.consume y <- src2 C.$$+- CL.consume return (x, y) x `shouldBe` [1..5] y `shouldBe` [] it "bound to sink, non-resumable" $ do- (x, y) <- runResourceT $ do- CL.sourceList [1..10 :: Int] C.$$ do- x <- CL.isolate 5 C.=$ CL.consume+ (x, y) <- runConduitRes $ do+ CL.sourceList [1..10 :: Int] .| do+ x <- CL.isolate 5 .| CL.consume y <- CL.consume return (x, y) x `shouldBe` [1..5] y `shouldBe` [6..10] it "bound to sink, resumable" $ do- (x, y) <- runResourceT $ do+ (x, y) <- runConduitRes $ do let src1 = CL.sourceList [1..10 :: Int]- (src2, x) <- src1 C.$$+ CL.isolate 5 C.=$ CL.consume+ (src2, x) <- src1 C.$$+ CL.isolate 5 .| CL.consume y <- src2 C.$$+- CL.consume return (x, y) x `shouldBe` [1..5] y `shouldBe` [6..10] it "consumes all data" $ do- x <- runResourceT $ CL.sourceList [1..10 :: Int] C.$$ do- CL.isolate 5 C.=$ CL.sinkNull+ x <- runConduitRes $ CL.sourceList [1..10 :: Int] .| do+ CL.isolate 5 .| CL.sinkNull CL.consume x `shouldBe` [6..10] @@ -348,9 +352,9 @@ Nothing -> return 0 Just a -> (+a) . fromMaybe 0 <$> CL.head - res <- runResourceT $ CL.sourceList [1..11 :: Int]- C.$= CL.sequence sumSink- C.$$ CL.consume+ res <- runConduitRes $ CL.sourceList [1..11 :: Int]+ .| CL.sequence sumSink+ .| CL.consume res `shouldBe` [3, 7, 11, 15, 19, 11] it "sink with unpull behaviour" $ do@@ -360,16 +364,16 @@ Nothing -> return 0 Just a -> (+a) . fromMaybe 0 <$> CL.peek - res <- runResourceT $ CL.sourceList [1..11 :: Int]- C.$= CL.sequence sumSink- C.$$ CL.consume+ res <- runConduitRes $ CL.sourceList [1..11 :: Int]+ .| CL.sequence sumSink+ .| CL.consume res `shouldBe` [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 11] #endif describe "peek" $ do it "works" $ do- (a, b) <- runResourceT $ CL.sourceList [1..10 :: Int] C.$$ do+ (a, b) <- runConduitRes $ CL.sourceList [1..10 :: Int] .| do a <- CL.peek b <- CL.consume return (a, b)@@ -377,51 +381,52 @@ describe "unbuffering" $ do it "works" $ do- x <- runResourceT $ do+ x <- runConduitRes $ do let src1 = CL.sourceList [1..10 :: Int] (src2, ()) <- src1 C.$$+ CL.drop 5 src2 C.$$+- CL.fold (+) 0 x `shouldBe` sum [6..10] describe "operators" $ do- it "only use =$=" $- runIdentity+ it "only use .|" $+ runConduitPure ( CL.sourceList [1..10 :: Int]- C.$$ CL.map (+ 1)- C.=$ CL.map (subtract 1)- C.=$ CL.mapM (return . (* 2))- C.=$ CL.map (`div` 2)- C.=$ CL.fold (+) 0+ .| CL.map (+ 1)+ .| CL.map (subtract 1)+ .| CL.mapM (return . (* 2))+ .| CL.map (`div` 2)+ .| CL.fold (+) 0 ) `shouldBe` sum [1..10] it "only use =$" $- runIdentity+ runConduitPure ( CL.sourceList [1..10 :: Int]- C.$$ CL.map (+ 1)- C.=$ CL.map (subtract 1)- C.=$ CL.map (* 2)- C.=$ CL.map (`div` 2)- C.=$ CL.fold (+) 0+ .| CL.map (+ 1)+ .| CL.map (subtract 1)+ .| CL.map (* 2)+ .| CL.map (`div` 2)+ .| CL.fold (+) 0 ) `shouldBe` sum [1..10] it "chain" $ do- x <- CL.sourceList [1..10 :: Int]- C.$= CL.map (+ 1)- C.$= CL.map (+ 1)- C.$= CL.map (+ 1)- C.$= CL.map (subtract 3)- C.$= CL.map (* 2)- C.$$ CL.map (`div` 2)- C.=$ CL.map (+ 1)- C.=$ CL.map (+ 1)- C.=$ CL.map (+ 1)- C.=$ CL.map (subtract 3)- C.=$ CL.fold (+) 0+ x <- runConduit+ $ CL.sourceList [1..10 :: Int]+ .| CL.map (+ 1)+ .| CL.map (+ 1)+ .| CL.map (+ 1)+ .| CL.map (subtract 3)+ .| CL.map (* 2)+ .| CL.map (`div` 2)+ .| CL.map (+ 1)+ .| CL.map (+ 1)+ .| CL.map (+ 1)+ .| CL.map (subtract 3)+ .| CL.fold (+) 0 x `shouldBe` sum [1..10] describe "termination" $ do it "terminates early" $ do let src = forever $ C.yield ()- x <- src C.$$ CL.head+ x <- runConduit $ src .| CL.head x `shouldBe` Just () it "bracket" $ do ref <- I.newIORef (0 :: Int)@@ -429,7 +434,7 @@ (I.modifyIORef ref (+ 1)) (\() -> I.modifyIORef ref (+ 2)) (\() -> forever $ C.yield (1 :: Int))- val <- C.runResourceT $ src C.$$ CL.isolate 10 C.=$ CL.fold (+) 0+ val <- runConduitRes $ src .| CL.isolate 10 .| CL.fold (+) 0 val `shouldBe` 10 i <- I.readIORef ref i `shouldBe` 3@@ -440,7 +445,7 @@ (\() -> I.modifyIORef ref (+ 2)) (\() -> forever $ C.yield (1 :: Int)) src' = CL.sourceList $ repeat 1- val <- C.runResourceT $ (src' >> src) C.$$ CL.isolate 10 C.=$ CL.fold (+) 0+ val <- runConduitRes $ (src' >> src) .| CL.isolate 10 .| CL.fold (+) 0 val `shouldBe` 10 i <- I.readIORef ref i `shouldBe` 0@@ -450,7 +455,7 @@ (I.modifyIORef ref (+ 1)) (\() -> I.modifyIORef ref (+ 2)) (\() -> forever $ C.yield (1 :: Int))- val <- C.runResourceT $ src C.$$ CL.isolate 10 C.=$ CL.fold (+) 0+ val <- runConduitRes $ src .| CL.isolate 10 .| CL.fold (+) 0 val `shouldBe` 10 i <- I.readIORef ref i `shouldBe` 3@@ -461,7 +466,7 @@ (\() -> I.modifyIORef ref (+ 2)) (\() -> forever $ C.yield (1 :: Int)) src' = CL.sourceList $ repeat 1- val <- C.runResourceT $ (src' >> src) C.$$ CL.isolate 10 C.=$ CL.fold (+) 0+ val <- runConduitRes $ (src' >> src) .| CL.isolate 10 .| CL.fold (+) 0 val `shouldBe` 10 i <- I.readIORef ref i `shouldBe` 0@@ -471,20 +476,20 @@ ref <- I.newIORef [] let add x = I.modifyIORef ref (x:) adder' = CI.NeedInput (\a -> liftIO (add a) >> adder') return- adder = CI.ConduitM (adder' >>=)- residue x = CI.ConduitM $ \rest -> CI.Leftover (rest ()) x+ adder = CI.ConduitT (adder' >>=)+ residue x = CI.ConduitT $ \rest -> CI.Leftover (rest ()) x - _ <- C.yield 1 C.$$ adder+ _ <- runConduit $ C.yield 1 .| adder x <- I.readIORef ref x `shouldBe` [1 :: Int] I.writeIORef ref [] - _ <- C.yield 1 C.$$ (residue 2 >> residue 3) >> adder+ _ <- runConduit $ C.yield 1 .| ((residue 2 >> residue 3) >> adder) y <- I.readIORef ref y `shouldBe` [1, 2, 3] I.writeIORef ref [] - _ <- C.yield 1 C.$$ residue 2 >> (residue 3 >> adder)+ _ <- runConduit $ C.yield 1 .| (residue 2 >> (residue 3 >> adder)) z <- I.readIORef ref z `shouldBe` [1, 2, 3] I.writeIORef ref []@@ -494,18 +499,12 @@ let is = [1..10] ++ undefined src [] = return () src (x:xs) = C.yield x >> src xs- x <- src is C.$$ CL.take 10+ x <- runConduit $ src is .| CL.take 10 x `shouldBe` [1..10 :: Int] it' "yield terminates (2)" $ do let is = [1..10] ++ undefined- x <- mapM_ C.yield is C.$$ CL.take 10+ x <- runConduit $ mapM_ C.yield is .| CL.take 10 x `shouldBe` [1..10 :: Int]- it' "yieldOr finalizer called" $ do- iref <- I.newIORef (0 :: Int)- let src = mapM_ (\i -> C.yieldOr i $ I.writeIORef iref i) [1..]- src C.$$ CL.isolate 10 C.=$ CL.sinkNull- x <- I.readIORef iref- x `shouldBe` 10 describe "upstream results" $ do it' "works" $ do@@ -518,17 +517,17 @@ describe "input/output mapping" $ do it' "mapOutput" $ do- x <- C.mapOutput (+ 1) (CL.sourceList [1..10 :: Int]) C.$$ CL.fold (+) 0+ x <- runConduit $ C.mapOutput (+ 1) (CL.sourceList [1..10 :: Int]) .| CL.fold (+) 0 x `shouldBe` sum [2..11] it' "mapOutputMaybe" $ do- x <- C.mapOutputMaybe (\i -> if even i then Just i else Nothing) (CL.sourceList [1..10 :: Int]) C.$$ CL.fold (+) 0+ x <- runConduit $ C.mapOutputMaybe (\i -> if even i then Just i else Nothing) (CL.sourceList [1..10 :: Int]) .| CL.fold (+) 0 x `shouldBe` sum [2, 4..10] it' "mapInput" $ do- xyz <- (CL.sourceList $ map show [1..10 :: Int]) C.$$ do+ xyz <- runConduit $ (CL.sourceList $ map show [1..10 :: Int]) .| do (x, y) <- C.mapInput read (Just . show) $ ((do- x <- CL.isolate 5 C.=$ CL.fold (+) 0+ x <- CL.isolate 5 .| CL.fold (+) 0 y <- CL.peek- return (x :: Int, y :: Maybe Int)) :: C.Sink Int IO (Int, Maybe Int))+ return (x :: Int, y :: Maybe Int)) :: ConduitT Int Void IO (Int, Maybe Int)) z <- CL.consume return (x, y, concat z) @@ -536,12 +535,12 @@ describe "left/right identity" $ do it' "left identity" $ do- x <- CL.sourceList [1..10 :: Int] C.$$ CI.ConduitM (CI.idP >>=) C.=$ CL.fold (+) 0- y <- CL.sourceList [1..10 :: Int] C.$$ CL.fold (+) 0+ x <- runConduit $ CL.sourceList [1..10 :: Int] .| CI.ConduitT (CI.idP >>=) .| CL.fold (+) 0+ y <- runConduit $ CL.sourceList [1..10 :: Int] .| CL.fold (+) 0 x `shouldBe` y it' "right identity" $ do- x <- CI.runPipe $ mapM_ CI.yield [1..10 :: Int] CI.>+> (CI.injectLeftovers $ flip CI.unConduitM CI.Done $ CL.fold (+) 0) CI.>+> CI.idP- y <- CI.runPipe $ mapM_ CI.yield [1..10 :: Int] CI.>+> (CI.injectLeftovers $ flip CI.unConduitM CI.Done $ CL.fold (+) 0)+ x <- CI.runPipe $ mapM_ CI.yield [1..10 :: Int] CI.>+> (CI.injectLeftovers $ flip CI.unConduitT CI.Done $ CL.fold (+) 0) CI.>+> CI.idP+ y <- CI.runPipe $ mapM_ CI.yield [1..10 :: Int] CI.>+> (CI.injectLeftovers $ flip CI.unConduitT CI.Done $ CL.fold (+) 0) x `shouldBe` y describe "generalizing" $ do@@ -570,122 +569,32 @@ describe "iterate" $ do it' "works" $ do- res <- CL.iterate (+ 1) (1 :: Int) C.$$ CL.isolate 10 C.=$ CL.fold (+) 0+ res <- runConduit $ CL.iterate (+ 1) (1 :: Int) .| CL.isolate 10 .| CL.fold (+) 0 res `shouldBe` sum [1..10] prop "replicate" $ \cnt' -> do let cnt = min cnt' 100- res <- CL.replicate cnt () C.$$ CL.consume+ res <- runConduit $ CL.replicate cnt () .| CL.consume res `shouldBe` replicate cnt () prop "replicateM" $ \cnt' -> do ref <- I.newIORef 0 let cnt = min cnt' 100- res <- CL.replicateM cnt (I.modifyIORef ref (+ 1)) C.$$ CL.consume+ res <- runConduit $ CL.replicateM cnt (I.modifyIORef ref (+ 1)) .| CL.consume res `shouldBe` replicate cnt () ref' <- I.readIORef ref ref' `shouldBe` (if cnt' <= 0 then 0 else cnt) - describe "unwrapResumable" $ do- it' "works" $ do- ref <- I.newIORef (0 :: Int)- let src0 = do- C.yieldOr () $ I.writeIORef ref 1- C.yieldOr () $ I.writeIORef ref 2- C.yieldOr () $ I.writeIORef ref 3- (rsrc0, Just ()) <- src0 C.$$+ CL.head-- x0 <- I.readIORef ref- x0 `shouldBe` 0-- (_, final) <- C.unwrapResumable rsrc0-- x1 <- I.readIORef ref- x1 `shouldBe` 0-- final-- x2 <- I.readIORef ref- x2 `shouldBe` 1-- it' "isn't called twice" $ do- ref <- I.newIORef (0 :: Int)- let src0 = do- C.yieldOr () $ I.writeIORef ref 1- C.yieldOr () $ I.writeIORef ref 2- (rsrc0, Just ()) <- src0 C.$$+ CL.head-- x0 <- I.readIORef ref- x0 `shouldBe` 0-- (src1, final) <- C.unwrapResumable rsrc0-- x1 <- I.readIORef ref- x1 `shouldBe` 0-- Just () <- src1 C.$$ CL.head-- x2 <- I.readIORef ref- x2 `shouldBe` 2-- final-- x3 <- I.readIORef ref- x3 `shouldBe` 2-- it' "source isn't used" $ do- ref <- I.newIORef (0 :: Int)- let src0 = do- C.yieldOr () $ I.writeIORef ref 1- C.yieldOr () $ I.writeIORef ref 2- (rsrc0, Just ()) <- src0 C.$$+ CL.head-- x0 <- I.readIORef ref- x0 `shouldBe` 0-- (src1, final) <- C.unwrapResumable rsrc0-- x1 <- I.readIORef ref- x1 `shouldBe` 0-- () <- src1 C.$$ return ()-- x2 <- I.readIORef ref- x2 `shouldBe` 0-- final-- x3 <- I.readIORef ref- x3 `shouldBe` 1 describe "injectLeftovers" $ do it "works" $ do let src = mapM_ CI.yield [1..10 :: Int]- conduit = CI.injectLeftovers $ flip CI.unConduitM CI.Done $ C.awaitForever $ \i -> do+ conduit = CI.injectLeftovers $ flip CI.unConduitT CI.Done $ C.awaitForever $ \i -> do js <- CL.take 2 mapM_ C.leftover $ reverse js C.yield i- res <- CI.ConduitM ((src CI.>+> CI.injectLeftovers conduit) >>=) C.$$ CL.consume+ res <- runConduit $ CI.ConduitT ((src CI.>+> CI.injectLeftovers conduit) >>=) .| CL.consume res `shouldBe` [1..10]- describe "up-upstream finalizers" $ do- it "pipe" $ do- let p1 = CI.await >>= maybe (return ()) CI.yield- p2 = idMsg "p2-final"- p3 = idMsg "p3-final"- idMsg msg = CI.addCleanup (const $ tell [msg]) $ CI.awaitForever CI.yield- printer = CI.awaitForever $ lift . tell . return . show- src = mapM_ CI.yield [1 :: Int ..]- let run' p = execWriter $ CI.runPipe $ printer CI.<+< p CI.<+< src- run' (p1 CI.<+< (p2 CI.<+< p3)) `shouldBe` run' ((p1 CI.<+< p2) CI.<+< p3)- it "conduit" $ do- let p1 = C.await >>= maybe (return ()) C.yield- p2 = idMsg "p2-final"- p3 = idMsg "p3-final"- idMsg msg = C.addCleanup (const $ tell [msg]) $ C.awaitForever C.yield- printer = C.awaitForever $ lift . tell . return . show- src = CL.sourceList [1 :: Int ..]- let run' p = execWriter $ src C.$$ p C.=$ printer- run' ((p3 C.=$= p2) C.=$= p1) `shouldBe` run' (p3 C.=$= (p2 C.=$= p1)) describe "monad transformer laws" $ do it "transPipe" $ do let source = CL.sourceList $ replicate 10 ()@@ -702,15 +611,15 @@ lift $ get >>= lift . tell' C.yield i - x <- runWriterT $ source C.$$ C.transPipe (`evalStateT` 1) replaceNum1 C.=$ CL.consume- y <- runWriterT $ source C.$$ C.transPipe (`evalStateT` 1) replaceNum2 C.=$ CL.consume+ x <- runWriterT $ runConduit $ source .| C.transPipe (`evalStateT` 1) replaceNum1 .| CL.consume+ y <- runWriterT $ runConduit $ source .| C.transPipe (`evalStateT` 1) replaceNum2 .| CL.consume x `shouldBe` y describe "iterM" $ do prop "behavior" $ \l -> monadicIO $ do let counter ref = CL.iterM (const $ liftIO $ M.modifyMVar_ ref (\i -> return $! i + 1)) v <- run $ do ref <- M.newMVar 0- CL.sourceList l C.$= counter ref C.$$ CL.mapM_ (const $ return ())+ runConduit $ CL.sourceList l .| counter ref .| CL.mapM_ (const $ return ()) M.readMVar ref assert $ v == length (l :: [Int])@@ -718,7 +627,7 @@ let runTest h = run $ do ref <- M.newMVar (0 :: Int) let f = action ref- s <- CL.sourceList (l :: [Int]) C.$= h f C.$$ CL.fold (+) 0+ s <- runConduit $ CL.sourceList (l :: [Int]) .| h f .| CL.fold (+) 0 c <- M.readMVar ref return (c, s)@@ -732,117 +641,36 @@ describe "generalizing" $ do it "works" $ do- let src :: Int -> C.Source IO Int+ let src :: Int -> ConduitT () Int IO () src i = CL.sourceList [1..i]- sink :: C.Sink Int IO Int+ sink :: ConduitT Int Void IO Int sink = CL.fold (+) 0- res <- C.yield 10 C.$$ C.awaitForever (C.toProducer . src) C.=$ (C.toConsumer sink >>= C.yield) C.=$ C.await+ res <- runConduit $ C.yield 10 .| C.awaitForever (C.toProducer . src) .| (C.toConsumer sink >>= C.yield) .| C.await res `shouldBe` Just (sum [1..10]) describe "mergeSource" $ do it "works" $ do- let src :: C.Source IO String+ let src :: ConduitT () String IO () src = CL.sourceList ["A", "B", "C"]- withIndex :: C.Conduit String IO (Integer, String)+ withIndex :: ConduitT String (Integer, String) IO () withIndex = CI.mergeSource (CL.sourceList [1..])- output <- src C.$= withIndex C.$$ CL.consume+ output <- runConduit $ src .| withIndex .| CL.consume output `shouldBe` [(1, "A"), (2, "B"), (3, "C")] it "does stop processing when the source exhausted" $ do- let src :: C.Source IO Integer+ let src :: ConduitT () Integer IO () src = CL.sourceList [1..]- withShortAlphaIndex :: C.Conduit Integer IO (String, Integer)+ withShortAlphaIndex :: ConduitT Integer (String, Integer) IO () withShortAlphaIndex = CI.mergeSource (CL.sourceList ["A", "B", "C"])- output <- src C.$= withShortAlphaIndex C.$$ CL.consume+ output <- runConduit $ src .| withShortAlphaIndex .| CL.consume output `shouldBe` [("A", 1), ("B", 2), ("C", 3)] - let modFlag ref cur next = do- prev <- I.atomicModifyIORef ref $ (,) next- prev `shouldBe` cur- flagShouldBe ref expect = do- cur <- I.readIORef ref- cur `shouldBe` expect- it "properly run the finalizer - When the main Conduit is fully consumed" $ do- called <- I.newIORef ("RawC" :: String)- let src :: MonadIO m => C.Source m String- src = CL.sourceList ["A", "B", "C"]- withIndex :: MonadIO m => C.Conduit String m (Integer, String)- withIndex = C.addCleanup (\f -> liftIO $ modFlag called "AllocC-3" ("FinalC:" ++ show f)) . CI.mergeSource $ do- liftIO $ modFlag called "RawC" "AllocC-1"- C.yield 1- liftIO $ modFlag called "AllocC-1" "AllocC-2"- C.yield 2- liftIO $ modFlag called "AllocC-2" "AllocC-3"- C.yield 3- liftIO $ modFlag called "AllocC-3" "AllocC-4"- C.yield 4- output <- src C.$= withIndex C.$$ CL.consume- output `shouldBe` [(1, "A"), (2, "B"), (3, "C")]- called `flagShouldBe` "FinalC:True"- it "properly run the finalizer - When the branch Source is fully consumed" $ do- called <- I.newIORef ("RawS" :: String)- let src :: MonadIO m => C.Source m Integer- src = CL.sourceList [1..]- withIndex :: MonadIO m => C.Conduit Integer m (String, Integer)- withIndex = C.addCleanup (\f -> liftIO $ modFlag called "AllocS-C" ("FinalS:" ++ show f)) . CI.mergeSource $ do- liftIO $ modFlag called "RawS" "AllocS-A"- C.yield "A"- liftIO $ modFlag called "AllocS-A" "AllocS-B"- C.yield "B"- liftIO $ modFlag called "AllocS-B" "AllocS-C"- C.yield "C"- output <- src C.$= withIndex C.$$ CL.consume- output `shouldBe` [("A", 1), ("B", 2), ("C", 3)]- called `flagShouldBe` "FinalS:True"- it "properly DO NOT run the finalizer - When nothing consumed" $ do- called <- I.newIORef ("Raw0" :: String)- let src :: MonadIO m => C.Source m String- src = CL.sourceList ["A", "B", "C"]- withIndex :: MonadIO m => C.Conduit String m (Integer, String)- withIndex = C.addCleanup (\f -> liftIO $ modFlag called "WONT CALLED" ("Final0:" ++ show f)) . CI.mergeSource $ do- liftIO $ modFlag called "Raw0" "Alloc0-1"- C.yield 1- output <- src C.$= withIndex C.$$ return ()- output `shouldBe` ()- called `flagShouldBe` "Raw0"- it "properly run the finalizer - When only one item consumed" $ do- called <- I.newIORef ("Raw1" :: String)- let src :: MonadIO m => C.Source m Integer- src = CL.sourceList [1..]- withIndex :: MonadIO m => C.Conduit Integer m (String, Integer)- withIndex = C.addCleanup (\f -> liftIO $ modFlag called "Alloc1-A" ("Final1:" ++ show f)) . CI.mergeSource $ do- liftIO $ modFlag called "Raw1" "Alloc1-A"- C.yield "A"- liftIO $ modFlag called "Alloc1-A" "Alloc1-B"- C.yield "B"- liftIO $ modFlag called "Alloc1-B" "Alloc1-C"- C.yield "C"- output <- src C.$= withIndex C.$= CL.isolate 1 C.$$ CL.consume- output `shouldBe` [("A", 1)]- called `flagShouldBe` "Final1:False"-- it "handles finalizers" $ do- ref <- I.newIORef (0 :: Int)- let src1 = C.addCleanup- (const $ I.modifyIORef ref (+1))- (mapM_ C.yield [1 :: Int ..])- src2 = mapM_ C.yield ("hi" :: String)- res1 <- src1 C.$$ C.mergeSource src2 C.=$ CL.consume- res1 `shouldBe` [('h', 1), ('i', 2)]- i1 <- I.readIORef ref- i1 `shouldBe` 1-- res2 <- src2 C.$$ C.mergeSource src1 C.=$ CL.consume- res2 `shouldBe` [(1, 'h'), (2, 'i')]- i2 <- I.readIORef ref- i2 `shouldBe` 2- 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 <- runConduit $ mapM_ C.yield input .| conduit .| CL.consume output `shouldBe` input x <- I.readIORef ref x `shouldBe` sum input@@ -851,7 +679,7 @@ let sink = CL.fold (+) (0 :: Int) conduit = C.passthroughSink sink (I.writeIORef ref) input = [undefined]- mapM_ C.yield input C.$$ conduit C.=$ return ()+ runConduit $ mapM_ C.yield input .| conduit .| return () x <- I.readIORef ref x `shouldBe` (-1) @@ -859,7 +687,7 @@ ref <- I.newIORef (-1 :: Int) let sink = CL.mapM_ (I.writeIORef ref) conduit = C.passthroughSink sink (const (return ()))- res <- mapM_ C.yield [1..] C.$$ conduit C.=$ CL.take 5+ res <- runConduit $ mapM_ C.yield [1..] .| conduit .| CL.take 5 res `shouldBe` [1..5] x <- I.readIORef ref x `shouldBe` 5@@ -876,131 +704,32 @@ lift $ return () C.yield 3 lift $ return ()- (src C.$$ CL.consume) `shouldBe` Right [1, 2, 4 :: Int]+ runConduit (src .| CL.consume) `shouldBe` Right [1, 2, 4 :: Int] describe "WriterT" $ it "pass" $ let writer = W.pass $ do W.tell [1 :: Int] pure ((), (2:))- in execWriter (C.runConduit writer) `shouldBe` [2, 1]-- describe "finalizers" $ do- it "promptness" $ do- imsgs <- I.newIORef []- let add x = liftIO $ do- msgs <- I.readIORef imsgs- I.writeIORef imsgs $ msgs ++ [x]- src' = C.bracketP- (add "acquire")- (const $ add "release")- (const $ C.addCleanup (const $ add "inside") (mapM_ C.yield [1..5]))- src = do- src' C.$= CL.isolate 4- add "computation"- sink = CL.mapM (\x -> add (show x) >> return x) C.=$ CL.consume-- res <- C.runResourceT $ src C.$$ sink-- msgs <- I.readIORef imsgs- -- FIXME this would be better msgs `shouldBe` words "acquire 1 2 3 4 inside release computation"- msgs `shouldBe` words "acquire 1 2 3 4 release inside computation"-- res `shouldBe` [1..4 :: Int]-- it "left associative" $ do- imsgs <- I.newIORef []- let add x = liftIO $ do- msgs <- I.readIORef imsgs- I.writeIORef imsgs $ msgs ++ [x]- p1 = C.bracketP (add "start1") (const $ add "stop1") (const $ add "inside1" >> C.yield ())- p2 = C.bracketP (add "start2") (const $ add "stop2") (const $ add "inside2" >> C.await >>= maybe (return ()) C.yield)- p3 = C.bracketP (add "start3") (const $ add "stop3") (const $ add "inside3" >> C.await)-- res <- C.runResourceT $ (p1 C.$= p2) C.$$ p3- res `shouldBe` Just ()-- msgs <- I.readIORef imsgs- msgs `shouldBe` words "start3 inside3 start2 inside2 start1 inside1 stop3 stop2 stop1"-- it "right associative" $ do- imsgs <- I.newIORef []- let add x = liftIO $ do- msgs <- I.readIORef imsgs- I.writeIORef imsgs $ msgs ++ [x]- p1 = C.bracketP (add "start1") (const $ add "stop1") (const $ add "inside1" >> C.yield ())- p2 = C.bracketP (add "start2") (const $ add "stop2") (const $ add "inside2" >> C.await >>= maybe (return ()) C.yield)- p3 = C.bracketP (add "start3") (const $ add "stop3") (const $ add "inside3" >> C.await)-- res <- C.runResourceT $ p1 C.$$ (p2 C.=$ p3)- res `shouldBe` Just ()-- msgs <- I.readIORef imsgs- msgs `shouldBe` words "start3 inside3 start2 inside2 start1 inside1 stop3 stop2 stop1"-- describe "dan burton's associative tests" $ do- let tellLn = tell . (++ "\n")- finallyP fin = CI.addCleanup (const fin)- printer = CI.awaitForever $ lift . tellLn . show- idMsg msg = finallyP (tellLn msg) CI.idP- takeP 0 = return ()- takeP n = CI.awaitE >>= \ex -> case ex of- Left _u -> return ()- Right i -> CI.yield i >> takeP (pred n)-- testPipe p = execWriter $ runPipe $ printer <+< p <+< CI.sourceList ([1..] :: [Int])-- p1 = takeP (1 :: Int)- p2 = idMsg "foo"- p3 = idMsg "bar"-- (<+<) = (CI.<+<)- runPipe = CI.runPipe-- test1L = testPipe $ (p1 <+< p2) <+< p3- test1R = testPipe $ p1 <+< (p2 <+< p3)-- _test2L = testPipe $ (p2 <+< p1) <+< p3- _test2R = testPipe $ p2 <+< (p1 <+< p3)-- test3L = testPipe $ (p2 <+< p3) <+< p1- test3R = testPipe $ p2 <+< (p3 <+< p1)-- verify testL testR p1' p2' p3'- | testL == testR = return () :: IO ()- | otherwise = error $ unlines- [ "FAILURE"- , ""- , "(" ++ p1' ++ " <+< " ++ p2' ++ ") <+< " ++ p3'- , "------------------"- , testL- , ""- , p1' ++ " <+< (" ++ p2' ++ " <+< " ++ p3' ++ ")"- , "------------------"- , testR- ]-- it "test1" $ verify test1L test1R "p1" "p2" "p3"- -- FIXME this is broken it "test2" $ verify test2L test2R "p2" "p1" "p3"- it "test3" $ verify test3L test3R "p2" "p3" "p1"+ in execWriter (runConduit writer) `shouldBe` [2, 1] describe "Data.Conduit.Lift" $ do it "execStateC" $ do let sink = C.execStateLC 0 $ CL.mapM_ $ modify . (+) src = mapM_ C.yield [1..10 :: Int]- res <- src C.$$ sink+ res <- runConduit $ src .| sink res `shouldBe` sum [1..10] it "execWriterC" $ do let sink = C.execWriterLC $ CL.mapM_ $ tell . return src = mapM_ C.yield [1..10 :: Int]- res <- src C.$$ sink+ res <- runConduit $ src .| sink res `shouldBe` [1..10] - it "runErrorC" $ do- let sink = C.runErrorC $ do- x <- C.catchErrorC (lift $ throwError "foo") return+ it "runExceptC" $ do+ let sink = C.runExceptC $ do+ x <- C.catchExceptC (lift $ throwError "foo") return return $ x ++ "bar"- res <- return () C.$$ sink+ res <- runConduit $ return () .| sink res `shouldBe` Right ("foobar" :: String) it "runMaybeC" $ do@@ -1009,7 +738,7 @@ () <- lift $ MaybeT $ return Nothing C.yield 2 sink = CL.consume- res <- src C.$$ sink+ res <- runConduit $ src .| sink res `shouldBe` [1 :: Int] describe "sequenceSources" $ do@@ -1022,7 +751,7 @@ , (2, src2) , (3, src3) ]- res <- srcs C.$$ CL.consume+ res <- runConduit $ srcs .| CL.consume res `shouldBe` [ Map.fromList [(1, 1), (2, 3), (3, 2)] , Map.fromList [(1, 2), (2, 2), (3, 2)]@@ -1030,8 +759,8 @@ ] describe "zipSink" $ do it "zip equal-sized" $ do- x <- runResourceT $- CL.sourceList [1..100] C.$$+ x <- runConduitRes $+ CL.sourceList [1..100] .| C.sequenceSinks [ CL.fold (+) 0, (`mod` 101) <$> CL.fold (*) 1 ] x `shouldBe` [5050, 100 :: Integer]@@ -1040,16 +769,16 @@ let sink = C.getZipSink $ (*) <$> C.ZipSink (CL.fold (+) 0) <*> C.ZipSink (Data.Maybe.fromJust <$> C.await)- x <- C.runResourceT $ CL.sourceList [100,99..1] C.$$ sink+ x <- runConduitRes $ CL.sourceList [100,99..1] .| sink x `shouldBe` (505000 :: Integer) describe "upstream results" $ do it "fuseBoth" $ do let upstream = do C.yield ("hello" :: String)- CL.isolate 5 C.=$= CL.fold (+) 0+ CL.isolate 5 .| CL.fold (+) 0 downstream = C.fuseBoth upstream CL.consume- res <- CL.sourceList [1..10 :: Int] C.$$ do+ res <- runConduit $ CL.sourceList [1..10 :: Int] .| do (x, y) <- downstream z <- CL.consume return (x, y, z)@@ -1057,22 +786,22 @@ it "fuseBothMaybe with no result" $ do let src = mapM_ C.yield [1 :: Int ..]- sink = CL.isolate 5 C.=$= CL.fold (+) 0- (mup, down) <- C.runConduit $ C.fuseBothMaybe src sink+ sink = CL.isolate 5 .| CL.fold (+) 0+ (mup, down) <- runConduit $ C.fuseBothMaybe src sink mup `shouldBe` (Nothing :: Maybe ()) down `shouldBe` sum [1..5] it "fuseBothMaybe with result" $ do let src = mapM_ C.yield [1 :: Int .. 5]- sink = CL.isolate 6 C.=$= CL.fold (+) 0- (mup, down) <- C.runConduit $ C.fuseBothMaybe src sink+ sink = CL.isolate 6 .| CL.fold (+) 0+ (mup, down) <- runConduit $ C.fuseBothMaybe src sink mup `shouldBe` Just () down `shouldBe` sum [1..5] it "fuseBothMaybe with almost result" $ do let src = mapM_ C.yield [1 :: Int .. 5]- sink = CL.isolate 5 C.=$= CL.fold (+) 0- (mup, down) <- C.runConduit $ C.fuseBothMaybe src sink+ sink = CL.isolate 5 .| CL.fold (+) 0+ (mup, down) <- runConduit $ C.fuseBothMaybe src sink mup `shouldBe` (Nothing :: Maybe ()) down `shouldBe` sum [1..5] @@ -1083,8 +812,8 @@ () <- Catch.throwM DummyError C.yield 2 src' = do- Catch.catch src (\DummyError -> C.yield (3 :: Int))- res <- src' C.$$ CL.consume+ CI.catchC src (\DummyError -> C.yield (3 :: Int))+ res <- runConduit $ src' .| CL.consume res `shouldBe` [1, 3] describe "sourceToList" $ do@@ -1104,5 +833,4 @@ data DummyError = DummyError deriving (Show, Eq, Typeable)-instance Error DummyError instance Catch.Exception DummyError
+ test/subdir/dummyfile.txt view