conduit 1.3.2.1 → 1.3.3
raw patch · 7 files changed
+135/−5 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Conduit.Internal: unconsEitherM :: Monad m => Pipe Void () o () m r -> m (Either r (o, Pipe Void () o () m r))
+ Data.Conduit.Internal: unconsM :: Monad m => Pipe Void () o () m () -> m (Maybe (o, Pipe Void () o () m ()))
+ Data.Conduit.List: uncons :: SealedConduitT () o Identity () -> Maybe (o, SealedConduitT () o Identity ())
+ Data.Conduit.List: unconsEither :: SealedConduitT () o Identity r -> Either r (o, SealedConduitT () o Identity r)
+ Data.Conduit.List: unconsEitherM :: Monad m => SealedConduitT () o m r -> m (Either r (o, SealedConduitT () o m r))
+ Data.Conduit.List: unconsM :: Monad m => SealedConduitT () o m () -> m (Maybe (o, SealedConduitT () o m ()))
Files
- ChangeLog.md +4/−0
- conduit.cabal +1/−1
- src/Data/Conduit/Internal.hs +2/−1
- src/Data/Conduit/Internal/Conduit.hs +37/−1
- src/Data/Conduit/Internal/Pipe.hs +30/−0
- src/Data/Conduit/List.hs +28/−2
- test/main.hs +33/−0
ChangeLog.md view
@@ -1,5 +1,9 @@ # ChangeLog for conduit +## 1.3.3++* Add `uncons`, `unconsM`, `unconsEither`, `unconsEitherM`.+ ## 1.3.2.1 * Fix isChunksForExactlyE [#445](https://github.com/snoyberg/conduit/issues/445) [#446](https://github.com/snoyberg/conduit/pull/446)
conduit.cabal view
@@ -1,5 +1,5 @@ Name: conduit-Version: 1.3.2.1+Version: 1.3.3 Synopsis: Streaming data processing library. description: `conduit` is a solution to the streaming data problem, allowing for production,
src/Data/Conduit/Internal.hs view
@@ -14,6 +14,7 @@ leftover, mapInput, mapInputM, mapOutput, mapOutputMaybe, transPipe,- yield, yieldM)+ yield, yieldM,+ unconsM, unconsEitherM) import Data.Conduit.Internal.Pipe import Data.Conduit.Internal.Fusion
src/Data/Conduit/Internal/Conduit.hs view
@@ -38,6 +38,8 @@ , runConduitRes , fuse , connect+ , unconsM+ , unconsEitherM -- ** Composition , connectResume , connectResumeConduit@@ -106,7 +108,7 @@ 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 Data.Conduit.Internal.Pipe hiding (yield, mapOutput, leftover, yieldM, await, awaitForever, bracketP, unconsM, unconsEitherM) import qualified Data.Conduit.Internal.Pipe as CI import Control.Monad (forever) import Data.Traversable (Traversable (..))@@ -719,6 +721,40 @@ -> ConduitT a Void m r -> m r connect = ($$)++-- | Split a conduit into head and tail.+--+-- Note that you have to 'sealConduitT' it first.+--+-- Since 1.3.3+unconsM :: Monad m+ => SealedConduitT () o m ()+ -> m (Maybe (o, SealedConduitT () o m ()))+unconsM (SealedConduitT p) = go p+ where+ -- This function is the same as @Pipe.unconsM@ but it ignores leftovers.+ go (HaveOutput p o) = pure $ Just (o, SealedConduitT p)+ go (NeedInput _ c) = go $ c ()+ go (Done ()) = pure Nothing+ go (PipeM mp) = mp >>= go+ go (Leftover p ()) = go p++-- | Split a conduit into head and tail or return its result if it is done.+--+-- Note that you have to 'sealConduitT' it first.+--+-- Since 1.3.3+unconsEitherM :: Monad m+ => SealedConduitT () o m r+ -> m (Either r (o, SealedConduitT () o m r))+unconsEitherM (SealedConduitT p) = go p+ where+ -- This function is the same as @Pipe.unconsEitherM@ but it ignores leftovers.+ go (HaveOutput p o) = pure $ Right (o, SealedConduitT p)+ go (NeedInput _ c) = go $ c ()+ go (Done r) = pure $ Left r+ go (PipeM mp) = mp >>= go+ go (Leftover p ()) = go p -- | Named function synonym for '.|' --
src/Data/Conduit/Internal/Pipe.hs view
@@ -18,6 +18,8 @@ , yield , yieldM , leftover+ , unconsM+ , unconsEitherM -- ** Finalization , bracketP -- ** Composition@@ -270,6 +272,34 @@ 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 #-}++-- | Split a pipe into head and tail.+--+-- Since 1.3.3+unconsM :: Monad m+ => Pipe Void () o () m ()+ -> m (Maybe (o, Pipe Void () o () m ()))+unconsM = go+ where+ go (HaveOutput p o) = pure $ Just (o, p)+ go (NeedInput _ c) = go $ c ()+ go (Done ()) = pure Nothing+ go (PipeM mp) = mp >>= go+ go (Leftover _ i) = absurd i++-- | Split a pipe into head and tail or return its result if it is done.+--+-- Since 1.3.3+unconsEitherM :: Monad m+ => Pipe Void () o () m r+ -> m (Either r (o, Pipe Void () o () m r))+unconsEitherM = go+ where+ go (HaveOutput p o) = pure $ Right (o, p)+ go (NeedInput _ c) = go $ c ()+ go (Done r) = pure $ Left r+ go (PipeM mp) = mp >>= go+ go (Leftover _ i) = absurd i -- | Bracket a pipe computation between allocation and release of a resource. -- We guarantee, via the @MonadResource@ context, that the resource
src/Data/Conduit/List.hs view
@@ -15,8 +15,8 @@ -- 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.+-- respectively). See the @Data.Conduit.Binary@ and @Data.Conduit.Text@+-- modules in the @conduit-extra@ package. module Data.Conduit.List ( -- * Sources sourceList@@ -33,6 +33,8 @@ -- ** Pure , fold , foldMap+ , uncons+ , unconsEither , take , drop , head@@ -42,6 +44,8 @@ -- ** Monadic , foldMapM , foldM+ , unconsM+ , unconsEitherM , mapM_ -- * Conduits -- ** Pure@@ -95,9 +99,11 @@ import Data.Monoid (Monoid, mempty, mappend) import qualified Data.Foldable as F import Data.Conduit+import Data.Conduit.Internal.Conduit (unconsM, unconsEitherM) import Data.Conduit.Internal.Fusion import Data.Conduit.Internal.List.Stream import qualified Data.Conduit.Internal as CI+import Data.Functor.Identity (Identity (runIdentity)) import Control.Monad (when, (<=<), liftM, void) import Control.Monad.Trans.Class (lift) @@ -179,6 +185,26 @@ Right (a, seed') -> yield a >> go seed' Left r -> return r STREAMING(unfoldEitherM, unfoldEitherMC, unfoldEitherMS, f seed)++-- | Split a pure conduit into head and tail.+-- This is equivalent to @runIdentity . unconsM@.+--+-- Note that you have to 'sealConduitT' it first.+--+-- Since 1.3.3+uncons :: SealedConduitT () o Identity ()+ -> Maybe (o, SealedConduitT () o Identity ())+uncons = runIdentity . unconsM++-- | Split a pure conduit into head and tail or return its result if it is done.+-- This is equivalent to @runIdentity . unconsEitherM@.+--+-- Note that you have to 'sealConduitT' it first.+--+-- Since 1.3.3+unconsEither :: SealedConduitT () o Identity r+ -> Either r (o, SealedConduitT () o Identity r)+unconsEither = runIdentity . unconsEitherM -- | Yield the values from the list. --
test/main.hs view
@@ -24,6 +24,7 @@ import Control.Monad.ST (runST) import Data.Monoid import qualified Data.IORef as I+import Data.Tuple (swap) import Control.Monad.Trans.Resource (allocate, resourceForkIO) import Control.Concurrent (threadDelay, killThread) import Control.Monad.IO.Class (liftIO)@@ -52,7 +53,17 @@ equivToList f conduit xs = f xs == runConduitPure (CL.sourceList xs .| conduit .| CL.consume) +-- | Check that two conduits produce the same outputs and return the same result.+bisimilarTo :: (Eq a, Eq r) => ConduitT () a Identity r -> ConduitT () a Identity r -> Bool+left `bisimilarTo` right =+ C.runConduitPure (toListRes left) == C.runConduitPure (toListRes right)+ where+ -- | Sink a conduit into a list and return it alongside the result.+ -- So it is, essentially, @sinkList@ plus result.+ toListRes :: Monad m => ConduitT () a m r -> ConduitT () Void m ([a], r)+ toListRes cond = swap <$> C.fuseBoth cond CL.consume + main :: IO () main = hspec $ do describe "Combinators" Spec.spec@@ -165,6 +176,28 @@ x <- runConduit $ CL.unfoldM (return . f) seed .| CL.consume let y = DL.unfoldr f seed x `shouldBe` y++ describe "uncons" $ do+ prop "folds to list" $ \xs ->+ let src = C.sealConduitT $ CL.sourceList xs in+ (xs :: [Int]) == DL.unfoldr CL.uncons src++ prop "works with unfold" $ \xs ->+ let src = CL.sourceList xs in+ CL.unfold CL.uncons (C.sealConduitT src) `bisimilarTo` (src :: ConduitT () Int Identity ())++ describe "unconsEither" $ do+ let+ eitherToMaybe :: Either l a -> Maybe a+ eitherToMaybe (Left _) = Nothing+ eitherToMaybe (Right a) = Just a+ prop "folds outputs to list" $ \xs ->+ let src = C.sealConduitT $ CL.sourceList xs in+ (xs :: [Int]) == DL.unfoldr (eitherToMaybe . CL.unconsEither) src++ prop "works with unfoldEither" $ \(xs, r) ->+ let src = CL.sourceList xs *> pure r in+ CL.unfoldEither CL.unconsEither (C.sealConduitT src) `bisimilarTo` (src :: ConduitT () Int Identity Int) describe "Monoid instance for Source" $ do it "mappend" $ do