packages feed

pipe-enumerator 0.1.0.0 → 0.2.0.0

raw patch · 2 files changed

+125/−68 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Pipes.Enumerator: fromStream :: Stream a -> Maybe [a]
+ Pipes.Enumerator: iterateeToPipe :: Monad m => Iteratee a m r -> Proxy () (Maybe a) b' b m (Either SomeException (r, Maybe [a]))
+ Pipes.Enumerator: pipeToIteratee :: Monad m => Proxy a' (Maybe a) () b m r -> Iteratee a m r
+ Pipes.Enumerator: stepToPipe :: Monad m => Step a m r -> Proxy () (Maybe a) b' b m (Either SomeException (r, Maybe [a]))
+ Pipes.Enumerator: toSingletonStream :: Maybe a -> Stream a
+ Pipes.Enumerator: toStream :: Maybe [a] -> Stream a

Files

pipe-enumerator.cabal view
@@ -1,6 +1,6 @@ name:           pipe-enumerator-version:        0.1.0.0-synopsis:       Pipes/iteratees bridge library+version:        0.2.0.0+synopsis:       A bidirectional bridge between pipes and iteratees homepage:       https://github.com/zadarnowski/pipe-enumerator category:       Control, Pipes stability:      alpha@@ -12,8 +12,16 @@  description: -    This library provides a bridge between pipe-based and iteratee-based programs.+    This library defines a set of functions that convert between+    the "Pipes" and "Data.Enumerator" paradigms. The conversion+    is bidirectional: an appropriately-typed pipe can be converted+    into an 'E.Iteratee' and back into a pipe. In addition, a pipe+    can be fed into an iteratee (or, more specifically, 'E.Step'),+    resulting in an 'E.Enumerator'. +    The library has been designed specifically for use with "Snap",+    but I'm sure that many other interesting uses of it exist.+ cabal-version:  >= 1.18 build-type:     Simple license:        BSD3@@ -26,7 +34,7 @@ source-repository this   type:         git   location:     https://github.com/zadarnowski/pipe-enumerator.git-  tag:          0.1.0.0+  tag:          0.2.0.0  library   hs-source-dirs:   src
src/Pipes/Enumerator.lhs view
@@ -1,61 +1,122 @@+> -- | Module:    Pipes.Enumerator+> -- Description: A bidirectional bridge between pipes and iteratees+> -- Copyright:   © 2015 Patryk Zadarnowski <pat@jantar.org>+> -- License:     BSD3+> -- Maintainer:  pat@jantar.org+> -- Stability:   experimental+> -- Portability: portable+> --+> -- This module defines a set of functions that convert between+> -- the "Pipes" and "Data.Enumerator" paradigms. The conversion+> -- is bidirectional: an appropriately-typed pipe can be converted+> -- into an 'E.Iteratee' and back into a pipe. In addition, a pipe+> -- can be fed into an iteratee (or, more specifically, 'E.Step'),+> -- resulting in an 'E.Enumerator'.+> --+> -- The library has been designed specifically for use with "Snap",+> -- but I'm sure that many other interesting uses of it exist.+ > module Pipes.Enumerator (+>   fromStream, toStream, toSingletonStream,+>   iterateeToPipe, stepToPipe,+>   pipeToIteratee, >   pipeToEnumerator > ) where +> import Control.Exception (SomeException) > import Control.Monad.Trans.Class > import qualified Pipes.Internal as P > import qualified Data.Enumerator as E +   Data Type Reference   =================== -    data Proxy a' a b' b m r-        = Request a' (a  -> Proxy a' a b' b m r )-        | Respond b  (b' -> Proxy a' a b' b m r )-        | M          (m    (Proxy a' a b' b m r))-        | Pure    r+  Definitions of the relevant Pipe and Iteratee types, for reference: -    type Pipe a b = Proxy () a () b+    data P.Proxy a' a b' b m r+        = P.Request a' (a  -> P.Proxy a' a b' b m r )+        | P.Respond b  (b' -> P.Proxy a' a b' b m r )+        | P.M          (m    (P.Proxy a' a b' b m r))+        | P.Pure    r -    type Enumerator a m b = Step a m b -> Iteratee a m b+    type P.Pipe a b = P.Proxy () a () b -    data Step a m b =-        Continue (Stream a -> Iteratee a m b)-      | Yield b (Stream a)-      | Error SomeException+    type E.Enumerator a m b = E.Step a m b -> E.Iteratee a m b -    newtype Iteratee a m b = Iteratee { runIteratee :: m (Step a m b) }+    data E.Step a m b =+        E.Continue (E.Stream a -> E.Iteratee a m b)+      | E.Yield b (E.Stream a)+      | E.Error SomeException -    data Stream a =-        Chunks [a]-      | EOF+    newtype E.Iteratee a m b = E.Iteratee { E.runIteratee :: m (E.Step a m b) } -  Connect a pipe to an iteratee, effectively converting it into an enumerator,-  generalised slightly to allow distinct input and output types. The chunks of-  the input stream are fed into the pipe one element at the time, and the pipe's-  output is fed to the iteratee one element per chunk. Once the input reaches-  @E.EOF@, the pipe is fed an infinite stream of @Nothing@ until it ends with-  a pure value. In effect, both the pipe and the iteratee are always consumed-  fully, with the resulting enumerator returning the results of both.+    data E.Stream a =+        E.Chunks [a]+      | E.EOF +> -- | Converts a 'E.Stream' to an optional list.+> fromStream :: E.Stream a -> Maybe [a]+> fromStream (E.Chunks cs) = Just cs+> fromStream (E.EOF)       = Nothing++> -- | Converts an optional list to a 'E.Stream'.+> toStream :: Maybe [a] -> E.Stream a+> toStream (Just cs) = E.Chunks cs+> toStream (Nothing) = E.EOF++> -- | Converts an optional value to a singleton 'E.Stream'.+> toSingletonStream :: Maybe a -> E.Stream a+> toSingletonStream (Just c)  = E.Chunks [c]+> toSingletonStream (Nothing) = E.EOF++> -- | Converts an 'E.Iteratee' into a 'P.Consumer'.+> iterateeToPipe :: Monad m => E.Iteratee a m r -> P.Proxy () (Maybe a) b' b m (Either SomeException (r, Maybe [a]))+> iterateeToPipe = P.M . fmap stepToPipe . E.runIteratee++> -- | Converts a 'E.Step' into a 'P.Consumer'.+> stepToPipe :: Monad m => E.Step a m r -> P.Proxy () (Maybe a) b' b m (Either SomeException (r, Maybe [a]))+> stepToPipe (E.Continue ik) = P.Request () (P.M . fmap stepToPipe . E.runIteratee . ik . toSingletonStream)+> stepToPipe (E.Yield r xs)  = return (Right (r, fromStream xs))+> stepToPipe (E.Error e)     = return (Left e)++> -- | Converts a 'P.Pipe' into an 'E.Iteratee'.+> --   Any output of the pipe is quietly discarded.+> pipeToIteratee :: Monad m => P.Proxy a' (Maybe a) () b m r -> E.Iteratee a m r+> pipeToIteratee = convert1 []+>  where+>   convert1 cs (P.Request _ pk)    = convert2 pk cs+>   convert1 cs (P.Respond _ pk)    = convert1 cs (pk ())+>   convert1 cs (P.M m)             = lift m >>= convert1 cs+>   convert1 cs (P.Pure r)          = E.yield r (E.Chunks cs)+>   convert2 pk (c:cs)              = convert1 cs (pk (Just c))+>   convert2 pk []                  = E.continue (convert3 pk)+>   convert3 pk (E.Chunks cs)       = convert2 pk cs+>   convert3 pk (E.EOF)             = convert4 pk+>   convert4 pk                     = convert5 (pk Nothing)+>   convert5 (P.Request _ pk)       = convert4 pk+>   convert5 (P.Respond _ pk)       = convert5 (pk ())+>   convert5 (P.M m)                = lift m >>= convert5+>   convert5 (P.Pure r)             = E.yield r E.EOF++> -- | Feed the output of a 'P.Pipe' to a 'E.Step', effectively converting it into+> --   an 'E.Enumerator',  generalised slightly to allow distinct input and output+> --   types.  The chunks of the input stream are fed into the pipe one element at+> --   the time, and the pipe's  output is fed to the iteratee one element per chunk.+> --   Once the input reaches 'E.EOF', the pipe is fed an infinite stream of 'Nothing'+> --   until it ends with  a pure value. In effect, both the pipe and the iteratee are+> --   always consumed fully, with the resulting enumerator returning the results of both. > pipeToEnumerator :: Monad m => P.Proxy a' (Maybe a) () b m q -> E.Step b m r -> E.Iteratee a m (q, r) > pipeToEnumerator = advanceIteratee [] >  where -    State Machine 1-    ===============--    Advance a single iteratee step, keeping track of any input @cs@ that has been-    supplied by the upstream enumerator but not yet used. If the target iteratee blocks,-    we will supply it with input obtained by advancing source pipe; otherwise, we'll-    simply drain the pipe to completion, in order to retrieve the remainder of the-    upstream input and the pipe's return value:- >   advanceIteratee :: Monad m => [a] -> P.Proxy a' (Maybe a) () b m q -> E.Step b m r -> E.Iteratee a m (q, r) >   advanceIteratee cs p (E.Continue ik)      = advancePipe cs ik p >   advanceIteratee cs p s                    = drainPipe cs s p -    Advance a pipe, feeding its response into a blocked iteratee @ik@.+>   advanceIteratee' :: Monad m => P.Proxy a' (Maybe a) () b m q -> E.Step b m r -> E.Iteratee a m (q, r)+>   advanceIteratee' p (E.Continue ik)        = advancePipe' ik p+>   advanceIteratee' p s                      = drainPipe' s p  >   advancePipe :: Monad m => [a] -> (E.Stream b -> E.Iteratee b m r) -> P.Proxy a' (Maybe a) () b m q -> E.Iteratee a m (q, r) >   advancePipe cs ik (P.Request _ pk)        = advancePipeWithChunks ik pk cs@@ -63,57 +124,45 @@ >   advancePipe cs ik (P.M m)                 = lift m >>= advancePipe cs ik >   advancePipe cs ik (P.Pure q)              = ik (E.EOF) E.>>== finish q (E.Chunks cs) ->   advancePipeWithChunks :: Monad m => (E.Stream b -> E.Iteratee b m r) -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> [a] -> E.Iteratee a m (q, r)->   advancePipeWithChunks ik pk (c:cs)        = advancePipe cs ik (pk (Just c))->   advancePipeWithChunks ik pk []            = E.continue (advancePipeWithStream ik pk)+>   advancePipe' :: Monad m => (E.Stream b -> E.Iteratee b m r) -> P.Proxy a' (Maybe a) () b m q -> E.Iteratee a m (q, r)+>   advancePipe' ik (P.Request _ pk)          = advancePipeWithEOF ik pk+>   advancePipe' ik (P.Respond x pk)          = ik (E.Chunks [x]) E.>>== advanceIteratee' (pk ())+>   advancePipe' ik (P.M m)                   = lift m >>= advancePipe' ik+>   advancePipe' ik (P.Pure q)                = ik (E.EOF) E.>>== finish q (E.EOF)  >   advancePipeWithStream :: Monad m => (E.Stream b -> E.Iteratee b m r) -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> E.Stream a -> E.Iteratee a m (q, r) >   advancePipeWithStream ik pk (E.Chunks cs) = advancePipeWithChunks ik pk cs >   advancePipeWithStream ik pk (E.EOF)       = advancePipeWithEOF ik pk +>   advancePipeWithChunks :: Monad m => (E.Stream b -> E.Iteratee b m r) -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> [a] -> E.Iteratee a m (q, r)+>   advancePipeWithChunks ik pk (c:cs)        = advancePipe cs ik (pk (Just c))+>   advancePipeWithChunks ik pk []            = E.continue (advancePipeWithStream ik pk)++>   advancePipeWithEOF :: Monad m => (E.Stream b -> E.Iteratee b m r) -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> E.Iteratee a m (q, r)+>   advancePipeWithEOF ik pk                  = advancePipe' ik (pk Nothing)+ >   drainPipe :: Monad m => [a] -> E.Step b m r -> P.Proxy a' (Maybe a) () b m q -> E.Iteratee a m (q, r) >   drainPipe cs s (P.Request _ pk)           = drainPipeWithChunks s pk cs >   drainPipe cs s (P.Respond _ pk)           = drainPipe cs s (pk ()) >   drainPipe cs s (P.M m)                    = lift m >>= drainPipe cs s >   drainPipe cs s (P.Pure q)                 = finish q (E.Chunks cs) s ->   drainPipeWithChunks :: Monad m => E.Step b m r -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> [a] -> E.Iteratee a m (q, r)->   drainPipeWithChunks s pk (c:cs)           = drainPipe cs s (pk (Just c))->   drainPipeWithChunks s pk []               = E.continue (drainPipeWithStream s pk)-->   drainPipeWithStream :: Monad m => E.Step b m r -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> E.Stream a -> E.Iteratee a m (q, r)->   drainPipeWithStream s pk (E.Chunks cs)    = drainPipeWithChunks s pk cs->   drainPipeWithStream s pk (E.EOF)          = drainPipeWithEOF s pk---    State Machine 2-    ===============-->   advanceIteratee' :: Monad m => P.Proxy a' (Maybe a) () b m q -> E.Step b m r -> E.Iteratee a m (q, r)->   advanceIteratee' p (E.Continue ik)        = advancePipe' ik p->   advanceIteratee' p s                      = drainPipe' s p-->   advancePipe' :: Monad m => (E.Stream b -> E.Iteratee b m r) -> P.Proxy a' (Maybe a) () b m q -> E.Iteratee a m (q, r)->   advancePipe' ik (P.Request _ pk)          = advancePipeWithEOF ik pk->   advancePipe' ik (P.Respond x pk)          = ik (E.Chunks [x]) E.>>== advanceIteratee' (pk ())->   advancePipe' ik (P.M m)                   = lift m >>= advancePipe' ik->   advancePipe' ik (P.Pure q)                = ik (E.EOF) E.>>== finish q (E.EOF)-->   advancePipeWithEOF :: Monad m => (E.Stream b -> E.Iteratee b m r) -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> E.Iteratee a m (q, r)->   advancePipeWithEOF ik pk                  = advancePipe' ik (pk Nothing)- >   drainPipe' :: Monad m => E.Step b m r -> P.Proxy a' (Maybe a) () b m q -> E.Iteratee a m (q, r) >   drainPipe' s (P.Request _ pk)             = drainPipeWithEOF s pk >   drainPipe' s (P.Respond _ pk)             = drainPipe' s (pk ()) >   drainPipe' s (P.M m)                      = lift m >>= drainPipe' s >   drainPipe' s (P.Pure q)                   = finish q (E.EOF) s ->   drainPipeWithEOF :: Monad m => E.Step b m r -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> E.Iteratee a m (q, r)->   drainPipeWithEOF s pk                     = drainPipe' s (pk Nothing)+>   drainPipeWithStream :: Monad m => E.Step b m r -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> E.Stream a -> E.Iteratee a m (q, r)+>   drainPipeWithStream s pk (E.Chunks cs)    = drainPipeWithChunks s pk cs+>   drainPipeWithStream s pk (E.EOF)          = drainPipeWithEOF s pk +>   drainPipeWithChunks :: Monad m => E.Step b m r -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> [a] -> E.Iteratee a m (q, r)+>   drainPipeWithChunks s pk (c:cs)           = drainPipe cs s (pk (Just c))+>   drainPipeWithChunks s pk []               = E.continue (drainPipeWithStream s pk) -    Final Step-    ==========+>   drainPipeWithEOF :: Monad m => E.Step b m r -> (Maybe a -> P.Proxy a' (Maybe a) () b m q) -> E.Iteratee a m (q, r)+>   drainPipeWithEOF s pk                     = drainPipe' s (pk Nothing)  >   finish :: Monad m => q -> E.Stream a -> E.Step b m r -> E.Iteratee a m (q, r) >   finish q xs (E.Yield r _)                 = E.yield (q, r) xs