packages feed

pipes-bytestring 2.0.1 → 2.1.0

raw patch · 2 files changed

+136/−118 lines, 2 filesdep −profunctorsdep ~transformers

Dependencies removed: profunctors

Dependency ranges changed: transformers

Files

pipes-bytestring.cabal view
@@ -1,5 +1,5 @@ Name: pipes-bytestring
-Version: 2.0.1
+Version: 2.1.0
 Cabal-Version: >=1.8.0.2
 Build-Type: Simple
 License: BSD3
@@ -23,7 +23,6 @@         pipes        >= 4.0     && < 4.2 ,
         pipes-group  >= 1.0.0   && < 1.1 ,
         pipes-parse  >= 3.0.0   && < 3.1 ,
-        profunctors  >= 3.1.1   && < 4.1 ,
-        transformers >= 0.2.0.0 && < 0.4
+        transformers >= 0.2.0.0 && < 0.5
     Exposed-Modules: Pipes.ByteString
     GHC-Options: -O2 -Wall
src/Pipes/ByteString.hs view
@@ -56,6 +56,7 @@     , fromHandle
     , hGetSome
     , hGet
+    , hGetRange
 
     -- * Servers
     , hGetSomeN
@@ -69,9 +70,7 @@     , map
     , concatMap
     , take
-    , drop
     , takeWhile
-    , dropWhile
     , filter
     , elemIndices
     , findIndices
@@ -115,23 +114,27 @@     , line
 
     -- * Transforming Byte Streams
+    , drop
+    , dropWhile
     , intersperse
     , pack
+    , unpack
     , chunksOf'
 
-    -- * FreeT Splitters
+    -- * FreeT Transformations
     , chunksOf
     , splitsWith
     , splits
     , groupsBy
     , groups
     , lines
+    , unlines
     , words
+    , unwords
 
     -- * Re-exports
     -- $reexports
     , module Data.ByteString
-    , module Data.Profunctor
     , module Data.Word
     , module Pipes.Group
     , module Pipes.Parse
@@ -146,12 +149,10 @@ 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.ByteString.Unsafe (unsafeTake)
 import Data.Char (ord)
 import Data.Functor.Constant (Constant(Constant, getConstant))
 import Data.Functor.Identity (Identity)
-import Data.Profunctor (Profunctor)
-import qualified Data.Profunctor
 import qualified Data.List as List
 import Data.Word (Word8)
 import Foreign.C.Error (Errno(Errno), ePIPE)
@@ -186,6 +187,8 @@     , splitAt
     , take
     , takeWhile
+    , unlines
+    , unwords
     , words
     )
 
@@ -239,6 +242,19 @@                 go
 {-# INLINABLE hGet #-}
 
+{-| Like 'hGet' but with an extra parameter specifying an initial handle offset
+-}
+hGetRange
+    :: MonadIO m
+    => Int -- ^ Offset
+    -> Int -- ^ Size
+    -> IO.Handle
+    -> Producer' ByteString m ()
+hGetRange offset size h = do
+    liftIO $ IO.hSeek h IO.AbsoluteSeek (fromIntegral offset)
+    hGet size h
+{-# INLINABLE hGetRange #-}
+
 (^.) :: a -> ((b -> Constant b b) -> (a -> Constant b a)) -> b
 a ^. lens = getConstant (lens Constant a)
 
@@ -306,13 +322,12 @@ {-# INLINE map #-}
 
 -- | Map a function over the byte stream and concatenate the results
-concatMap
-    :: Monad m => (Word8 -> ByteString) -> Pipe ByteString ByteString m r
+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 :: (Monad m, Integral n) => n -> Pipe ByteString ByteString m ()
 take n0 = go n0 where
     go n
         | n <= 0    = return ()
@@ -326,21 +341,6 @@                     go (n - len)
 {-# INLINABLE take #-}
 
--- | @(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
-        | 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
@@ -355,18 +355,6 @@             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)
@@ -522,9 +510,9 @@ 
 -- | Index into a byte stream
 index
-    :: (Monad m, Integral a)
-    => a-> Producer ByteString m () -> m (Maybe Word8)
-index n p = head (p >-> drop n)
+    :: (Monad m, Integral n)
+    => n -> Producer ByteString m () -> m (Maybe Word8)
+index n p = head (drop n p)
 {-# INLINABLE index #-}
 
 -- | Find the index of an element that matches the given 'Word8'
@@ -622,8 +610,6 @@ 
 type Lens' a b = forall f . Functor f => (b -> f b) -> (a -> f a)
 
-type Iso' a b = forall f p . (Functor f, Profunctor p) => p b (f b) -> p a (f a)
-
 -- | Improper lens that splits a 'Producer' after the given number of bytes
 splitAt
     :: (Monad m, Integral n)
@@ -698,8 +684,8 @@ groupBy
     :: Monad m
     => (Word8 -> Word8 -> Bool)
-    -> Lens' (Producer ByteString m r)
-             (Producer ByteString m (Producer ByteString m r))
+    -> Lens' (Producer ByteString m x)
+             (Producer ByteString m (Producer ByteString m x))
 groupBy equals k p0 = fmap join (k (_groupBy p0))
   where
     -- _groupBy
@@ -718,8 +704,8 @@ -- | Like 'groupBy', where the equality predicate is ('==')
 group
     :: Monad m
-    => Lens' (Producer ByteString m r)
-             (Producer ByteString m (Producer ByteString m r))
+    => Lens' (Producer ByteString m x)
+             (Producer ByteString m (Producer ByteString m x))
 group = groupBy (==)
 {-# INLINABLE group #-}
 
@@ -729,12 +715,12 @@ 
     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.
+    this function from the @pipes-text@ library.
 -}
 word
     :: Monad m
-    => Lens' (Producer ByteString m r)
-             (Producer ByteString m (Producer ByteString m r))
+    => Lens' (Producer ByteString m x)
+             (Producer ByteString m (Producer ByteString m x))
 word k p0 = fmap join (k (to p0))
   where
     -- to
@@ -756,15 +742,33 @@ 
     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.
+    this function from the @pipes-text@ library.
 -}
 line
     :: Monad m
-    => Lens' (Producer ByteString m r)
-             (Producer ByteString m (Producer ByteString m r))
+    => Lens' (Producer ByteString m x)
+             (Producer ByteString m (Producer ByteString m x))
 line = break (== nl)
 {-# INLINABLE line #-}
 
+-- | @(drop n)@ drops the first @n@ bytes
+drop
+    :: (Monad m, Integral n)
+    => n -> Producer ByteString m r -> Producer ByteString m r
+drop n p = do
+    p' <- lift $ runEffect (for (p ^. splitAt n) discard)
+    p'
+{-# INLINABLE drop #-}
+
+-- | Drop bytes until they fail the predicate
+dropWhile
+    :: Monad m
+    => (Word8 -> Bool) -> Producer ByteString m r -> Producer ByteString m r
+dropWhile predicate p = do
+    p' <- lift $ runEffect (for (p ^. span predicate) discard)
+    p'
+{-# INLINABLE dropWhile #-}
+
 -- | Intersperse a 'Word8' in between the bytes of the byte stream
 intersperse
     :: Monad m => Word8 -> Producer ByteString m r -> Producer ByteString m r
@@ -787,20 +791,27 @@                 go1 p'
 {-# INLINABLE intersperse #-}
 
--- | Improper isomorphism between a 'Producer' of 'ByteString's and 'Word8's
-pack :: Monad m => Iso' (Producer Word8 m x) (Producer ByteString m x)
-pack = Data.Profunctor.dimap to (fmap from)
-  where
-    -- to :: Monad m => Producer Word8 m x -> Producer ByteString m x
-    to p = PG.folds step id done (p^.PG.chunksOf defaultChunkSize)
+-- | Improper lens from unpacked 'Word8's to packaged 'ByteString's
+pack :: Monad m => Lens' (Producer Word8 m x) (Producer ByteString m x)
+pack k p = fmap _unpack (k (_pack p))
+{-# INLINABLE pack #-}
 
+-- | Improper lens from packed 'ByteString's to unpacked 'Word8's
+unpack :: Monad m => Lens' (Producer ByteString m x) (Producer Word8 m x)
+unpack k p = fmap _pack (k (_unpack p))
+{-# INLINABLE unpack #-}
+
+_pack :: Monad m => Producer Word8 m x -> Producer ByteString m x
+_pack p = PG.folds step id done (p^.PG.chunksOf defaultChunkSize)
+  where
     step diffAs w8 = diffAs . (w8:)
 
     done diffAs = BS.pack (diffAs [])
+{-# INLINABLE _pack #-}
 
-    -- from :: Monad m => Producer ByteString m x -> Producer Word8 m x
-    from p = for p (each . BS.unpack)
-{-# INLINABLE pack #-}
+_unpack :: Monad m => Producer ByteString m x -> Producer Word8 m x
+_unpack p = for p (each . BS.unpack)
+{-# INLINABLE _unpack #-}
 
 {-| Group byte stream chunks into chunks of fixed length
 
@@ -821,8 +832,7 @@ -- | Split a byte stream into 'FreeT'-delimited byte streams of fixed size
 chunksOf
     :: (Monad m, Integral n)
-    => n
-    -> Lens' (Producer ByteString m x) (FreeT (Producer ByteString m) m x)
+    => n -> Lens' (Producer ByteString m x) (FreeT (Producer ByteString m) m x)
 chunksOf n k p0 = fmap concats (k (go p0))
   where
     go p = PG.FreeT $ do
@@ -904,75 +914,84 @@ groups = groupsBy (==)
 {-# INLINABLE groups #-}
 
-{-| Improper isomorphism between a bytestream and its lines
+{-| Improper lens between a bytestream and its 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.
+    this function from the @pipes-text@ library.
 -}
 lines
     :: Monad m
-    => Iso' (Producer ByteString m x) (FreeT (Producer ByteString m) m x)
-lines = Data.Profunctor.dimap _lines (fmap _unlines)
+    => Lens' (Producer ByteString m x) (FreeT (Producer ByteString m) m x)
+lines k p = fmap _unlines (k (_lines p))
+{-# INLINABLE lines #-}
+
+{-| Improper lens between lines and a bytestream
+
+    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 @pipes-text@ library.
+-}
+unlines
+    :: Monad m
+    => Lens' (FreeT (Producer ByteString m) m x) (Producer ByteString m x)
+unlines k p = fmap _lines (k (_unlines p))
+{-# INLINABLE unlines #-}
+
+_lines
+    :: Monad m => Producer ByteString m x -> FreeT (Producer ByteString m) m x
+_lines p0 = PG.FreeT (go0 p0)
   where
-    -- _lines
-    --     :: Monad m
-    --     => Producer ByteString m x -> FreeT (Producer ByteString m) m x
-    _lines p0 = PG.FreeT (go0 p0)
-      where
-        go0 p = do
-            x <- next p
+    go0 p = do
+        x <- next p
+        case x of
+            Left   r       -> return (PG.Pure r)
+            Right (bs, p') ->
+                if (BS.null bs)
+                then go0 p'
+                else return $ PG.Free $ go1 (yield bs >> p')
+    go1 p = do
+        p' <- p^.line
+        return $ PG.FreeT $ do
+            x  <- nextByte p'
             case x of
                 Left   r       -> return (PG.Pure r)
-                Right (bs, p') ->
-                    if (BS.null bs)
-                    then go0 p'
-                    else return $ PG.Free $ go1 (yield bs >> p')
-        go1 p = do
-            p' <- p^.line
-            return $ PG.FreeT $ do
-                x  <- nextByte p'
-                case x of
-                    Left   r       -> return (PG.Pure r)
-                    Right (_, p'') -> go0 p''
-
-    -- _unlines
-    --     :: Monad m
-    --      => FreeT (Producer ByteString m) m x -> Producer ByteString m x
-    _unlines = concats . PG.maps addNewline
+                Right (_, p'') -> go0 p''
+{-# INLINABLE _lines #-}
 
-    -- addNewline
-    --     :: Monad m => Producer ByteString m r -> Producer ByteString m r
+_unlines
+    :: Monad m => FreeT (Producer ByteString m) m x -> Producer ByteString m x
+_unlines = concats . PG.maps addNewline
+  where
     addNewline p = p <* yield (BS.singleton nl)
-{-# INLINABLE lines #-}
+{-# INLINABLE _unlines #-}
 
-{-| Improper isomorphism between a bytestream and its words
+{-| Convert a bytestream to 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.
+    this function from the @pipes-text@ library.
 -}
-words
-    :: Monad m
-    => Iso' (Producer ByteString m x) (FreeT (Producer ByteString m) m x)
-words = Data.Profunctor.dimap _words (fmap _unwords)
-  where
-    -- _words
-    --     :: Monad m
-    --     => Producer ByteString m x -> FreeT (Producer ByteString m) m x
-    _words p = PG.FreeT $ do
-            x <- next (p >-> dropWhile isSpaceWord8)
-            return $ case x of
-                Left   r       -> PG.Pure r
-                Right (bs, p') -> PG.Free $ do
-                    p'' <- (yield bs >> p')^.break isSpaceWord8
-                    return (_words p'')
-
-    -- _unwords
-    --     :: Monad m
-    --     => FreeT (Producer ByteString m) m x -> Producer ByteString m x
-    _unwords = PG.intercalates (yield $ BS.singleton $ fromIntegral $ ord ' ')
+words :: Monad m => Producer ByteString m x -> FreeT (Producer ByteString m) m x
+words p = PG.FreeT $ do
+    x <- next (dropWhile isSpaceWord8 p)
+    return $ case x of
+        Left   r       -> PG.Pure r
+        Right (bs, p') -> PG.Free $ do
+            p'' <- (yield bs >> p')^.break isSpaceWord8
+            return (words p'')
 {-# INLINABLE words #-}
+
+{-| Convert delimited words back to 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 @pipes-text@ library.
+-}
+unwords
+    :: Monad m => FreeT (Producer ByteString m) m x -> Producer ByteString m x
+unwords = PG.intercalates (yield $ BS.singleton $ fromIntegral $ ord ' ')
+{-# INLINABLE unwords #-}
 
 {- $parse
     The following parsing utilities are single-byte analogs of the ones found