pipe-enumerator (empty) → 0.1.0.0
raw patch · 4 files changed
+196/−0 lines, 4 filesdep +basedep +enumeratordep +pipessetup-changed
Dependencies added: base, enumerator, pipes, transformers
Files
- LICENSE +28/−0
- Setup.hs +3/−0
- pipe-enumerator.cabal +43/−0
- src/Pipes/Enumerator.lhs +122/−0
+ LICENSE view
@@ -0,0 +1,28 @@++ Pipe/Iteratee Bridge+ ====================++ Copyright © 2015 Patryk Zadarnowski «pat@jantar.org».+ 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. ➂ The name of any+ author may not be used to endorse or promote products derived from this+ software without their specific prior written permission.++ THIS SOFTWARE IS PROVIDED “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 AUTHORS 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,3 @@+#! /usr/bin/env runhaskell+import Distribution.Simple+main = defaultMain
+ pipe-enumerator.cabal view
@@ -0,0 +1,43 @@+name: pipe-enumerator+version: 0.1.0.0+synopsis: Pipes/iteratees bridge library+homepage: https://github.com/zadarnowski/pipe-enumerator+category: Control, Pipes+stability: alpha++author: Patryk Zadarnowski+maintainer: Patryk Zadarnowski <pat@jantar.org>++copyright: Copyright (c) 2015 Patryk Zadarnowski++description:++ This library provides a bridge between pipe-based and iteratee-based programs.++cabal-version: >= 1.18+build-type: Simple+license: BSD3+license-file: LICENSE++source-repository head+ type: git+ location: https://github.com/zadarnowski/pipe-enumerator.git++source-repository this+ type: git+ location: https://github.com/zadarnowski/pipe-enumerator.git+ tag: 0.1.0.0++library+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-unused-binds++ exposed-modules:+ Pipes.Enumerator++ build-depends:+ base >= 4.8 && < 5,+ enumerator >= 0.4.20,+ pipes >= 4.1.5,+ transformers >= 0.4.2.0
+ src/Pipes/Enumerator.lhs view
@@ -0,0 +1,122 @@+> module Pipes.Enumerator (+> pipeToEnumerator+> ) where++> 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++ type Pipe a b = Proxy () a () b++ type Enumerator a m b = Step a m b -> Iteratee a m b++ data Step a m b =+ Continue (Stream a -> Iteratee a m b)+ | Yield b (Stream a)+ | Error SomeException++ newtype Iteratee a m b = Iteratee { runIteratee :: m (Step a m b) }++ data Stream a =+ Chunks [a]+ | EOF++ 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.++> 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@.++> 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+> advancePipe cs ik (P.Respond x pk) = ik (E.Chunks [x]) E.>>== advanceIteratee cs (pk ())+> 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)++> 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++> 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)+++ Final Step+ ==========++> 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+> finish _ _ (E.Error e) = E.throwError e+> finish _ _ (E.Continue _) = error "divergent iteratee" -- iteratees aren't allowed to continue on EOF+