packages feed

pipes-bytestring (empty) → 1.0.0

raw patch · 4 files changed

+968/−0 lines, 4 filesdep +basedep +bytestringdep +pipessetup-changed

Dependencies added: base, bytestring, pipes, pipes-parse, transformers

Files

+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2012, 2013 Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:+    * Redistributions of source code must retain the above copyright notice,+      this list of conditions and the following disclaimer.+    * Redistributions in binary form must reproduce the above copyright notice,+      this list of conditions and the following disclaimer in the documentation+      and/or other materials provided with the distribution.+    * Neither the name of Gabriel Gonzalez nor the names of other contributors+      may be used to endorse or promote products derived from this software+      without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ pipes-bytestring.cabal view
@@ -0,0 +1,27 @@+Name: pipes-bytestring+Version: 1.0.0+Cabal-Version: >=1.8.0.2+Build-Type: Simple+License: BSD3+License-File: LICENSE+Copyright: 2012, 2013 Gabriel Gonzalez+Author: Gabriel Gonzalez+Maintainer: Gabriel439@gmail.com+Bug-Reports: https://github.com/Gabriel439/Haskell-Pipes-ByteString-Library/issues+Synopsis: ByteString support for pipes+Description: This library provides @pipes@ utilities for @ByteString@s+Category: Control, Pipes+Source-Repository head+    Type: git+    Location: https://github.com/Gabriel439/Haskell-Pipes-ByteString-Library++Library+    Hs-Source-Dirs: src+    Build-Depends:+        base         >= 4       && < 5   ,+        bytestring   >= 0.9.2.1 && < 0.11,+        pipes        >= 4.0     && < 4.1 ,+        pipes-parse  >= 2.0.0   && < 2.1 ,+        transformers >= 0.2.0.0 && < 0.4+    Exposed-Modules: Pipes.ByteString+    GHC-Options: -O2 -Wall
+ src/Pipes/ByteString.hs view
@@ -0,0 +1,915 @@+{-# LANGUAGE RankNTypes #-}++{-| This module provides @pipes@ utilities for \"byte streams\", which are+    streams of strict 'ByteString's chunks.  Use byte streams to interact+    with both 'IO.Handle's and lazy 'ByteString's.++    To stream to or from 'IO.Handle's, use 'fromHandle' or 'toHandle'.  For+    example, the following program copies data from one file to another:++> import Pipes+> import qualified Pipes.ByteString as P+> import System.IO+>+> main =+>     withFile "inFile.txt"  ReadMode  $ \hIn  ->+>     withFile "outFile.txt" WriteMode $ \hOut ->+>     runEffect $ P.fromHandle hIn >-> P.toHandle hOut++    You can stream to and from 'stdin' and 'stdout' using the predefined 'stdin'+    and 'stdout' proxies, like in the following \"echo\" program:++> main = runEffect $ P.stdin >-> P.stdout++    You can also translate pure lazy 'BL.ByteString's to and from proxies:++> import qualified Data.ByteString.Lazy.Char8 as BL+>+> main = runEffect $ P.fromLazy (BL.pack "Hello, world!\n") >-> P.stdout++    In addition, this module provides many functions equivalent to lazy+    'ByteString' functions so that you can transform or fold byte streams.  For+    example, to stream only the first three lines of 'stdin' to 'stdout' you+    would write:++> import Pipes+> import qualified Pipes.ByteString as PB+> import qualified Pipes.Parse      as PP+>+> main = runEffect $ takeLines 3 PB.stdin >-> PB.stdout+>   where+>     takeLines n = PB.unlines . PP.takeFree n . PB.lines++    The above program will never bring more than one chunk (~ 32 KB) into+    memory, no matter how long the lines are.++    Note that functions in this library are designed to operate on streams that+    are insensitive to chunk boundaries.  This means that they may freely split+    chunks into smaller chunks and /discard empty chunks/.  However, they will+    /never concatenate chunks/ in order to provide strict upper bounds on memory+    usage.+-}++module Pipes.ByteString (+    -- * Producers+    fromLazy,+    stdin,+    fromHandle,+    hGetSome,+    hGet,++    -- * Servers+    hGetSomeN,+    hGetN,++    -- * Consumers+    stdout,+    toHandle,++    -- * Pipes+    map,+    concatMap,+    take,+    drop,+    takeWhile,+    dropWhile,+    filter,+    elemIndices,+    findIndices,+    scan,++    -- * Folds+    toLazy,+    toLazyM,+    fold,+    head,+    last,+    null,+    length,+    any,+    all,+    maximum,+    minimum,+    elem,+    notElem,+    find,+    index,+    elemIndex,+    findIndex,+    count,++    -- * Splitters+    splitAt,+    chunksOf,+    span,+    break,+    splitWith,+    split,+    groupBy,+    group,+    lines,+    words,++    -- * Transformations+    intersperse,++    -- * Joiners+    intercalate,+    unlines,+    unwords,++    -- * Low-level Parsers+    -- $parse+    nextByte,+    drawByte,+    unDrawByte,+    peekByte,+    isEndOfBytes,+    takeWhile',++    -- * Re-exports+    -- $reexports+    module Data.ByteString,+    module Data.Word,+    module Pipes.Parse+    ) where++import Control.Exception (throwIO, try)+import Control.Monad (liftM)+import Control.Monad.Trans.State.Strict (StateT, modify)+import qualified Data.ByteString as BS+import Data.ByteString (ByteString)+import Data.ByteString.Internal (isSpaceWord8)+import qualified Data.ByteString.Lazy as BL+import Data.ByteString.Lazy.Internal (foldrChunks, defaultChunkSize)+import Data.ByteString.Unsafe (unsafeTake, unsafeDrop)+import Data.Char (ord)+import Data.Functor.Identity (Identity)+import qualified Data.List as List+import Data.Word (Word8)+import Foreign.C.Error (Errno(Errno), ePIPE)+import qualified GHC.IO.Exception as G+import Pipes+import Pipes.Core (respond, Server')+import qualified Pipes.Parse as PP+import Pipes.Parse (input, concat, FreeT)+import qualified Pipes.Prelude as P+import qualified System.IO as IO+import Prelude hiding (+    all,+    any,+    break,+    concat,+    concatMap,+    drop,+    dropWhile,+    elem,+    filter,+    head,+    last,+    lines,+    length,+    map,+    maximum,+    minimum,+    notElem,+    null,+    span,+    splitAt,+    take,+    takeWhile,+    unlines,+    unwords,+    words )++-- | Convert a lazy 'BL.ByteString' into a 'Producer' of strict 'ByteString's+fromLazy :: (Monad m) => BL.ByteString -> Producer' ByteString m ()+fromLazy bs = foldrChunks (\e a -> yield e >> a) (return ()) bs+{-# INLINABLE fromLazy #-}++-- | Stream bytes from 'stdin'+stdin :: MonadIO m => Producer' ByteString m ()+stdin = fromHandle IO.stdin+{-# INLINABLE stdin #-}++-- | Convert a 'IO.Handle' into a byte stream using a default chunk size+fromHandle :: MonadIO m => IO.Handle -> Producer' ByteString m ()+fromHandle = hGetSome defaultChunkSize+-- TODO: Test chunk size for performance+{-# INLINABLE fromHandle #-}++{-| Convert a handle into a byte stream using a maximum chunk size++    'hGetSome' forwards input immediately as it becomes available, splitting the+    input into multiple chunks if it exceeds the maximum chunk size.+-}+hGetSome :: MonadIO m => Int -> IO.Handle -> Producer' ByteString m ()+hGetSome size h = go where+    go = do+        eof <- liftIO (IO.hIsEOF h)+        if eof+            then return ()+            else do+                bs <- liftIO (BS.hGetSome h size)+                yield bs+                go+{-# INLINABLE hGetSome #-}++{-| Convert a handle into a byte stream using a fixed chunk size++    'hGet' waits until exactly the requested number of bytes are available for+    each chunk.+-}+hGet :: MonadIO m => Int -> IO.Handle -> Producer' ByteString m ()+hGet size h = go where+    go = do+        eof <- liftIO (IO.hIsEOF h)+        if eof+            then return ()+            else do+                bs <- liftIO (BS.hGet h size)+                yield bs+                go+{-# INLINABLE hGet #-}++{-| Like 'hGetSome', except you can vary the maximum chunk size for each request+-}+hGetSomeN :: MonadIO m => IO.Handle -> Int -> Server' Int ByteString m ()+hGetSomeN h = go where+    go size = do+        eof <- liftIO (IO.hIsEOF h)+        if eof+            then return ()+            else do+                bs    <- liftIO (BS.hGetSome h size)+                size2 <- respond bs+                go size2+{-# INLINABLE hGetSomeN #-}++-- | Like 'hGet', except you can vary the chunk size for each request+hGetN :: MonadIO m => IO.Handle -> Int -> Server' Int ByteString m ()+hGetN h = go where+    go size = do+        eof <- liftIO (IO.hIsEOF h)+        if eof+            then return ()+            else do+                bs    <- liftIO (BS.hGet h size)+                size2 <- respond bs+                go size2+{-# INLINABLE hGetN #-}++{-| Stream bytes to 'stdout'++    Unlike 'toHandle', 'stdout' gracefully terminates on a broken output pipe.++    Note: For best performance, use @(for source (liftIO . putStr))@ instead of+    @(source >-> stdout)@.+-}+stdout :: MonadIO m => Consumer' ByteString m ()+stdout = go+  where+    go = do+        bs <- await+        x  <- liftIO $ try (BS.putStr bs)+        case x of+            Left (G.IOError { G.ioe_type  = G.ResourceVanished+                            , G.ioe_errno = Just ioe })+                 | Errno ioe == ePIPE+                     -> return ()+            Left  e  -> liftIO (throwIO e)+            Right () -> go+{-# INLINABLE stdout #-}++{-| Convert a byte stream into a 'Handle'++    Note: For best performance, use @(for source (liftIO . hPutStr handle))@+    instead of @(source >-> toHandle handle)@.+-}+toHandle :: MonadIO m => IO.Handle -> Consumer' ByteString m r+toHandle h = for cat (liftIO . BS.hPut h)+{-# INLINABLE toHandle #-}++-- | Apply a transformation to each 'Word8' in the stream+map :: (Monad m) => (Word8 -> Word8) -> Pipe ByteString ByteString m r+map f = P.map (BS.map f)+{-# INLINABLE map #-}++-- | Map a function over the byte stream and concatenate the results+concatMap+    :: (Monad m) => (Word8 -> ByteString) -> Pipe ByteString ByteString m r+concatMap f = P.map (BS.concatMap f)+{-# INLINABLE concatMap #-}++-- | @(take n)@ only allows @n@ bytes to pass+take :: (Monad m, Integral a) => a -> Pipe ByteString ByteString m ()+take n0 = go n0 where+    go n+        | n <= 0    = return ()+        | otherwise = do+            bs <- await+            let len = fromIntegral (BS.length bs)+            if (len > n)+                then yield (unsafeTake (fromIntegral n) bs)+                else do+                    yield bs+                    go (n - len)+{-# INLINABLE take #-}++-- | @(dropD n)@ drops the first @n@ bytes+drop :: (Monad m, Integral a) => a -> Pipe ByteString ByteString m r+drop n0 = go n0 where+    go n+        | n <= 0    = cat+        | otherwise = do+            bs <- await+            let len = fromIntegral (BS.length bs)+            if (len >= n)+                then do+                    yield (unsafeDrop (fromIntegral n) bs)+                    cat+                else go (n - len)+{-# INLINABLE drop #-}++-- | Take bytes until they fail the predicate+takeWhile :: (Monad m) => (Word8 -> Bool) -> Pipe ByteString ByteString m ()+takeWhile predicate = go+  where+    go = do+        bs <- await+        let (prefix, suffix) = BS.span predicate bs+        if (BS.null suffix)+            then do+                yield bs+                go+            else yield prefix+{-# INLINABLE takeWhile #-}++-- | Drop bytes until they fail the predicate+dropWhile :: (Monad m) => (Word8 -> Bool) -> Pipe ByteString ByteString m r+dropWhile predicate = go where+    go = do+        bs <- await+        case BS.findIndex (not . predicate) bs of+            Nothing -> go+            Just i -> do+                yield (unsafeDrop i bs)+                cat+{-# INLINABLE dropWhile #-}++-- | Only allows 'Word8's to pass if they satisfy the predicate+filter :: (Monad m) => (Word8 -> Bool) -> Pipe ByteString ByteString m r+filter predicate = P.map (BS.filter predicate)+{-# INLINABLE filter #-}++-- | Stream all indices whose elements match the given 'Word8'+elemIndices :: (Monad m, Num n) => Word8 -> Pipe ByteString n m r+elemIndices w8 = findIndices (w8 ==)+{-# INLINABLE elemIndices #-}++-- | Stream all indices whose elements satisfy the given predicate+findIndices :: (Monad m, Num n) => (Word8 -> Bool) -> Pipe ByteString n m r+findIndices predicate = go 0+  where+    go n = do+        bs <- await+	each $ List.map (\i -> n + fromIntegral i) (BS.findIndices predicate bs)+        go $! n + fromIntegral (BS.length bs)+{-# INLINABLE findIndices #-}++-- | Strict left scan over the bytes+scan+    :: (Monad m)+    => (Word8 -> Word8 -> Word8) -> Word8 -> Pipe ByteString ByteString m r+scan step begin = go begin+  where+    go w8 = do+        bs <- await+        let bs' = BS.scanl step w8 bs+            w8' = BS.last bs'+        yield bs'+        go w8'+{-# INLINABLE scan #-}++{-| Fold a pure 'Producer' of strict 'ByteString's into a lazy+    'BL.ByteString'+-}+toLazy :: Producer ByteString Identity () -> BL.ByteString+toLazy = BL.fromChunks . P.toList+{-# INLINABLE toLazy #-}++{-| Fold an effectful 'Producer' of strict 'ByteString's into a lazy+    'BL.ByteString'++    Note: 'toLazyM' is not an idiomatic use of @pipes@, but I provide it for+    simple testing purposes.  Idiomatic @pipes@ style consumes the chunks+    immediately as they are generated instead of loading them all into memory.+-}+toLazyM :: (Monad m) => Producer ByteString m () -> m BL.ByteString+toLazyM = liftM BL.fromChunks . P.toListM+{-# INLINABLE toLazyM #-}++-- | Reduce the stream of bytes using a strict left fold+fold+    :: Monad m+    => (x -> Word8 -> x) -> x -> (x -> r) -> Producer ByteString m () -> m r+fold step begin done = P.fold (\x bs -> BS.foldl' step x bs) begin done+{-# INLINABLE fold #-}++-- | Retrieve the first 'Word8'+head :: (Monad m) => Producer ByteString m () -> m (Maybe Word8)+head = go+  where+    go p = do+        x <- nextByte p+        case x of+            Left   _      -> return  Nothing+            Right (w8, _) -> return (Just w8)+{-# INLINABLE head #-}++-- | Retrieve the last 'Word8'+last :: (Monad m) => Producer ByteString m () -> m (Maybe Word8)+last = go Nothing+  where+    go r p = do+        x <- next p+        case x of+            Left   ()      -> return r+            Right (bs, p') ->+                if (BS.null bs)+                then go r p'+                else go (Just $ BS.last bs) p'+                -- TODO: Change this to 'unsafeLast' when bytestring-0.10.2.0+                --       becomes more widespread+{-# INLINABLE last #-}++-- | Determine if the stream is empty+null :: (Monad m) => Producer ByteString m () -> m Bool+null = P.all BS.null+{-# INLINABLE null #-}++-- | Count the number of bytes+length :: (Monad m, Num n) => Producer ByteString m () -> m n+length = P.fold (\n bs -> n + fromIntegral (BS.length bs)) 0 id+{-# INLINABLE length #-}++-- | Fold that returns whether 'M.Any' received 'Word8's satisfy the predicate+any :: (Monad m) => (Word8 -> Bool) -> Producer ByteString m () -> m Bool+any predicate = P.any (BS.any predicate)+{-# INLINABLE any #-}++-- | Fold that returns whether 'M.All' received 'Word8's satisfy the predicate+all :: (Monad m) => (Word8 -> Bool) -> Producer ByteString m () -> m Bool+all predicate = P.all (BS.all predicate)+{-# INLINABLE all #-}++-- | Return the maximum 'Word8' within a byte stream+maximum :: (Monad m) => Producer ByteString m () -> m (Maybe Word8)+maximum = P.fold step Nothing id+  where+    step mw8 bs =+        if (BS.null bs)+        then mw8+        else Just $ case mw8 of+            Nothing -> BS.maximum bs+            Just w8 -> max w8 (BS.maximum bs)+{-# INLINABLE maximum #-}++-- | Return the minimum 'Word8' within a byte stream+minimum :: (Monad m) => Producer ByteString m () -> m (Maybe Word8)+minimum = P.fold step Nothing id+  where+    step mw8 bs =+        if (BS.null bs)+        then mw8+        else case mw8 of+            Nothing -> Just (BS.minimum bs)+            Just w8 -> Just (min w8 (BS.minimum bs))+{-# INLINABLE minimum #-}++-- | Determine whether any element in the byte stream matches the given 'Word8'+elem :: (Monad m) => Word8 -> Producer ByteString m () -> m Bool+elem w8 = P.any (BS.elem w8)+{-# INLINABLE elem #-}++{-| Determine whether all elements in the byte stream do not match the given+    'Word8'+-}+notElem :: (Monad m) => Word8 -> Producer ByteString m () -> m Bool+notElem w8 = P.all (BS.notElem w8)+{-# INLINABLE notElem #-}++-- | Find the first element in the stream that matches the predicate+find+    :: (Monad m)+    => (Word8 -> Bool) -> Producer ByteString m () -> m (Maybe Word8)+find predicate p = head (p >-> filter predicate)+{-# INLINABLE find #-}++-- | Index into a byte stream+index+    :: (Monad m, Integral a)+    => a-> Producer ByteString m () -> m (Maybe Word8)+index n p = head (p >-> drop n)+{-# INLINABLE index #-}++-- | Find the index of an element that matches the given 'Word8'+elemIndex+    :: (Monad m, Num n) => Word8 -> Producer ByteString m () -> m (Maybe n)+elemIndex w8 = findIndex (w8 ==)+{-# INLINABLE elemIndex #-}++-- | Store the first index of an element that satisfies the predicate+findIndex+    :: (Monad m, Num n)+    => (Word8 -> Bool) -> Producer ByteString m () -> m (Maybe n)+findIndex predicate p = P.head (p >-> findIndices predicate)+{-# INLINABLE findIndex #-}++-- | Store a tally of how many elements match the given 'Word8'+count :: (Monad m, Num n) => Word8 -> Producer ByteString m () -> m n+count w8 p = P.fold (+) 0 id (p >-> P.map (fromIntegral . BS.count w8))+{-# INLINABLE count #-}++-- | Splits a 'Producer' after the given number of bytes+splitAt+    :: (Monad m, Integral n)+    => n+    -> Producer ByteString m r+    -> Producer' ByteString m (Producer ByteString m r)+splitAt = go+  where+    go 0 p = return p+    go n p = do+        x <- lift (next p)+        case x of+            Left   r       -> return (return r)+            Right (bs, p') -> do+                let len = fromIntegral (BS.length bs)+                if (len <= n)+                    then do+                        yield bs+                        go (n - len) p'+                    else do+                        let (prefix, suffix) = BS.splitAt (fromIntegral n) bs+                        yield prefix+                        return (yield suffix >> p')+{-# INLINABLE splitAt #-}++-- | Split a byte stream into 'FreeT'-delimited byte streams of fixed size+chunksOf+    :: (Monad m, Integral n)+    => n -> Producer ByteString m r -> FreeT (Producer ByteString m) m r+chunksOf n p0 = PP.FreeT (go p0)+  where+    go p = do+        x <- next p+        return $ case x of+            Left   r       -> PP.Pure r+            Right (bs, p') -> PP.Free $ do+                p'' <- splitAt n (yield bs >> p')+                return $ PP.FreeT (go p'')+{-# INLINABLE chunksOf #-}++{-| Split a byte stream in two, where the first byte stream is the longest+    consecutive group of bytes that satisfy the predicate+-}+span+    :: (Monad m)+    => (Word8 -> Bool)+    -> Producer ByteString m r+    -> Producer' ByteString m (Producer ByteString m r)+span predicate = go+  where+    go p = do+        x <- lift (next p)+        case x of+            Left   r       -> return (return r)+            Right (bs, p') -> do+                let (prefix, suffix) = BS.span predicate bs+                if (BS.null suffix)+                    then do+                        yield bs+                        go p'+                    else do+                        yield prefix+                        return (yield suffix >> p')+{-# INLINABLE span #-}++{-| Split a byte stream in two, where the first byte stream is the longest+    consecutive group of bytes that don't satisfy the predicate+-}+break+    :: (Monad m)+    => (Word8 -> Bool)+    -> Producer ByteString m r+    -> Producer ByteString m (Producer ByteString m r)+break predicate = span (not . predicate)+{-# INLINABLE break #-}++{-| Split a byte stream into sub-streams delimited by bytes that satisfy the+    predicate+-}+splitWith+    :: (Monad m)+    => (Word8 -> Bool)+    -> Producer ByteString m r+    -> PP.FreeT (Producer ByteString m) m r+splitWith predicate p0 = PP.FreeT (go0 p0)+  where+    go0 p = do+        x <- next p+        case x of+            Left   r       -> return (PP.Pure r)+            Right (bs, p') ->+                if (BS.null bs)+                then go0 p'+                else return $ PP.Free $ do+                    p'' <- span (not . predicate) (yield bs >> p')+                    return $ PP.FreeT (go1 p'')+    go1 p = do+        x <- nextByte p+        return $ case x of+            Left   r      -> PP.Pure r+            Right (_, p') -> PP.Free $ do+                    p'' <- span (not . predicate) p'+                    return $ PP.FreeT (go1 p'')+{-# INLINABLE splitWith #-}++-- | Split a byte stream using the given 'Word8' as the delimiter+split :: (Monad m)+      => Word8+      -> Producer ByteString m r+      -> FreeT (Producer ByteString m) m r+split w8 = splitWith (w8 /=)+{-# INLINABLE split #-}++{-| Group a byte stream into 'FreeT'-delimited byte streams using the supplied+    equality predicate+-}+groupBy+    :: (Monad m)+    => (Word8 -> Word8 -> Bool)+    -> Producer ByteString m r+    -> FreeT (Producer ByteString m) m r+groupBy equal p0 = PP.FreeT (go p0)+  where+    go p = do+        x <- next p+        case x of+            Left   r       -> return (PP.Pure r)+            Right (bs, p') -> case (BS.uncons bs) of+                Nothing      -> go p'+                Just (w8, _) -> do+                    return $ PP.Free $ do+                        p'' <- span (equal w8) (yield bs >> p')+                        return $ PP.FreeT (go p'')+{-# INLINABLE groupBy #-}++-- | Group a byte stream into 'FreeT'-delimited byte streams of identical bytes+group+    :: (Monad m) => Producer ByteString m r -> FreeT (Producer ByteString m) m r+group = groupBy (==)+{-# INLINABLE group #-}++{-| Split a byte stream into 'FreeT'-delimited lines++    Note: This function is purely for demonstration purposes since it assumes a+    particular encoding.  You should prefer the 'Data.Text.Text' equivalent of+    this function from the upcoming @pipes-text@ library.+-}+lines+    :: (Monad m) => Producer ByteString m r -> FreeT (Producer ByteString m) m r+lines p0 = PP.FreeT (go0 p0)+  where+    go0 p = do+        x <- next p+        case x of+            Left   r       -> return (PP.Pure r)+            Right (bs, p') ->+                if (BS.null bs)+                then go0 p'+                else return $ PP.Free $ go1 (yield bs >> p')+    go1 p = do+        p' <- break (fromIntegral (ord '\n') ==) p+        return $ PP.FreeT (go2 p')+    go2 p = do+        x  <- next p+        return $ case x of+            Left   r      -> PP.Pure r+            Right (_, p') -> PP.Free (go1 p')+{-# INLINABLE lines #-}++{-| Split a byte stream into 'FreeT'-delimited words++    Note: This function is purely for demonstration purposes since it assumes a+    particular encoding.  You should prefer the 'Data.Text.Text' equivalent of+    this function from the upcoming @pipes-text@ library.+-}+words+    :: (Monad m) => Producer ByteString m r -> FreeT (Producer ByteString m) m r+words p0 = removeEmpty (splitWith isSpaceWord8 p0)+  where+    removeEmpty f = PP.FreeT $ do+        x <- PP.runFreeT f+        case x of+            PP.Pure r -> return (PP.Pure r)+            PP.Free p -> do+                y <- next p+                case y of+                    Left   f'      -> PP.runFreeT (removeEmpty f')+                    Right (bs, p') -> return $ PP.Free $ do+                        yield bs+                        f' <- p'+                        return (removeEmpty f')+{-# INLINABLE words #-}++-- | Intersperse a 'Word8' in between the bytes of the byte stream+intersperse+    :: (Monad m) => Word8 -> Producer ByteString m r -> Producer ByteString m r+intersperse w8 = go0+  where+    go0 p = do+        x <- lift (next p)+        case x of+            Left   r       -> return r+            Right (bs, p') -> do+                yield (BS.intersperse w8 bs)+                go1 p'+    go1 p = do+        x <- lift (next p)+        case x of+            Left   r       -> return r+            Right (bs, p') -> do+                yield (BS.singleton w8)+                yield (BS.intersperse w8 bs)+                go1 p'+{-# INLINABLE intersperse #-}++{-| 'intercalate' concatenates the 'FreeT'-delimited byte streams after+    interspersing a byte stream in between them+-}+intercalate+    :: (Monad m)+    => Producer ByteString m ()+    -> FreeT (Producer ByteString m) m r+    -> Producer ByteString m r+intercalate p0 = go0+  where+    go0 f = do+        x <- lift (PP.runFreeT f)+        case x of+            PP.Pure r -> return r+            PP.Free p -> do+                f' <- p+                go1 f'+    go1 f = do+        x <- lift (PP.runFreeT f)+        case x of+            PP.Pure r -> return r+            PP.Free p -> do+                p0+                f' <- p+                go1 f'+{-# INLINABLE intercalate #-}++{-| Join 'FreeT'-delimited lines into a byte stream++    Note: This function is purely for demonstration purposes since it assumes a+    particular encoding.  You should prefer the 'Data.Text.Text' equivalent of+    this function from the upcoming @pipes-text@ library.+-}+unlines+    :: (Monad m) => FreeT (Producer ByteString m) m r -> Producer ByteString m r+unlines = go+  where+    go f = do+        x <- lift (PP.runFreeT f)+        case x of+            PP.Pure r -> return r+            PP.Free p -> do+                f' <- p+                yield $ BS.singleton $ fromIntegral (ord '\n')+                go f'+{-# INLINABLE unlines #-}++{-| Join 'FreeT'-delimited words into a byte stream++    Note: This function is purely for demonstration purposes since it assumes a+    particular encoding.  You should prefer the 'Data.Text.Text' equivalent of+    this function from the upcoming @pipes-text@ library.+-}+unwords+    :: (Monad m) => FreeT (Producer ByteString m) m r -> Producer ByteString m r+unwords = intercalate (yield $ BS.singleton $ fromIntegral $ ord ' ')+{-# INLINABLE unwords #-}++{- $parse+    The following parsing utilities are single-byte analogs of the ones found+    in @pipes-parse@.+-}++{-| Consume the first byte from a byte stream++    'next' either fails with a 'Left' if the 'Producer' has no more bytes or+    succeeds with a 'Right' providing the next byte and the remainder of the+    'Producer'.+-}+nextByte+    :: (Monad m)+    => Producer ByteString m r+    -> m (Either r (Word8, Producer ByteString m r))+nextByte = go+  where+    go p = do+        x <- next p+        case x of+            Left   r       -> return (Left r)+            Right (bs, p') -> case (BS.uncons bs) of+                Nothing        -> go p'+                Just (w8, bs') -> return (Right (w8, yield bs' >> p'))+{-# INLINABLE nextByte #-}++{-| Draw one 'Word8' from the underlying 'Producer', returning 'Left' if the+    'Producer' is empty+-}+drawByte :: (Monad m) => StateT (Producer ByteString m r) m (Either r Word8)+drawByte = do+    x <- PP.draw+    case x of+        Left  r  -> return (Left r)+        Right bs -> case (BS.uncons bs) of+            Nothing        -> drawByte+            Just (w8, bs') -> do+                PP.unDraw bs'+                return (Right w8)+{-# INLINABLE drawByte #-}++-- | Push back a 'Word8' onto the underlying 'Producer'+unDrawByte :: (Monad m) => Word8 -> StateT (Producer ByteString m r) m ()+unDrawByte w8 = modify (yield (BS.singleton w8) >>)+{-# INLINABLE unDrawByte #-}++{-| 'peekByte' checks the first 'Word8' in the stream, but uses 'unDrawByte' to+    push the 'Word8' back++> peekByte = do+>     x <- drawByte+>     case x of+>         Left  _  -> return ()+>         Right w8 -> unDrawByte w8+>     return x+-}+peekByte :: (Monad m) => StateT (Producer ByteString m r) m (Either r Word8)+peekByte = do+    x <- drawByte+    case x of+        Left  _  -> return ()+        Right w8 -> unDrawByte w8+    return x+{-# INLINABLE peekByte #-}++{-| Check if the underlying 'Producer' has no more bytes++    Note that this will skip over empty 'ByteString' chunks, unlike+    'PP.isEndOfInput' from @pipes-parse@.++> isEndOfBytes = liftM isLeft peekByte+-}+isEndOfBytes :: (Monad m) => StateT (Producer ByteString m r) m Bool+isEndOfBytes = do+    x <- peekByte+    return (case x of+        Left  _ -> True+        Right _ -> False )+{-# INLINABLE isEndOfBytes #-}++{-| Take bytes until they fail the predicate++    Unlike 'takeWhile', this 'PP.unDraw's unused bytes+-}+takeWhile'+    :: (Monad m)+    => (Word8 -> Bool)+    -> Pipe ByteString ByteString (StateT (Producer ByteString m r) m) ()+takeWhile' predicate = go+  where+    go = do+        bs <- await+        let (prefix, suffix) = BS.span predicate bs+        if (BS.null suffix)+            then do+                yield bs+                go+            else do+                lift $ PP.unDraw suffix+                yield prefix+{-# INLINABLE takeWhile' #-}++{- $reexports+    @Data.ByteString@ re-exports the 'ByteString' type.++    @Data.Word@ re-exports the 'Word8' type.++    @Pipes.Parse@ re-exports 'input', 'concat', and 'FreeT' (the type).+-}