packages feed

pipes-bytestring 1.0.1 → 1.0.2

raw patch · 3 files changed

+310/−219 lines, 3 files

Files

pipes-bytestring.cabal view
@@ -1,5 +1,5 @@ Name: pipes-bytestring-Version: 1.0.1+Version: 1.0.2 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -23,5 +23,7 @@         pipes        >= 4.0     && < 4.1 ,         pipes-parse  >= 2.0.0   && < 2.1 ,         transformers >= 0.2.0.0 && < 0.4-    Exposed-Modules: Pipes.ByteString+    Exposed-Modules:+        Pipes.ByteString,+        Pipes.ByteString.Parse     GHC-Options: -O2 -Wall
src/Pipes/ByteString.hs view
@@ -1,5 +1,10 @@-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RankNTypes, CPP #-} +-- The rewrite rules require the Trustworthy annotation+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+ {-| 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.@@ -52,91 +57,93 @@  module Pipes.ByteString (     -- * Producers-    fromLazy,-    stdin,-    fromHandle,-    hGetSome,-    hGet,+      fromLazy+    , stdin+    , fromHandle+    , hGetSome+    , hGet+    , pack      -- * Servers-    hGetSomeN,-    hGetN,+    , hGetSomeN+    , hGetN      -- * Consumers-    stdout,-    toHandle,+    , stdout+    , toHandle      -- * Pipes-    map,-    concatMap,-    take,-    drop,-    takeWhile,-    dropWhile,-    filter,-    elemIndices,-    findIndices,-    scan,+    , map+    , concatMap+    , take+    , drop+    , takeWhile+    , dropWhile+    , filter+    , elemIndices+    , findIndices+    , scan+    , unpack      -- * Folds-    toLazy,-    toLazyM,-    fold,-    head,-    last,-    null,-    length,-    any,-    all,-    maximum,-    minimum,-    elem,-    notElem,-    find,-    index,-    elemIndex,-    findIndex,-    count,+    , 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,+    , splitAt+    , chunksOf+    , span+    , break+    , splitWith+    , split+    , groupBy+    , group+    , lines+    , words      -- * Transformations-    intersperse,+    , intersperse      -- * Joiners-    intercalate,-    unlines,-    unwords,+    , intercalate+    , unlines+    , unwords      -- * Low-level Parsers     -- $parse-    nextByte,-    drawByte,-    unDrawByte,-    peekByte,-    isEndOfBytes,-    takeWhile',+    , nextByte+    , drawByte+    , unDrawByte+    , peekByte+    , isEndOfBytes+    , takeWhile'      -- * Re-exports     -- $reexports-    module Data.ByteString,-    module Data.Word,-    module Pipes.Parse+    , 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 Control.Monad.Trans.State.Strict (StateT) import qualified Data.ByteString as BS import Data.ByteString (ByteString) import Data.ByteString.Internal (isSpaceWord8)@@ -150,37 +157,42 @@ import Foreign.C.Error (Errno(Errno), ePIPE) import qualified GHC.IO.Exception as G import Pipes+import qualified Pipes.ByteString.Parse as PBP+import Pipes.ByteString.Parse (+    nextByte, drawByte, unDrawByte, peekByte, isEndOfBytes ) import Pipes.Core (respond, Server')+import Pipes.Lift (evalStateP) import qualified Pipes.Parse as PP-import Pipes.Parse (input, concat, FreeT)+import Pipes.Parse (input, concat, FreeT, isEndOfInput) 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 )+      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 ()@@ -232,6 +244,19 @@                 go {-# INLINABLE hGet #-} +-- | Convert a 'Word8' producer into a byte stream using a default chunk size+pack :: Monad m => Producer Word8 m () -> Producer ByteString m ()+pack p = evalStateP p go where+    go = do+        eof <- lift isEndOfInput+        if eof+            then return ()+            else do+                bytes <- lift $ P.toListM (P.take defaultChunkSize <-< input)+                yield $ BS.pack bytes+                go+{-# INLINABLE pack #-}+ {-| Like 'hGetSome', except you can vary the maximum chunk size for each request -} hGetSomeN :: MonadIO m => IO.Handle -> Int -> Server' Int ByteString m ()@@ -290,6 +315,10 @@ toHandle h = for cat (liftIO . BS.hPut h) {-# INLINABLE toHandle #-} +{-# RULES "p >-> toHandle h" forall p h .+        p >-> toHandle h = for p (\bs -> liftIO (BS.hPut h bs))+  #-}+ -- | 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)@@ -316,7 +345,7 @@                     go (n - len) {-# INLINABLE take #-} --- | @(dropD n)@ drops the first @n@ bytes+-- | @(drop n)@ drops the first @n@ bytes drop :: (Monad m, Integral a) => a -> Pipe ByteString ByteString m r drop n0 = go n0 where     go n@@ -391,6 +420,16 @@         go w8' {-# INLINABLE scan #-} +-- | Unpack the bytes+unpack :: Monad m => Pipe ByteString Word8 m ()+unpack = for cat (mapM_ yield . BS.unpack)+{-# INLINABLE unpack #-}++{-# RULES+    "p >-> unpack" forall p .+        p >-> unpack = for p (\bs -> mapM_ yield (BS.unpack bs))+  #-}+ {-| Fold a pure 'Producer' of strict 'ByteString's into a lazy     'BL.ByteString' -}@@ -422,9 +461,9 @@   where     go p = do         x <- nextByte p-        case x of-            Left   _      -> return  Nothing-            Right (w8, _) -> return (Just w8)+        return $ case x of+            Left   _      -> Nothing+            Right (w8, _) -> Just w8 {-# INLINABLE head #-}  -- | Retrieve the last 'Word8'@@ -436,9 +475,7 @@         case x of             Left   ()      -> return r             Right (bs, p') ->-                if (BS.null bs)-                then go r p'-                else go (Just $ BS.last bs) p'+                go (if BS.null bs then r else (Just $ BS.last bs)) p'                 -- TODO: Change this to 'unsafeLast' when bytestring-0.10.2.0                 --       becomes more widespread {-# INLINABLE last #-}@@ -560,15 +597,15 @@ chunksOf     :: (Monad m, Integral n)     => n -> Producer ByteString m r -> FreeT (Producer ByteString m) m r-chunksOf n p0 = PP.FreeT (go p0)+chunksOf n = go   where-    go p = do+    go p = PP.FreeT $ 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'')+                return (go p'') {-# INLINABLE chunksOf #-}  {-| Split a byte stream in two, where the first byte stream is the longest@@ -577,7 +614,7 @@ span     :: (Monad m)     => (Word8 -> Bool)-    -> Producer ByteString m r+    -> Producer  ByteString m  r     -> Producer' ByteString m (Producer ByteString m r) span predicate = go   where@@ -602,7 +639,7 @@ break     :: (Monad m)     => (Word8 -> Bool)-    -> Producer ByteString m r+    -> Producer ByteString m  r     -> Producer ByteString m (Producer ByteString m r) break predicate = span (not . predicate) {-# INLINABLE break #-}@@ -624,16 +661,14 @@             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'')+                else go1 (yield bs >> p')+    go1 p = return $ PP.Free $ do+        p' <- span (not . predicate) p+        return $ PP.FreeT $ do+            x <- nextByte p'+            case x of+                Left   r       -> return (PP.Pure r)+                Right (_, p'') -> go1 p'' {-# INLINABLE splitWith #-}  -- | Split a byte stream using the given 'Word8' as the delimiter@@ -641,7 +676,7 @@       => Word8       -> Producer ByteString m r       -> FreeT (Producer ByteString m) m r-split w8 = splitWith (w8 /=)+split w8 = splitWith (w8 ==) {-# INLINABLE split #-}  {-| Group a byte stream into 'FreeT'-delimited byte streams using the supplied@@ -692,12 +727,11 @@                 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  <- nextByte p-        return $ case x of-            Left   r      -> PP.Pure r-            Right (_, p') -> PP.Free (go1 p')+        return $ PP.FreeT $ do+            x  <- nextByte p'+            case x of+                Left   r       -> return (PP.Pure r)+                Right (_, p'') -> go0 p'' {-# INLINABLE lines #-}  {-| Split a byte stream into 'FreeT'-delimited words@@ -708,20 +742,15 @@ -} words     :: (Monad m) => Producer ByteString m r -> FreeT (Producer ByteString m) m r-words p0 = removeEmpty (splitWith isSpaceWord8 p0)+words = go   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')+    go p = PP.FreeT $ do+        x <- next (p >-> dropWhile isSpaceWord8)+        return $ case x of+            Left   r       -> PP.Pure r+            Right (bs, p') -> PP.Free $ do+                p'' <- break isSpaceWord8 (yield bs >> p')+                return (go p'') {-# INLINABLE words #-}  -- | Intersperse a 'Word8' in between the bytes of the byte stream@@ -809,81 +838,6 @@     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@@ -892,21 +846,14 @@     :: (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+takeWhile' = PBP.takeWhile {-# INLINABLE takeWhile' #-}+{-# DEPRECATED takeWhile' "Use Pipes.ByteString.Parse.takeWhile instead" #-}  {- $reexports+    "Pipes.ByteString.Parse" re-exports 'nextByte', 'drawByte', 'unDrawByte',+    'peekByte', and 'isEndOfBytes'.+         @Data.ByteString@ re-exports the 'ByteString' type.      @Data.Word@ re-exports the 'Word8' type.
+ src/Pipes/ByteString/Parse.hs view
@@ -0,0 +1,142 @@+-- | Parsing utilities for bytestrings, in the style of @pipes-parse@++module Pipes.ByteString.Parse (+    -- * Parsers+      nextByte+    , drawByte+    , unDrawByte+    , peekByte+    , isEndOfBytes+    , take+    , takeWhile+    ) where++import Control.Monad.Trans.State.Strict (StateT, modify)+import qualified Data.ByteString as BS+import Data.ByteString (ByteString)+import Data.ByteString.Unsafe (unsafeTake, unsafeDrop)+import Data.Word (Word8)+import Pipes+import qualified Pipes.Parse as PP++import Prelude hiding (take, takeWhile)++{-| 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 n)@ only allows @n@ bytes to pass++    Unlike @Pipes.ByteString.'Pipes.ByteString.take'@, this 'PP.unDraw's unused+    bytes+-}+take :: (Monad m, Integral a) => a -> Pipe ByteString ByteString (StateT (Producer ByteString m r) 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 do+                    let n' = fromIntegral n+                    lift . PP.unDraw $ unsafeDrop n' bs+                    yield $ unsafeTake n' bs+                else do+                    yield bs+                    go (n - len)+{-# INLINABLE take #-}++{-| Take bytes until they fail the predicate++    Unlike @Pipes.ByteString.'Pipes.ByteString.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 #-}