packages feed

conduit-combinators 0.2.0.1 → 0.2.1

raw patch · 5 files changed

+256/−3 lines, 5 filesdep +mwc-randomdep +void

Dependencies added: mwc-random, void

Files

Data/Conduit/Combinators.hs view
@@ -39,6 +39,12 @@     , sourceIOHandle     , stdin +      -- ** Random numbers+    , sourceRandom+    , sourceRandomN+    , sourceRandomGen+    , sourceRandomNGen+       -- * Consumers       -- ** Pure     , drop@@ -78,6 +84,8 @@     , lastE     , length     , lengthE+    , lengthIf+    , lengthIfE     , maximum     , maximumE     , minimum@@ -160,7 +168,7 @@ import           Control.Monad               (unless, when, (>=>), liftM, forever) import           Control.Monad.Base          (MonadBase (liftBase)) import           Control.Monad.IO.Class      (MonadIO (..))-import           Control.Monad.Primitive     (PrimMonad)+import           Control.Monad.Primitive     (PrimMonad, PrimState) import           Control.Monad.Trans.Class   (lift) import           Data.Conduit import qualified Data.Conduit.List           as CL@@ -185,6 +193,8 @@ import qualified Data.Conduit.Text as CT import Data.ByteString (ByteString) import Data.Text (Text)+import qualified System.Random.MWC as MWC+import Data.Conduit.Combinators.Internal  -- END IMPORTS @@ -340,6 +350,45 @@ stdin :: (MonadIO m, IOData a) => Producer m a stdin = sourceHandle SIO.stdin +-- | Create an infinite stream of random values, seeding from the system random+-- number.+--+-- Since 1.0.0+sourceRandom :: (MWC.Variate a, MonadIO m) => Producer m a+sourceRandom = initRepeat (liftIO MWC.createSystemRandom) (liftIO . MWC.uniform)+{-# INLINE sourceRandom #-}++-- | Create a stream of random values of length n, seeding from the system+-- random number.+--+-- Since 1.0.0+sourceRandomN :: (MWC.Variate a, MonadIO m)+              => Int -- ^ count+              -> Producer m a+sourceRandomN = initReplicate (liftIO MWC.createSystemRandom) (liftIO . MWC.uniform)+{-# INLINE [0] sourceRandomN #-}++-- | Create an infinite stream of random values, using the given random number+-- generator.+--+-- Since 1.0.0+sourceRandomGen :: (MWC.Variate a, MonadBase base m, PrimMonad base)+                => MWC.Gen (PrimState base)+                -> Producer m a+sourceRandomGen gen = initRepeat (return gen) (liftBase . MWC.uniform)+{-# INLINE sourceRandomGen #-}++-- | Create a stream of random values of length n, seeding from the system+-- random number.+--+-- Since 1.0.0+sourceRandomNGen :: (MWC.Variate a, MonadBase base m, PrimMonad base)+                 => MWC.Gen (PrimState base)+                 -> Int -- ^ count+                 -> Producer m a+sourceRandomNGen gen = initReplicate (return gen) (liftBase . MWC.uniform)+{-# INLINE sourceRandomNGen #-}+ -- | Ignore a certain number of values in the stream. -- -- Since 1.0.0@@ -774,6 +823,21 @@ lengthE :: (Monad m, Num len, MonoFoldable mono) => Consumer mono m len lengthE = foldl (\x y -> x + fromIntegral (olength y)) 0 {-# INLINE lengthE #-}++-- | Count how many values in the stream pass the given predicate.+--+-- Since 1.0.0+lengthIf :: (Monad m, Num len) => (a -> Bool) -> Consumer a m len+lengthIf f = foldl (\cnt a -> if f a then (cnt + 1) else cnt) 0+{-# INLINE lengthIf #-}++-- | Count how many elements in the chunked stream pass the given predicate.+--+-- Since 1.0.0+lengthIfE :: (Monad m, Num len, MonoFoldable mono)+          => (Element mono -> Bool) -> Consumer mono m len+lengthIfE f = foldlE (\cnt a -> if f a then (cnt + 1) else cnt) 0+{-# INLINE lengthIfE #-}  -- | Get the largest value in the stream, if present. --
+ Data/Conduit/Combinators/Internal.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE RankNTypes #-}+-- | Internal helper functions, usually used for rewrite rules.+module Data.Conduit.Combinators.Internal+    ( initReplicate+    , initReplicateConnect+    , initRepeat+    , initRepeatConnect+    ) where++import Data.Conduit+import Data.Conduit.Internal (ConduitM (..), Pipe (..), injectLeftovers)+import Data.Void (absurd)+import Control.Monad.Trans.Class (lift)+import Control.Monad (replicateM_, forever)++-- | Acquire the seed value and perform the given action with it n times,+-- yielding each result.+--+-- Since 0.2.1+initReplicate :: Monad m => m seed -> (seed -> m a) -> Int -> Producer m a+initReplicate mseed f cnt = do+    seed <- lift mseed+    replicateM_ cnt (lift (f seed) >>= yield)+{-# INLINE [1] initReplicate #-}++-- | Optimized version of initReplicate for the special case of connecting with+-- a @Sink@.+--+-- Since 0.2.1+initReplicateConnect :: Monad m+                     => m seed+                     -> (seed -> m a)+                     -> Int+                     -> Sink a m b+                     -> m b+initReplicateConnect mseed f cnt0 (ConduitM sink0) = do+    seed <- mseed+    let loop cnt sink | cnt <= 0 = finish sink+        loop _ (Done r) = return r+        loop cnt (NeedInput p _) = f seed >>= loop (pred cnt) . p+        loop _ (HaveOutput _ _ o) = absurd o+        loop cnt (PipeM mp) = mp >>= loop cnt+        loop _ (Leftover _ i) = absurd i++    loop cnt0 (injectLeftovers sink0)+  where+    finish (Done r) = return r+    finish (HaveOutput _ _ o) = absurd o+    finish (NeedInput _ p) = finish (p ())+    finish (PipeM mp) = mp >>= finish+    finish (Leftover _ i) = absurd i+{-# RULES "initReplicateConnect" forall mseed f cnt sink.+    initReplicate mseed f cnt $$ sink+    = initReplicateConnect mseed f cnt sink+  #-}++-- | Acquire the seed value and perform the given action with it forever,+-- yielding each result.+--+-- Since 0.2.1+initRepeat :: Monad m => m seed -> (seed -> m a) -> Producer m a+initRepeat mseed f = do+    seed <- lift mseed+    forever $ lift (f seed) >>= yield++-- | Optimized version of initRepeat for the special case of connecting with+-- a @Sink@.+--+-- Since 0.2.1+initRepeatConnect :: Monad m+                  => m seed+                  -> (seed -> m a)+                  -> Sink a m b+                  -> m b+initRepeatConnect mseed f (ConduitM sink0) = do+    seed <- mseed+    let loop (Done r) = return r+        loop (NeedInput p _) = f seed >>= loop . p+        loop (HaveOutput _ _ o) = absurd o+        loop (PipeM mp) = mp >>= loop+        loop (Leftover _ i) = absurd i++    loop (injectLeftovers sink0)+{-# RULES "initRepeatConnect" forall mseed f sink.+    initRepeat mseed f $$ sink+    = initRepeatConnect mseed f sink+  #-}
Data/Conduit/Combinators/Unqualified.hs view
@@ -28,6 +28,12 @@     , sourceIOHandle     , stdinC +      -- *** Random numbers+    , sourceRandom+    , sourceRandomN+    , sourceRandomGen+    , sourceRandomNGen+       -- ** Consumers       -- *** Pure     , dropC@@ -67,6 +73,8 @@     , lastCE     , lengthC     , lengthCE+    , lengthIfC+    , lengthIfCE     , maximumC     , maximumCE     , minimumC@@ -152,7 +160,7 @@ import           Control.Monad               (unless, when, (>=>), liftM, forever) import           Control.Monad.Base          (MonadBase (liftBase)) import           Control.Monad.IO.Class      (MonadIO (..))-import           Control.Monad.Primitive     (PrimMonad)+import           Control.Monad.Primitive     (PrimMonad, PrimState) import           Control.Monad.Trans.Class   (lift) import           Data.Conduit import qualified Data.Conduit.List           as CL@@ -177,6 +185,8 @@ import qualified Data.Conduit.Text as CT import Data.ByteString (ByteString) import Data.Text (Text)+import qualified System.Random.MWC as MWC+import Data.Conduit.Combinators.Internal   -- END IMPORTS@@ -314,6 +324,45 @@ stdinC = CC.stdin {-# INLINE stdinC #-} +-- | Create an infinite stream of random values, seeding from the system random+-- number.+--+-- Since 1.0.0+sourceRandom :: (MWC.Variate a, MonadIO m) => Producer m a+sourceRandom = CC.sourceRandom+{-# INLINE sourceRandom #-}++-- | Create a stream of random values of length n, seeding from the system+-- random number.+--+-- Since 1.0.0+sourceRandomN :: (MWC.Variate a, MonadIO m)+              => Int -- ^ count+              -> Producer m a+sourceRandomN = CC.sourceRandomN+{-# INLINE sourceRandomN #-}++-- | Create an infinite stream of random values, using the given random number+-- generator.+--+-- Since 1.0.0+sourceRandomGen :: (MWC.Variate a, MonadBase base m, PrimMonad base)+                => MWC.Gen (PrimState base)+                -> Producer m a+sourceRandomGen = CC.sourceRandomGen+{-# INLINE sourceRandomGen #-}++-- | Create a stream of random values of length n, seeding from the system+-- random number.+--+-- Since 1.0.0+sourceRandomNGen :: (MWC.Variate a, MonadBase base m, PrimMonad base)+                 => MWC.Gen (PrimState base)+                 -> Int -- ^ count+                 -> Producer m a+sourceRandomNGen = CC.sourceRandomNGen+{-# INLINE sourceRandomNGen #-}+ -- | Ignore a certain number of values in the stream. -- -- Since 1.0.0@@ -662,6 +711,21 @@ lengthCE :: (Monad m, Num len, MonoFoldable mono) => Consumer mono m len lengthCE = CC.lengthE {-# INLINE lengthCE #-}++-- | Count how many values in the stream pass the given predicate.+--+-- Since 1.0.0+lengthIfC :: (Monad m, Num len) => (a -> Bool) -> Consumer a m len+lengthIfC = CC.lengthIf+{-# INLINE lengthIfC #-}++-- | Count how many elements in the chunked stream pass the given predicate.+--+-- Since 1.0.0+lengthIfCE :: (Monad m, Num len, MonoFoldable mono)+          => (Element mono -> Bool) -> Consumer mono m len+lengthIfCE = CC.lengthIfE+{-# INLINE lengthIfCE #-}  -- | Get the largest value in the stream, if present. --
conduit-combinators.cabal view
@@ -1,5 +1,5 @@ name:                conduit-combinators-version:             0.2.0.1+version:             0.2.1 synopsis:            Commonly used conduit functions, for both chunked and unchunked data description:         Provides a replacement for Data.Conduit.List, as well as a convenient Conduit module. homepage:            https://github.com/fpco/conduit-combinators@@ -14,6 +14,7 @@ library   exposed-modules:     Conduit                        Data.Conduit.Combinators+                       Data.Conduit.Combinators.Internal   other-modules:       Data.Conduit.Combinators.Unqualified   build-depends:       base >= 4 && < 5                      , chunked-data@@ -27,6 +28,8 @@                      , system-filepath                      , text                      , bytestring+                     , void+                     , mwc-random  test-suite test   hs-source-dirs: test@@ -44,6 +47,7 @@                 , mono-traversable                 , silently                 , bytestring+                , mwc-random   ghc-options:    -Wall  source-repository head
test/Spec.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-type-defaults #-} import Conduit+import Data.Conduit.Combinators.Internal import Test.Hspec import Test.Hspec.QuickCheck import BasicPrelude hiding (encodeUtf8)@@ -23,6 +24,7 @@ import GHC.IO.Handle (hDuplicateTo) import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8+import System.Random.MWC (createSystemRandom)  main :: IO () main = hspec $ do@@ -107,6 +109,20 @@             hDuplicateTo h IO.stdin             x <- stdinC $$ foldC             x `shouldBe` content+    it "sourceRandom" $ do+        x <- sourceRandom $$ takeC 100 =$ sumC :: IO Double+        x `shouldSatisfy` (\y -> y > 10 && y < 90)+    it "sourceRandomN" $ do+        x <- sourceRandomN 100 $$ sumC :: IO Double+        x `shouldSatisfy` (\y -> y > 10 && y < 90)+    it "sourceRandomGen" $ do+        gen <- createSystemRandom+        x <- sourceRandomGen gen $$ takeC 100 =$ sumC :: IO Double+        x `shouldSatisfy` (\y -> y > 10 && y < 90)+    it "sourceRandomNGen" $ do+        gen <- createSystemRandom+        x <- sourceRandomNGen gen 100 $$ sumC :: IO Double+        x `shouldSatisfy` (\y -> y > 10 && y < 90)     prop "drop" $ \(T.pack -> input) count ->         runIdentity (yieldMany input $$ (dropC count >>= \() -> sinkList))         `shouldBe` T.unpack (T.drop count input)@@ -215,6 +231,12 @@     prop "lengthE" $ \xs ->         runIdentity (yieldMany xs $$ lengthCE)         `shouldBe` length (concat xs :: [Int])+    prop "lengthIf" $ \x xs ->+        runIdentity (yieldMany xs $$ lengthIfC (< x))+        `shouldBe` length (filter (< x) xs :: [Int])+    prop "lengthIfE" $ \x xs ->+        runIdentity (yieldMany xs $$ lengthIfCE (< x))+        `shouldBe` length (filter (< x) (concat xs) :: [Int])     prop "maximum" $ \xs ->         runIdentity (yieldMany xs $$ maximumC)         `shouldBe` (if null (xs :: [Int]) then Nothing else Just (maximum xs))@@ -491,6 +513,18 @@     prop "linesUnboundedAscii" $ \(map S.pack -> input) ->         runIdentity (yieldMany input $$ (linesUnboundedAsciiC >>= \() -> mempty) =$ sinkList)         `shouldBe` S8.lines (S.concat input)+    prop "initReplicate" $ \seed delta (min 50 . abs -> cnt) -> do+        let sink = sumC+        res1 <- initReplicate (return seed) (return . (+ delta)) cnt $$ sink+        res1 `shouldBe` cnt * (seed + delta)+        res2 <- initReplicateConnect (return seed) (return . (+ delta)) cnt sink+        res2 `shouldBe` res1+    prop "initReplicate" $ \seed delta (min 50 . abs -> cnt) -> do+        let sink = takeC cnt =$ sumC+        res1 <- initRepeat (return seed) (return . (+ delta)) $$ sink+        res1 `shouldBe` cnt * (seed + delta)+        res2 <- initRepeatConnect (return seed) (return . (+ delta)) sink+        res2 `shouldBe` res1  evenInt :: Int -> Bool evenInt = even