packages feed

streaming-bytestring 0.1.4.4 → 0.1.4.5

raw patch · 5 files changed

+253/−85 lines, 5 filesdep +smallcheckdep +streaming-bytestringdep +tastydep ~basedep ~bytestringdep ~streaming

Dependencies added: smallcheck, streaming-bytestring, tasty, tasty-smallcheck

Dependency ranges changed: base, bytestring, streaming, transformers

Files

Data/ByteString/Streaming.hs view
@@ -84,20 +84,13 @@     , uncons           -- uncons :: Monad m => ByteString m r -> m (Either r (Word8, ByteString m r))      , nextByte -- nextByte :: Monad m => ByteString m r -> m (Either r (Word8, ByteString m r))     , denull-   -    -- * Direct chunk handling -    , unconsChunk-    , nextChunk        -- nextChunk :: Monad m => ByteString m r -> m (Either r (ByteString, ByteString m r)) -    , consChunk-    , chunk-    , foldrChunks-    , foldlChunks          -- * Substrings      -- ** Breaking strings     , break            -- break :: Monad m => (Word8 -> Bool) -> ByteString m r -> ByteString m (ByteString m r)      , drop             -- drop :: Monad m => GHC.Int.Int64 -> ByteString m r -> ByteString m r +    , dropWhile      , group            -- group :: Monad m => ByteString m r -> Stream (ByteString m) m r      , groupBy     , span             -- span :: Monad m => (Word8 -> Bool) -> ByteString m r -> ByteString m (ByteString m r) @@ -130,11 +123,13 @@     -- ** Unfolding ByteStrings     , unfoldM          -- unfoldr :: (a -> m (Maybe (Word8, a))) -> m a -> ByteString m ()      , unfoldr          -- unfold  :: (a -> Either r (Word8, a)) -> a -> ByteString m r-+    , reread+         -- *  Folds, including support for `Control.Foldl`     , foldr            -- foldr :: Monad m => (Word8 -> a -> a) -> a -> ByteString m () -> m a      , fold             -- fold :: Monad m => (x -> Word8 -> x) -> x -> (x -> b) -> ByteString m () -> m b      , fold_            -- fold' :: Monad m => (x -> Word8 -> x) -> x -> (x -> b) -> ByteString m r -> m (b, r) +         , head     , head_     , last@@ -173,6 +168,17 @@     -- * Etc.     , zipWithStream    -- zipWithStream :: Monad m => (forall x. a -> ByteString m x -> ByteString m x) -> [a] -> Stream (ByteString m) m r -> Stream (ByteString m) m r  +    -- * Simple chunkwise operations +    , unconsChunk+    , nextChunk    +    , chunk+    , foldrChunks+    , foldlChunks+    , chunkFold+    , chunkFoldM+    , chunkMap+    , chunkMapM+    , chunkMapM_   ) where  import Prelude hiding@@ -533,14 +539,14 @@   return r {-# INLINE snoc #-} --- | /O(1)/ Extract the first element of a ByteString, which must be non-empty.+-- | /O(1)/ Extract the first element of a 'ByteString', which must be non-empty. head_ :: Monad m => ByteString m r -> m Word8 head_ (Empty _)   = error "head" head_ (Chunk c _) = return $ S.unsafeHead c head_ (Go m)      = m >>= head_ {-# INLINE head_ #-} --- | /O(c)/ Extract the first element of a ByteString, which must be non-empty.+-- | /O(c)/ Extract the first element of a 'ByteString', which must be non-empty. head :: Monad m => ByteString m r -> m (Of (Maybe Word8) r) head (Empty r)  = return (Nothing :> r) head (Chunk c rest) = case S.uncons c of @@ -551,7 +557,7 @@ head (Go m)      = m >>= head {-# INLINE head #-} --- | /O(1)/ Extract the head and tail of a ByteString, or Nothing+-- | /O(1)/ Extract the head and tail of a 'ByteString', or 'Nothing' -- if it is empty uncons :: Monad m => ByteString m r -> m (Maybe (Word8, ByteString m r)) uncons (Empty _) = return Nothing@@ -563,7 +569,7 @@ uncons (Go m) = m >>= uncons {-# INLINABLE uncons #-} ----- | /O(1)/ Extract the head and tail of a ByteString, or its return value+-- | /O(1)/ Extract the head and tail of a 'ByteString', or its return value -- if it is empty. This is the \'natural\' uncons for an effectful byte stream. nextByte :: Monad m => ByteString m r -> m (Either r (Word8, ByteString m r)) nextByte (Empty r) = return (Left r)@@ -593,7 +599,7 @@   Go m       -> m >>= nextChunk {-# INLINABLE nextChunk #-} --- | /O(n\/c)/ Extract the last element of a ByteString, which must be finite+-- | /O(n\/c)/ Extract the last element of a 'ByteString', which must be finite -- and non-empty. last_ :: Monad m => ByteString m r -> m Word8 last_ (Empty _)      = error "Data.ByteString.Streaming.last: empty string"@@ -690,12 +696,12 @@            {-# INLINABLE intersperse #-} -{- | 'foldr', applied to a binary operator, a starting value+-- | 'foldr', applied to a binary operator, a starting value -- (typically the right-identity of the operator), and a ByteString, -- reduces the ByteString using the binary operator, from right to left.--> foldr cons = id--}+--+-- > foldr cons = id+-- foldr :: Monad m => (Word8 -> a -> a) -> a -> ByteString m () -> m a foldr k  = foldrChunks (flip (S.foldr k)) {-# INLINE foldr #-}@@ -715,7 +721,7 @@ {-# INLINABLE fold #-}  --- | 'fold\'' keeps the return value of the left-folded bytestring. Useful for+-- | 'fold_' keeps the return value of the left-folded bytestring. Useful for --   simultaneous folds over a segmented bytestream  fold_ :: Monad m => (x -> Word8 -> x) -> x -> (x -> b) -> ByteString m r -> m (Of b r)@@ -907,10 +913,10 @@ cycle = forever {-# INLINE cycle #-} --- | /O(n)/ The 'unfoldr' function is analogous to the Stream \'unfoldr\'.+-- | /O(n)/ The 'unfoldr' function is analogous to the Stream @unfoldr@. -- 'unfoldr' builds a ByteString from a seed value.  The function takes -- the element and returns 'Nothing' if it is done producing the--- ByteString or returns 'Just' @(a,b)@, in which case, @a@ is a+-- ByteString or returns @'Just' (a,b)@, in which case, @a@ is a -- prepending to the ByteString and @b@ is used as the next element in a -- recursive call. @@ -925,8 +931,8 @@ {-# INLINABLE unfoldM #-}  -- | 'unfold' is like 'unfoldr' but stops when the co-algebra --- returns 'Left'; the result is the return value of the 'ByteString m r'--- 'unfoldr uncons = id'+-- returns 'Left'; the result is the return value of the @ByteString m r@+-- @unfoldr uncons = id@ unfoldr :: (a -> Either r (Word8, a)) -> a -> ByteString m r unfoldr f s0 = unfoldChunk 32 s0   where unfoldChunk n s =@@ -1027,14 +1033,17 @@           | otherwise      -> Chunk c (takeWhile' cs) {-# INLINABLE takeWhile #-} --- -- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@.--- dropWhile :: (Word8 -> Bool) -> ByteString -> ByteString--- dropWhile f cs0 = dropWhile' cs0---   where dropWhile' Empty        = Empty---         dropWhile' (Chunk c cs) =---           case findIndexOrEnd (not . f) c of---             n | n < S.length c -> Chunk (S.drop n c) cs---               | otherwise      -> dropWhile' cs+-- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@.+dropWhile :: Monad m => (Word8 -> Bool) -> ByteString m r -> ByteString m r+dropWhile pred = drop' where +  drop' bs = case bs of +    Empty r    -> Empty r+    Go m       -> Go (liftM drop' m) +    Chunk c cs -> case findIndexOrEnd (not.pred) c of+        0                  -> Chunk c cs+        n | n < S.length c -> Chunk (S.drop n c) cs+          | otherwise      -> drop' cs+{-#INLINABLE dropWhile #-}  -- | 'break' @p@ is equivalent to @'span' ('not' . p)@. break :: Monad m => (Word8 -> Bool) -> ByteString m r -> ByteString m (ByteString m r)@@ -1419,7 +1428,7 @@         c <- liftIO (S.hGetSome h k)         -- only blocks if there is no data available         if S.null c-          then Go $ liftIO (hClose h) >> return (Empty ())+          then Empty ()           else Chunk c loop {-#INLINABLE hGetContentsN #-} -- very effective inline pragma @@ -1527,8 +1536,8 @@   return r {-# INLINE writeFile #-} -{-| Read an entire file into a chunked 'ByteString IO ()'.-    The Handle will be held open until EOF is encountered.+{-| Read an entire file into a chunked @'ByteString' IO ()@.+    The handle will be held open until EOF is encountered.     The block governed by 'Control.Monad.Trans.Resource.runResourceT'     will end with the closing of any handles opened. @@ -1753,7 +1762,7 @@ {-#INLINABLE concatBuilders #-}  -{-| A simple construction of a builder from a byte stream.+{-| A simple construction of a builder from a 'ByteString'.  >>> let aaa = "10000 is a number\n" :: Q.ByteString IO () >>>  hPutBuilder  IO.stdout $ toBuilder  aaa
Data/ByteString/Streaming/Char8.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE CPP, BangPatterns #-}-{-#LANGUAGE RankNTypes, OverloadedStrings #-}+{-#LANGUAGE RankNTypes, OverloadedStrings, ScopedTypeVariables #-} -- This library emulates Data.ByteString.Lazy.Char8 but includes a monadic element -- and thus at certain points uses a `Stream`/`FreeT` type in place of lists. @@ -30,7 +30,6 @@     , mwrap  -     -- * Transforming ByteStrings     , map              -- map :: Monad m => (Char -> Char) -> ByteString m r -> ByteString m r      , intercalate      -- intercalate :: Monad m => ByteString m () -> Stream (ByteString m) m r -> ByteString m r @@ -51,19 +50,12 @@     , uncons           -- uncons :: Monad m => ByteString m r -> m (Either r (Char, ByteString m r))      , nextChar      -    -- * Direct chunk handling-    , unconsChunk-    , nextChunk        -- nextChunk :: Monad m => ByteString m r -> m (Either r (ByteString, ByteString m r)) -    , consChunk-    , chunk-    , foldrChunks-    , foldlChunks-         -- * Substrings      -- ** Breaking strings     , break            -- break :: Monad m => (Char -> Bool) -> ByteString m r -> ByteString m (ByteString m r)      , drop             -- drop :: Monad m => GHC.Int.Int64 -> ByteString m r -> ByteString m r +    , dropWhile     , group            -- group :: Monad m => ByteString m r -> Stream (ByteString m) m r      , groupBy     , span             -- span :: Monad m => (Char -> Bool) -> ByteString m r -> ByteString m (ByteString m r) @@ -77,8 +69,8 @@     , lines     , words     , denull+         -- ** Special folds-     , concat          -- concat :: Monad m => Stream (ByteString m) m r -> ByteString m r       -- * Builders@@ -98,7 +90,7 @@     -- ** Unfolding ByteStrings     , unfoldr          -- unfoldr :: (a -> Maybe (Char, a)) -> a -> ByteString m ()      , unfoldM          -- unfold  :: (a -> Either r (Char, a)) -> a -> ByteString m r-+    , reread     -- *  Folds, including support for `Control.Foldl` --    , foldr            -- foldr :: Monad m => (Char -> a -> a) -> a -> ByteString m () -> m a      , fold             -- fold :: Monad m => (x -> Char -> x) -> x -> (x -> b) -> ByteString m () -> m b @@ -135,6 +127,19 @@     , hGetNonBlockingN -- hGetNonBlockingN :: Int -> Handle -> Int -> ByteString IO ()      , hPut             -- hPut :: Handle -> ByteString IO r -> IO r  --    , hPutNonBlocking  -- hPutNonBlocking :: Handle -> ByteString IO r -> ByteString IO r ++    -- * Simple chunkwise operations +    , unconsChunk+    , nextChunk    +    , chunk+    , foldrChunks+    , foldlChunks+    , chunkFold+    , chunkFoldM+    , chunkMap+    , chunkMapM+    , chunkMapM_+         -- * Etc. --    , zipWithStream    -- zipWithStream :: Monad m => (forall x. a -> ByteString m x -> ByteString m x) -> [a] -> Stream (ByteString m) m r -> Stream (ByteString m) m r      , distribute      -- distribute :: ByteString (t m) a -> t (ByteString m) a @@ -174,7 +179,8 @@     appendFile, stdout, stdin, fromHandle, toHandle,     hGetContents, hGetContentsN, hGet, hGetN, hPut,      getContents, hGetNonBlocking,-    hGetNonBlockingN, readFile, writeFile, interact)+    hGetNonBlockingN, readFile, writeFile, interact,+    chunkFold, chunkFoldM, chunkMap, chunkMapM)  --   hPutNonBlocking,   import Control.Monad            (liftM)@@ -351,12 +357,14 @@  iterate :: (Char -> Char) -> Char -> ByteString m r iterate f c = R.iterate (c2w . f . w2c) (c2w c)+{-#INLINE iterate #-}  -- | @'repeat' x@ is an infinite ByteString, with @x@ the value of every -- element. -- repeat :: Char -> ByteString m r repeat = R.repeat . c2w+{-#INLINE repeat #-}  -- -- | /O(n)/ @'replicate' n x@ is a ByteString of length @n@ with @x@ -- -- the value of every element.@@ -388,10 +396,12 @@   go a = case f a of     Nothing    -> Nothing     Just (c,a) -> Just (c2w c, a)-+{-#INLINE unfoldM #-}+      unfoldr :: (a -> Either r (Char, a)) -> a -> ByteString m r unfoldr step = R.unfoldr (either Left (\(c,a) -> Right (c2w c,a)) . step) +{-#INLINE unfoldr #-}   -- ---------------------------------------------------------------------@@ -402,25 +412,27 @@ -- satisfy @p@. takeWhile :: Monad m => (Char -> Bool) -> ByteString m r -> ByteString m () takeWhile f  = R.takeWhile (f . w2c)--- -- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@.--- dropWhile :: (Word8 -> Bool) -> ByteString -> ByteString--- dropWhile f cs0 = dropWhile' cs0---   where dropWhile' Empty        = Empty---         dropWhile' (Chunk c cs) =---           case findIndexOrEnd (not . f) c of---             n | n < B.length c -> Chunk (B.drop n c) cs---               | otherwise      -> dropWhile' cs+{-#INLINE takeWhile #-} +-- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@.++dropWhile :: Monad m => (Char -> Bool) -> ByteString m r -> ByteString m r+dropWhile f = R.dropWhile (f . w2c)+{-#INLINE dropWhile #-}+ {- | 'break' @p@ is equivalent to @'span' ('not' . p)@.  -} break :: Monad m => (Char -> Bool) -> ByteString m r -> ByteString m (ByteString m r) break f = R.break (f . w2c)+{-#INLINE break #-}+ -- -- | 'span' @p xs@ breaks the ByteString into two segments. It is -- equivalent to @('takeWhile' p xs, 'dropWhile' p xs)@ span :: Monad m => (Char -> Bool) -> ByteString m r -> ByteString m (ByteString m r) span p = break (not . p)+{-#INLINE span #-}  -- -- | /O(n)/ Splits a 'ByteString' into components delimited by -- -- separators, where the predicate returns True for a separator element.@@ -483,29 +495,50 @@      This is the genuinely streaming 'lines' which only breaks chunks, and      thus never increases the use of memory.  -> lines :: Monad m => ByteString m r -> Stream (ByteString m) m r+     Because 'ByteString's are usually read in binary mode, with no line+     ending conversion, this function recognizes both @\\n@ and @\\r\\n@+     endings (regardless of the current platform). -} -lines :: Monad m => ByteString m r -> Stream (ByteString m) m r--- lines = loop---   where---   loop !x = case x of---     Empty r      -> Return r---     Go m         -> Effect $ liftM loop m---     Chunk c0 cs0 -> comb [] (B.split 10 c0) cs0-lines (Empty r) = Return r-lines (Go m)    = Effect $ liftM lines m-lines (Chunk c0 cs0) = comb [] (B.split 10 c0) cs0 where-  comb !acc [] (Empty r)       = Step (revChunks acc (Return r))-  comb acc [] (Chunk c cs)     = comb acc (B.split 10 c) cs-  comb acc (s:[]) (Empty r)    = Step (revChunks (s:acc) (Return r))-  comb acc (s:[]) (Chunk c cs) = comb (s:acc) (B.split 10 c) cs-  comb acc b (Go m)            = Effect (liftM (comb acc b) m)-  comb acc (s:ss) cs           = Step (revChunks (s:acc) (comb [] ss cs))-  revChunks cs r = L.foldl' (flip Chunk) (Empty r) cs+lines :: forall m r . Monad m => ByteString m r -> Stream (ByteString m) m r+lines text0 = loop1 text0+  where+    loop1 :: ByteString m r -> Stream (ByteString m) m r+    loop1 text =+      case text of+        Empty r -> Return r+        Go m -> Effect $ liftM loop1 m+        Chunk c cs+          | B.null c -> loop1 cs+          | otherwise -> Step (loop2 text)+    loop2 :: ByteString m r -> ByteString m (Stream (ByteString m) m r)+    loop2 text =+      case text of+        Empty r -> Empty (Return r)+        Go m -> Go $ liftM loop2 m+        Chunk c cs ->+          case B.elemIndex 10 c of+            Nothing -> Chunk c (loop2 cs)+            Just i ->+              let prefixLength =+                    if i >= 1 && B.unsafeIndex c (i-1) == 13 -- \r\n (dos)+                      then i-1+                      else i+                  rest =+                    if B.length c > i+1+                      then Chunk (B.drop (i+1) c) cs+                      else cs+              in Chunk (B.unsafeTake prefixLength c) (Empty (loop1 rest)) {-#INLINABLE lines #-} --- | The 'unlines' function restores line breaks between layers +-- | The 'unlines' function restores line breaks between layers.+--+-- Note that this is not a perfect inverse of 'lines':+--+--  * @'lines' . 'unlines'@ can produce more strings than there were if some of+--  the \"lines\" had embedded newlines.+--+--  * @'unlines' . 'lines'@ will replace @\\r\\n@ with @\\n@. unlines :: Monad m => Stream (ByteString m) m r ->  ByteString m r unlines = loop where   loop str =  case str of
Data/ByteString/Streaming/Internal.hs view
@@ -14,6 +14,11 @@     , foldrChunksM       -- :: Monad m => (ByteString -> m a -> m a) -> m a -> ByteString m r -> m a    , foldlChunksM       -- :: Monad m => (ByteString -> m a -> m a) -> m a -> ByteString m r -> m a+   , chunkFold+   , chunkFoldM+   , chunkMap+   , chunkMapM+   , chunkMapM_    , unfoldMChunks    , unfoldrChunks    @@ -88,8 +93,12 @@  instance Monad m => Applicative (ByteString m) where   pure = Empty-  (<*>) = ap-+  {-#INLINE pure #-} +  bf <*> bx = do {f <- bf; x <- bx; Empty (f x)}+  {-#INLINE (<*>) #-} +  (*>) = (>>)+  {-#INLINE (*>) #-}+   instance Monad m => Monad (ByteString m) where   return = Empty   {-#INLINE return #-}@@ -121,9 +130,9 @@  instance MFunctor ByteString where   hoist phi bs = case bs of-    Empty r       -> Empty r+    Empty r        -> Empty r     Chunk bs' rest -> Chunk bs' (hoist phi rest)-    Go m          -> Go (phi (liftM (hoist phi) m))+    Go m           -> Go (phi (liftM (hoist phi) m))   {-#INLINABLE hoist #-}    instance (r ~ ()) => IsString (ByteString m r) where@@ -131,10 +140,10 @@   {-#INLINE fromString #-}    instance (m ~ Identity, Show r) => Show (ByteString m r) where-  show bs0 = case bs0 of-    Empty r -> "Empty (" ++ show r ++ ")"+  show bs0 = case bs0 of  -- the implementation this instance deserves ...+    Empty r           -> "Empty (" ++ show r ++ ")"     Go (Identity bs') -> "Go (Identity (" ++ show bs' ++ "))"-    Chunk bs'' bs -> "Chunk " ++ show bs'' ++ " (" ++ show bs ++ ")"+    Chunk bs'' bs     -> "Chunk " ++ show bs'' ++ " (" ++ show bs ++ ")"      instance (Monoid r, Monad m) => Monoid (ByteString m r) where   mempty = Empty mempty@@ -150,7 +159,6 @@   throwM = lift . throwM    {-#INLINE throwM #-} - instance (MonadCatch m) => MonadCatch (ByteString m) where   catch str f = go str     where@@ -347,6 +355,46 @@         go a (Go m)       = m >>= go a {-# INLINABLE foldlChunks #-} +chunkMap :: Monad m => (S.ByteString -> S.ByteString) -> ByteString m r -> ByteString m r +chunkMap f bs = dematerialize bs return (\bs bss -> Chunk (f bs) bss) Go+{-#INLINE chunkMap #-}++chunkMapM :: Monad m => (S.ByteString -> m S.ByteString) -> ByteString m r -> ByteString m r +chunkMapM f bs = dematerialize bs return (\bs bss -> Go (liftM (flip Chunk bss) (f bs))) Go+{-#INLINE chunkMapM #-}++chunkMapM_ :: Monad m => (S.ByteString -> m x) -> ByteString m r -> m r +chunkMapM_ f bs = dematerialize bs return (\bs mr -> f bs >> mr) join+{-#INLINE chunkMapM_ #-}+++{- | @chunkFold@ is preferable to @foldlChunks@ since it is +     an appropriate argument for @Control.Foldl.purely@ which +     permits many folds and sinks to be run simulaneously on one bytestream.++  -}+chunkFold :: Monad m => (x -> S.ByteString -> x) -> x -> (x -> a) -> ByteString m r -> m (Of a r)+chunkFold step begin done = go begin+  where go a _ | a `seq` False = undefined+        go a (Empty r)    = return (done a :> r)+        go a (Chunk c cs) = go (step a c) cs+        go a (Go m)       = m >>= go a+{-# INLINABLE chunkFold #-}++{- | @chunkFoldM@ is preferable to @foldlChunksM@ since it is +     an appropriate argument for @Control.Foldl.impurely@ which+     permits many folds and sinks to be run simulaneously on one bytestream.++  -}+chunkFoldM :: Monad m => (x -> S.ByteString -> m x) -> m x -> (x -> m a) -> ByteString m r -> m (Of a r)+chunkFoldM step begin done bs = begin >>= go bs+  where +    go str !x = case str of +      Empty r    -> done x >>= \a -> return (a :> r)+      Chunk c cs -> step x c >>= go cs+      Go m       -> m >>= \str' -> go str' x+{-# INLINABLE chunkFoldM  #-}+ foldlChunksM :: Monad m => (a -> S.ByteString -> m a) -> m a -> ByteString m r -> m (Of a r) foldlChunksM f z bs = z >>= \a -> go a bs   where @@ -356,6 +404,8 @@       Go m       -> m >>= go a  {-# INLINABLE foldlChunksM #-} ++ -- | Consume the chunks of an effectful ByteString with a natural right monadic fold. foldrChunksM :: Monad m => (S.ByteString -> m a -> m a) -> m a -> ByteString m r -> m a foldrChunksM step nil bs = dematerialize bs@@ -397,7 +447,18 @@ {-# INLINABLE unfoldrChunks #-}  +{-| Stream chunks from something that contains @IO (Maybe ByteString)@+    until it returns @Nothing@. @reread@ is of particular use rendering @io-streams@+    input streams as byte streams in the present sense +> Q.reread Streams.read             :: InputStream S.ByteString -> Q.ByteString IO ()+> Q.reread (liftIO . Streams.read)  :: MonadIO m => InputStream S.ByteString -> Q.ByteString m ()++The other direction here is ++> Streams.unfoldM Q.unconsChunk     :: Q.ByteString IO r -> IO (InputStream S.ByteString)++  -} reread :: Monad m => (s -> m (Maybe S.ByteString)) -> s -> ByteString m () reread step s = loop where    loop = Go $ do 
streaming-bytestring.cabal view
@@ -1,5 +1,5 @@ name:                streaming-bytestring-version:             0.1.4.4+version:             0.1.4.5 synopsis:            effectful byte steams, or: bytestring io done right.  description:         This is an implementation of effectful, memory-constrained @@ -199,3 +199,21 @@   default-language:    Haskell2010   ghc-options: -O2   +test-suite test+  default-language:+    Haskell2010+  type:+    exitcode-stdio-1.0+  hs-source-dirs:+    tests+  main-is:+    test.hs+  build-depends:+      base >= 4 && < 5+    , transformers+    , tasty >= 0.11.0.4+    , tasty-smallcheck >= 0.8.1+    , smallcheck >= 1.1.1+    , streaming+    , streaming-bytestring+    , bytestring
+ tests/test.hs view
@@ -0,0 +1,47 @@+import Test.Tasty+import Test.Tasty.SmallCheck+import Test.SmallCheck.Series++import Control.Applicative+import Data.Functor.Identity+import qualified Data.ByteString.Char8 as BS8+import qualified Data.ByteString.Streaming.Char8 as SBS8+import Text.Printf+import qualified Streaming.Prelude as S++listOf :: Monad m => Series m a -> Series m [a]+listOf a = decDepth $+  pure [] \/ ((:) <$> a <~> listOf a)++strSeries :: Monad m => Series m String+strSeries = listOf (generate $ const ['a', 'b', '\n'])++chunksSeries :: Monad m => Series m [String]+chunksSeries = listOf strSeries++fromChunks :: [String] -> SBS8.ByteString Identity ()+fromChunks = SBS8.fromChunks . S.each .  map BS8.pack++unix2dos :: String -> String+unix2dos = concatMap $ \c -> if c == '\n' then "\r\n" else [c]++s_lines :: SBS8.ByteString Identity () -> [BS8.ByteString]+s_lines+  = runIdentity+  . S.toList_+  . S.mapped SBS8.toStrict+  . SBS8.lines++main = defaultMain $ testGroup "Tests"+  [ testGroup "lines" $+    [ testProperty "Data.ByteString.Streaming.Char8.lines is equivalent to Prelude.lines" $ over chunksSeries $ \chunks ->+        let expected = lines $ concat chunks+            got = (map BS8.unpack . s_lines . fromChunks) chunks+        in+        if expected == got+          then Right ""+          else Left (printf "Expected %s; got %s" (show expected) (show got) :: String)+    , testProperty "lines recognizes DOS line endings" $ over strSeries $ \str ->+        s_lines (SBS8.string $ unix2dos str) == s_lines (SBS8.string str)+    ]+  ]