packages feed

enumerator 0.4.7 → 0.4.8

raw patch · 37 files changed

+4949/−3275 lines, 37 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Enumerator: instance (Typeable a, Typeable1 m) => Typeable1 (Step a m)
+ Data.Enumerator: instance Typeable1 Stream
+ Data.Enumerator.Binary: concatMap :: Monad m => (Word8 -> ByteString) -> Enumeratee ByteString ByteString m b
+ Data.Enumerator.Binary: concatMapM :: Monad m => (Word8 -> m ByteString) -> Enumeratee ByteString ByteString m b
+ Data.Enumerator.Binary: enumFileRange :: FilePath -> Maybe Integer -> Maybe Integer -> Enumerator ByteString IO b
+ Data.Enumerator.Binary: enumHandleRange :: MonadIO m => Integer -> Maybe Integer -> Maybe Integer -> Handle -> Enumerator ByteString m b
+ Data.Enumerator.Binary: filter :: Monad m => (Word8 -> Bool) -> Enumeratee ByteString ByteString m b
+ Data.Enumerator.Binary: filterM :: Monad m => (Word8 -> m Bool) -> Enumeratee ByteString ByteString m b
+ Data.Enumerator.Binary: fold :: Monad m => (b -> Word8 -> b) -> b -> Iteratee ByteString m b
+ Data.Enumerator.Binary: foldM :: Monad m => (b -> Word8 -> m b) -> b -> Iteratee ByteString m b
+ Data.Enumerator.Binary: generateM :: Monad m => m (Maybe Word8) -> Enumerator ByteString m b
+ Data.Enumerator.Binary: iterate :: Monad m => (Word8 -> Word8) -> Word8 -> Enumerator ByteString m b
+ Data.Enumerator.Binary: iterateM :: Monad m => (Word8 -> m Word8) -> Word8 -> Enumerator ByteString m b
+ Data.Enumerator.Binary: map :: Monad m => (Word8 -> Word8) -> Enumeratee ByteString ByteString m b
+ Data.Enumerator.Binary: mapM :: Monad m => (Word8 -> m Word8) -> Enumeratee ByteString ByteString m b
+ Data.Enumerator.Binary: repeat :: Monad m => Word8 -> Enumerator ByteString m b
+ Data.Enumerator.Binary: repeatM :: Monad m => m Word8 -> Enumerator ByteString m b
+ Data.Enumerator.Binary: replicate :: Monad m => Integer -> Word8 -> Enumerator ByteString m b
+ Data.Enumerator.Binary: replicateM :: Monad m => Integer -> m Word8 -> Enumerator ByteString m b
+ Data.Enumerator.Binary: splitWhen :: Monad m => (Word8 -> Bool) -> Enumeratee ByteString ByteString m b
+ Data.Enumerator.Binary: unfold :: Monad m => (s -> Maybe (Word8, s)) -> s -> Enumerator ByteString m b
+ Data.Enumerator.Binary: unfoldM :: Monad m => (s -> m (Maybe (Word8, s))) -> s -> Enumerator ByteString m b
+ Data.Enumerator.List: concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b
+ Data.Enumerator.List: concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b
+ Data.Enumerator.List: filter :: Monad m => (a -> Bool) -> Enumeratee a a m b
+ Data.Enumerator.List: filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b
+ Data.Enumerator.List: fold :: Monad m => (b -> a -> b) -> b -> Iteratee a m b
+ Data.Enumerator.List: foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b
+ Data.Enumerator.List: generateM :: Monad m => m (Maybe a) -> Enumerator a m b
+ Data.Enumerator.List: iterate :: Monad m => (a -> a) -> a -> Enumerator a m b
+ Data.Enumerator.List: iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b
+ Data.Enumerator.List: map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b
+ Data.Enumerator.List: mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b
+ Data.Enumerator.List: repeat :: Monad m => a -> Enumerator a m b
+ Data.Enumerator.List: repeatM :: Monad m => m a -> Enumerator a m b
+ Data.Enumerator.List: replicate :: Monad m => Integer -> a -> Enumerator a m b
+ Data.Enumerator.List: replicateM :: Monad m => Integer -> m a -> Enumerator a m b
+ Data.Enumerator.List: splitWhen :: Monad m => (a -> Bool) -> Enumeratee a [a] m b
+ Data.Enumerator.List: unfold :: Monad m => (s -> Maybe (a, s)) -> s -> Enumerator a m b
+ Data.Enumerator.List: unfoldM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Enumerator a m b
+ Data.Enumerator.Text: concatMap :: Monad m => (Char -> Text) -> Enumeratee Text Text m b
+ Data.Enumerator.Text: concatMapM :: Monad m => (Char -> m Text) -> Enumeratee Text Text m b
+ Data.Enumerator.Text: filter :: Monad m => (Char -> Bool) -> Enumeratee Text Text m b
+ Data.Enumerator.Text: filterM :: Monad m => (Char -> m Bool) -> Enumeratee Text Text m b
+ Data.Enumerator.Text: fold :: Monad m => (b -> Char -> b) -> b -> Iteratee Text m b
+ Data.Enumerator.Text: foldM :: Monad m => (b -> Char -> m b) -> b -> Iteratee Text m b
+ Data.Enumerator.Text: generateM :: Monad m => m (Maybe Char) -> Enumerator Text m b
+ Data.Enumerator.Text: iterate :: Monad m => (Char -> Char) -> Char -> Enumerator Text m b
+ Data.Enumerator.Text: iterateM :: Monad m => (Char -> m Char) -> Char -> Enumerator Text m b
+ Data.Enumerator.Text: lines :: Monad m => Enumeratee Text Text m b
+ Data.Enumerator.Text: map :: Monad m => (Char -> Char) -> Enumeratee Text Text m b
+ Data.Enumerator.Text: mapM :: Monad m => (Char -> m Char) -> Enumeratee Text Text m b
+ Data.Enumerator.Text: repeat :: Monad m => Char -> Enumerator Text m b
+ Data.Enumerator.Text: repeatM :: Monad m => m Char -> Enumerator Text m b
+ Data.Enumerator.Text: replicate :: Monad m => Integer -> Char -> Enumerator Text m b
+ Data.Enumerator.Text: replicateM :: Monad m => Integer -> m Char -> Enumerator Text m b
+ Data.Enumerator.Text: splitWhen :: Monad m => (Char -> Bool) -> Enumeratee Text Text m b
+ Data.Enumerator.Text: unfold :: Monad m => (s -> Maybe (Char, s)) -> s -> Enumerator Text m b
+ Data.Enumerator.Text: unfoldM :: Monad m => (s -> m (Maybe (Char, s))) -> s -> Enumerator Text m b

Files

enumerator.cabal view
@@ -1,5 +1,5 @@ name: enumerator-version: 0.4.7+version: 0.4.8 synopsis: Reliable, high-performance processing with left-fold enumerators license: MIT license-file: license.txt@@ -57,21 +57,28 @@   readme.txt   --   src/api-docs.anansi-  src/binary.anansi-  src/compat.anansi+  src/compatibility.anansi   src/enumerator.anansi-  src/list.anansi+  src/io.anansi+  src/list-analogues.anansi   src/primitives.anansi-  src/text.anansi+  src/public-interface.anansi+  src/summary.anansi+  src/text-codecs.anansi   src/types.anansi-  src/util.anansi+  src/utilities.anansi   --   examples/cat.hs   examples/wc.hs   ---  scripts/cabal-dist+  scripts/common.bash+  scripts/dist+  scripts/haddock+  scripts/latex+  scripts/run-benchmarks   scripts/run-tests   --+  tests/Benchmarks.hs   tests/enumerator-tests.cabal   tests/Properties.hs 
examples/cat.hs view
@@ -8,99 +8,10 @@ -- ----------------------------------------------------------------------------- module Main (main) where-import Prelude as Prelude-import Control.Exception as E-import Control.Monad.IO.Class (liftIO) import Data.Enumerator-import qualified Data.ByteString as B-import qualified Foreign as F-import System.IO-import System.IO.Error (isEOFError)+import Data.Enumerator.Binary (enumFile, enumHandle, iterHandle)+import System.IO (stdin, stdout) import System.Environment (getArgs)---- The following definitions of 'enumHandle', 'enumFile', and 'iterHandle' are--- copied from "Data.Enumerator.Binary", with additional comments so they're--- easier to understand.--enumHandle :: Integer -- ^ Buffer size-           -> Handle-           -> Enumerator B.ByteString IO b-enumHandle bufferSize h = loop where-	intSize = fromInteger bufferSize-	-	-- If more input is required before the enumerator's iteratee can-	-- yield a result, feed it from the handle.-	loop (Continue k) = do-		-- While not strictly necessary to proper operation, catching-		-- exceptions here allows more unified exception handling when-		-- the enumerator/iteratee is run.-		eitherBytes <- liftIO $ E.try $ do-			-			-- The enumerator must function normally when the-			-- handle is something like a slow file, or network-			-- socket; if there's not enough data to fill the-			-- buffer yet, a partial read is returned.-			hasInput <- E.catch-				(hWaitForInput h (1))-				(\err -> if isEOFError err-					then return False-					else E.throwIO err)-			-			-- An EOF is represented by the empty bytestring-			if hasInput-				then B.hGetNonBlocking h intSize-				else return B.empty-			-		case eitherBytes of-			-- Interacting with the socket threw an IO error of-			-- some sort-			Left err -> throwError (err :: E.SomeException)-			-			-- The socket has reached EOF; pass control to the-			-- next enumerator-			Right bytes | B.null bytes -> continue k-			-			-- Bytes were read successfully; feed them to the-			-- iteratee and continue looping-			Right bytes -> k (Chunks [bytes]) >>== loop-	-	-- If a different step is received ('Error' or 'Yield'), just pass-	-- it through.-	loop step = returnI step--enumFile :: FilePath -> Enumerator B.ByteString IO b-enumFile path s = do-	-- Opening the file can be performed either inside or outside of the-	-- Iteratee. Inside allows exceptions to be caught and propagated-	-- through the 'Error' step constructor.-	eitherH <- liftIO (E.try (openBinaryFile path ReadMode))-	case eitherH of-		Left err -> throwError (err :: E.SomeException)-		Right h -> Iteratee $ finally-			(runIteratee (enumHandle 4096 h s))-			(hClose h)---- 'iterHandle' is the opposite of 'enumHandle', in that it *writes to* a--- handle instead of reading from it. An enumerator is a source, an iteratee--- is a sink.-iterHandle :: Handle -> Iteratee B.ByteString IO ()---- Most iteratees start in the 'Continue' state, as they need some--- input before they can produce any value.-iterHandle h = continue step where-	-	-- This iteratee produces no value; its only purpose is its-	-- side-effects. When 'EOF' is received, it simply yields ().-	step EOF = yield () EOF-	-	-- When some chunks are received from the Enumeratee, they're written-	-- to the handle. Any exceptions are caught and reported, as in-	-- 'enumHandle'.-	step (Chunks bytes) = do-		eitherErr <- liftIO (E.try (mapM_ (B.hPut h) bytes))-		case eitherErr of-			Left err -> throwError (err :: E.SomeException)-			_ -> continue step  main :: IO () main = do
examples/wc.hs view
@@ -12,12 +12,8 @@ import qualified Data.Enumerator.Binary as EB import qualified Data.Enumerator.Text as ET import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as B8-import qualified Data.Text as T  -- support imports-import Control.Exception as E-import Data.List import Control.Monad (unless, forM_) import System.IO import System.Console.GetOpt@@ -27,23 +23,17 @@ -- support wc modes -c (bytes), -m (characters), and -l (lines)  -- iterBytes simply counts how many bytes are in each chunk, accumulates this--- count, and returns it when EOF is received+-- count, and returns it when EOF is received.  iterBytes :: Monad m => Iteratee B.ByteString m Integer-iterBytes = continue (step 0) where-	step acc EOF = yield acc EOF-	step acc (Chunks xs) = continue $ step $! Data.List.foldl' foldStep acc xs-	foldStep acc bytes = acc + toInteger (B.length bytes)+iterBytes = EB.fold (\acc _ -> acc + 1) 0  -- iterLines is similar, except it only counts newlines ('\n')------ Because it's basically the same as 'iterBytes', we use it to demonstrate--- the 'liftFoldL\'' helper function.  iterLines :: Monad m => Iteratee B.ByteString m Integer-iterLines = E.foldl' step 0 where-	step acc bytes = acc + countChar '\n' bytes-	countChar c = B8.foldl (\acc c' -> if c' == c then acc + 1 else acc) 0+iterLines = EB.fold step 0 where+	step acc 0xA = acc + 1+	step acc _ = acc  -- iterChars is a bit more complicated. It has to decode the input (for now, -- assuming UTF-8) before performing any counting. Leftover bytes, not part@@ -55,7 +45,7 @@  iterChars :: Monad m => Iteratee B.ByteString m Integer iterChars = joinI (ET.decode ET.utf8 $$ count) where-	count = E.foldl' (\acc t -> acc + toInteger (T.length t)) 0+	count = ET.fold (\acc _ -> acc + 1) 0  main :: IO () main = do@@ -72,7 +62,6 @@ 	forM_ files $ \filename -> do 		putStr $ filename ++ ": " 		-		-- see cat.hs for commented implementation of 'Data.Enumerator.IO.enumFile' 		eitherStat <- run (EB.enumFile filename $$ iter) 		putStrLn $ case eitherStat of 			Left err -> "ERROR: " ++ show err
hs/Data/Enumerator.hs view
@@ -21,129 +21,104 @@  module Data.Enumerator ( -	-- * Core-	-- ** Types+	-- * Types 	  Stream (..) 	, Iteratee (..) 	, Step (..) 	, Enumerator 	, Enumeratee-+	+	-- * Primitives 	, returnI-	, yield 	, continue-+	, yield+	 	-- ** Operators 	, (>>==) 	, (==<<) 	, ($$) 	, (>==>) 	, (<==<)--	-- * Primitives-+	+	-- ** Running iteratees+	, run+	, run_+	 	-- ** Error handling 	, throwError 	, catchError--	-- ** Iteratees-	, Data.Enumerator.foldl-	, Data.Enumerator.foldl'-	, Data.Enumerator.foldM--	-- ** Enumerators-	, Data.Enumerator.iterate-	, iterateM-	, Data.Enumerator.repeat-	, repeatM-	, Data.Enumerator.replicate-	, replicateM-	, generateM--	-- ** Enumeratees-	, Data.Enumerator.map-	, Data.Enumerator.concatMap-	, Data.Enumerator.filter-	, Data.Enumerator.mapM-	, concatMapM-	, Data.Enumerator.filterM--	-- ** Debugging-	, printChunks--	-- * Misc. utilities-+	+	-- * Miscellaneous 	, concatEnums- 	, joinI 	, joinE 	, Data.Enumerator.sequence-	, enumList- 	, enumEOF-	, run-	, run_--	, checkDone 	, checkDoneEx-+	, checkDone 	, isEOF--	-- * Compatibility--	-- ** Obsolete functions+	+	-- ** Testing and debugging+	, printChunks+	, enumList+	+	-- * Legacy compatibility+	+	-- ** Obsolete 	, liftTrans 	, liftI 	, peek 	, Data.Enumerator.last 	, Data.Enumerator.length--	-- ** Deprecated aliases+	+	-- ** Aliases 	, Data.Enumerator.head 	, Data.Enumerator.drop 	, Data.Enumerator.dropWhile 	, Data.Enumerator.span 	, Data.Enumerator.break-	, Data.Enumerator.consume-+	, consume+	, Data.Enumerator.foldl+	, Data.Enumerator.foldl'+	, foldM+	, Data.Enumerator.iterate+	, iterateM+	, Data.Enumerator.repeat+	, repeatM+	, Data.Enumerator.replicate+	, replicateM+	, generateM+	, Data.Enumerator.map+	, Data.Enumerator.mapM+	, Data.Enumerator.concatMap+	, concatMapM+	, Data.Enumerator.filter+	, filterM 	, liftFoldL 	, liftFoldL' 	, liftFoldM  	) where -import qualified Prelude as Prelude-import Prelude hiding (--	concatMap,--	)--import Data.Monoid (Monoid, mempty, mappend, mconcat)--import qualified Control.Exception as Exc--import Data.Function (fix)--import Control.Monad.Trans.Class (MonadTrans, lift)-import Control.Monad.IO.Class (MonadIO, liftIO)--import qualified Control.Applicative as A-import qualified Control.Monad as CM- import Data.Typeable ( Typeable, typeOf                      , Typeable1, typeOf1                      , mkTyConApp, mkTyCon) -import Data.List (foldl')- import Data.List (genericSplitAt) +import qualified Control.Exception as Exc+import Data.Monoid (Monoid, mempty, mappend, mconcat)+import Control.Monad.Trans.Class (MonadTrans, lift)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Applicative as A+import qualified Control.Monad as CM+import Data.Function (fix)+import {-# SOURCE #-} qualified Data.Enumerator.List as EL import Data.List (genericLength) -import {-# SOURCE #-} qualified Data.Enumerator.List as EL  + -- | A 'Stream' is a sequence of chunks generated by an 'Enumerator'. -- -- @('Chunks' [])@ is used to indicate that a stream is still active, but@@ -159,15 +134,6 @@ 	Chunks xs >>= f = mconcat (fmap f xs) 	EOF >>= _ = EOF -instance Functor Stream where-	fmap f (Chunks xs) = Chunks (fmap f xs)-	fmap _ EOF = EOF---- | Since: 0.4.5-instance A.Applicative Stream where-	pure = return-	(<*>) = CM.ap- instance Monoid (Stream a) where 	mempty = Chunks mempty 	mappend (Chunks xs) (Chunks ys) = Chunks (xs ++ ys)@@ -209,24 +175,26 @@ 	{ runIteratee :: m (Step a m b) 	} ---- | @returnI step = 'Iteratee' (return step)@--returnI :: Monad m => Step a m b -> Iteratee a m b-returnI step = Iteratee (return step)----- | @yield x extra = 'returnI' ('Yield' x extra)@--yield :: Monad m => b -> Stream a -> Iteratee a m b-yield x extra = returnI (Yield x extra)+instance Monad m => Monad (Iteratee a m) where+	return x = yield x (Chunks []) +	m0 >>= f = ($ m0) $ fix $+		\bind m -> Iteratee $ runIteratee m >>= \r1 ->+			case r1 of+				Continue k -> return (Continue (bind . k))+				Error err -> return (Error err)+				Yield x (Chunks []) -> runIteratee (f x)+				Yield x extra -> runIteratee (f x) >>= \r2 ->+					case r2 of+						Continue k -> runIteratee (k extra)+						Error err -> return (Error err)+						Yield x' _ -> return (Yield x' extra) --- | @continue k = 'returnI' ('Continue' k)@+instance MonadTrans (Iteratee a) where+	lift m = Iteratee (m >>= runIteratee . return) -continue :: Monad m => (Stream a -> Iteratee a m b)-         -> Iteratee a m b-continue k = returnI (Continue k)+instance MonadIO m => MonadIO (Iteratee a m) where+	liftIO = lift . liftIO   -- | While 'Iteratee's consume data, enumerators generate it. Since@@ -246,117 +214,108 @@ -- type is named an 'Enumeratee'. Enumeratees have two input types, -- &#x201c;outer a&#x201d; (@aOut@) and &#x201c;inner a&#x201d; (@aIn@). -type Enumeratee ao ai m b = Step ai m b-          -> Iteratee ao m (Step ai m b)+type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b) -infixl 1 >>== +-- | Since: 0.4.8+instance Typeable1 Stream where+	typeOf1 _ = mkTyConApp tyCon [] where+		tyCon = mkTyCon "Data.Enumerator.Stream" --- | Equivalent to '(>>=)' for @m ('Step' a m b)@; allows 'Iteratee's with--- different input types to be composed.+-- | Since: 0.4.6+instance (Typeable a, Typeable1 m) =>+	Typeable1 (Iteratee a m) where+		typeOf1 i = let+			tyCon = mkTyCon "Data.Enumerator.Iteratee"+			(a, m) = peel i+			+			peel :: Iteratee a m b -> (a, m ())+			peel = undefined+			+			in mkTyConApp tyCon [typeOf a, typeOf1 m] -(>>==) :: Monad m-       => Iteratee a m b-       -> (Step a m b -> Iteratee a' m b')-       -> Iteratee a' m b'-i >>== f = Iteratee (runIteratee i >>= runIteratee . f)+-- | Since: 0.4.8+instance (Typeable a, Typeable1 m) =>+	Typeable1 (Step a m) where+		typeOf1 s = let+			tyCon = mkTyCon "Data.Enumerator.Step"+			(a, m) = peel s+			+			peel :: Step a m b -> (a, m ())+			peel = undefined+			+			in mkTyConApp tyCon [typeOf a, typeOf1 m] -infixr 1 ==<<+instance Monad m => Functor (Iteratee a m) where+	fmap = CM.liftM +instance Monad m => A.Applicative (Iteratee a m) where+	pure = return+	(<*>) = CM.ap --- | @(==\<\<) = flip (\>\>==)@+instance Functor Stream where+	fmap f (Chunks xs) = Chunks (fmap f xs)+	fmap _ EOF = EOF -(==<<) :: Monad m-       => (Step a m b -> Iteratee a' m b')-       -> Iteratee a m b-       -> Iteratee a' m b'-(==<<) = flip (>>==)+-- | Since: 0.4.5+instance A.Applicative Stream where+	pure = return+	(<*>) = CM.ap -infixr 0 $$  --- | @($$) = (==\<\<)@------ This might be easier to read when passing a chain of iteratees to an--- enumerator.------ Since: 0.1.1--($$) :: Monad m-     => (Step a m b -> Iteratee a' m b')-     -> Iteratee a m b-     -> Iteratee a' m b'-($$) = (==<<)+-- | @'returnI' step = 'Iteratee' (return step)@ -infixr 1 >==>+returnI :: Monad m => Step a m b -> Iteratee a m b+returnI step = Iteratee (return step)  --- | @(>==>) e1 e2 s = e1 s >>== e2@+-- | @'yield' x extra = 'returnI' ('Yield' x extra)@ ----- Since: 0.1.1+-- WARNING: due to the current encoding of iteratees in this library,+-- careless use of the 'yield' primitive may violate the monad laws.+-- To prevent this, always make sure that an iteratee never yields+-- extra data unless it has received at least one input element.+--+-- More strictly, iteratees may not yield data that they did not+-- receive as input. Don't use 'yield' to &#x201c;inject&#x201d; elements+-- into the stream. -(>==>) :: Monad m-       => Enumerator a m b-       -> (Step a m b -> Iteratee a' m b')-       -> Step a m b-       -> Iteratee a' m b'-(>==>) e1 e2 s = e1 s >>== e2+yield :: Monad m => b -> Stream a -> Iteratee a m b+yield x extra = returnI (Yield x extra) -infixr 1 <==< +-- | @'continue' k = 'returnI' ('Continue' k)@ --- | @(\<==\<) = flip (>==>)@------ Since: 0.1.1+continue :: Monad m => (Stream a -> Iteratee a m b) -> Iteratee a m b+continue k = returnI (Continue k) -(<==<) :: Monad m-       => (Step a m b -> Iteratee a' m b')-       -> Enumerator a m b-       -> Step a m b-       -> Iteratee a' m b'-(<==<) = flip (>==>) -instance Monad m => Monad (Iteratee a m) where-	return x = yield x (Chunks [])-	-	m0 >>= f = ($ m0) $ fix $ \bind m -> Iteratee $ runIteratee m >>=-		\r1 -> case r1 of-			Continue k -> return (Continue (bind . k))-			Error err -> return (Error err)-			Yield x (Chunks []) -> runIteratee (f x)-			Yield x extra -> runIteratee (f x) >>=-				\r2 -> case r2 of-					Continue k -> runIteratee (k extra)-					Error err -> return (Error err)-					Yield x' _ -> return (Yield x' extra)+-- | Run an iteratee until it finishes, and return either the final value+-- (if it succeeded) or the error (if it failed). -instance MonadTrans (Iteratee a) where-	lift m = Iteratee (m >>= runIteratee . return)+run :: Monad m => Iteratee a m b+    -> m (Either Exc.SomeException b)+run i = do+	mStep <- runIteratee $ enumEOF ==<< i+	case mStep of+		Error err -> return $ Left err+		Yield x _ -> return $ Right x+		Continue _ -> error "run: divergent iteratee" -instance MonadIO m => MonadIO (Iteratee a m) where-	liftIO = lift . liftIO -instance Monad m => Functor (Iteratee a m) where-	fmap = CM.liftM--instance Monad m => A.Applicative (Iteratee a m) where-	pure = return-	(<*>) = CM.ap+-- | Like 'run', except errors are converted to exceptions and thrown.+-- Primarily useful for small scripts or other simple cases.+--+-- Since: 0.4.1 --- | Since: 0.4.6-instance (Typeable a, Typeable1 m) => Typeable1 (Iteratee a m) where-	typeOf1 i = mkTyConApp tyCon [typeOf a, typeOf1 m] where-		tyCon = mkTyCon "Data.Enumerator.Iteratee"-		(a, m) = peel i-		-		peel :: Iteratee a m b -> (a, m ())-		peel = undefined+run_ :: Monad m => Iteratee a m b -> m b+run_ i = run i >>= either Exc.throw return  --- | @throwError exc = 'returnI' ('Error' ('Exc.toException' exc))@+-- | @'throwError' exc = 'returnI' ('Error' ('Exc.toException' exc))@ -throwError :: (Monad m, Exc.Exception e) => e-           -> Iteratee a m b+throwError :: (Monad m, Exc.Exception e) => e -> Iteratee a m b throwError exc = returnI (Error (Exc.toException exc))  @@ -367,7 +326,8 @@ -- -- Since: 0.1.1 -catchError :: Monad m => Iteratee a m b+catchError :: Monad m+           => Iteratee a m b            -> (Exc.SomeException -> Iteratee a m b)            -> Iteratee a m b catchError iter h = iter >>== step where@@ -376,202 +336,71 @@ 	step (Continue k) = continue (\s -> k s >>== step)  --- | Run the entire input stream through a pure left fold, yielding when--- there is no more input.------ Since: 0.4.5--foldl :: Monad m => (b -> a -> b) -> b-      -> Iteratee a m b-foldl step = continue . loop where-	fold = Prelude.foldl step-	loop acc stream = case stream of-		Chunks [] -> continue (loop acc)-		Chunks xs -> continue (loop (fold acc xs))-		EOF -> yield acc EOF+infixl 1 >>==+infixr 1 ==<<+infixr 0 $$+infixr 1 >==>+infixr 1 <==<  --- | Run the entire input stream through a pure strict left fold, yielding--- when there is no more input.------ Since: 0.4.5+-- | Equivalent to '(>>=)' for @m ('Step' a m b)@; allows 'Iteratee's with+-- different input types to be composed. -foldl' :: Monad m => (b -> a -> b) -> b-       -> Iteratee a m b-foldl' step = continue . loop where-	fold = Data.List.foldl' step-	loop acc stream = case stream of-		Chunks [] -> continue (loop acc)-		Chunks xs -> continue (loop (fold acc xs))-		EOF -> yield acc EOF+(>>==) :: Monad m+       => Iteratee a m b+       -> (Step a m b -> Iteratee a' m b')+       -> Iteratee a' m b'+i >>== f = Iteratee (runIteratee i >>= runIteratee . f)  --- | Run the entire input stream through a monadic left fold, yielding--- when there is no more input.------ Since: 0.4.5+-- | @'(==\<\<)' = flip '(\>\>==)'@ -foldM :: Monad m => (b -> a -> m b) -> b-      -> Iteratee a m b-foldM step = continue . loop where-	fold acc = lift . CM.foldM step acc-	-	loop acc stream = case stream of-		Chunks [] -> continue (loop acc)-		Chunks xs -> fold acc xs >>= continue . loop-		EOF -> yield acc EOF+(==<<) :: Monad m+       => (Step a m b -> Iteratee a' m b')+       -> Iteratee a m b+       -> Iteratee a' m b'+(==<<) = flip (>>==)  --- | @iterate f x@ enumerates an infinite stream of repeated applications--- of /f/ to /x/.+-- | @'($$)' = '(==\<\<)'@ ----- Analogous to 'Prelude.iterate'.+-- This might be easier to read when passing a chain of iteratees to an+-- enumerator. ----- Since: 0.4.5+-- Since: 0.1.1 -iterate :: Monad m => (a -> a) -> a -> Enumerator a m b-iterate f = loop where-	loop a (Continue k) = k (Chunks [a]) >>== loop (f a)-	loop _ step = returnI step+($$) :: Monad m+     => (Step a m b -> Iteratee a' m b')+     -> Iteratee a m b+     -> Iteratee a' m b'+($$) = (==<<)  --- | Similar to 'iterate', except the iteration function is monadic.+-- | @'(>==>)' e1 e2 s = e1 s '>>==' e2@ ----- Since: 0.4.5+-- Since: 0.1.1 -iterateM :: Monad m => (a -> m a) -> a-         -> Enumerator a m b-iterateM f base = loop (return base) where-	loop m_a (Continue k) = do-		a <- lift m_a-		k (Chunks [a]) >>== loop (f a)-	loop _ step = returnI step+(>==>) :: Monad m+       => Enumerator a m b+       -> (Step a m b -> Iteratee a' m b')+       -> Step a m b+       -> Iteratee a' m b'+(>==>) e1 e2 s = e1 s >>== e2  --- | Enumerates an infinite stream of the provided value.------ Analogous to 'Prelude.repeat'.+-- | @'(\<==\<)' = flip '(>==>)'@ ----- Since: 0.4.5+-- Since: 0.1.1 -repeat :: Monad m => a -> Enumerator a m b-repeat a = Data.Enumerator.iterate (const a) a+(<==<) :: Monad m+       => (Step a m b -> Iteratee a' m b')+       -> Enumerator a m b+       -> Step a m b+       -> Iteratee a' m b'+(<==<) = flip (>==>)  --- | Enumerates an infinite stream by running the provided computation and--- passing each result to the iteratee.------ Since: 0.4.5 -repeatM :: Monad m => m a -> Enumerator a m b-repeatM m_a step = do-	a <- lift m_a-	iterateM (const m_a) a step----- | @replicateM n m_x@ enumerates a stream of /n/ input elements; each--- element is generated by running the input computation /m_x/ once.------ Since: 0.4.5--replicateM :: Monad m => Integer -> m a-           -> Enumerator a m b-replicateM maxCount getNext = loop maxCount where-	loop 0 step = returnI step-	loop n (Continue k) = do-		next <- lift getNext-		k (Chunks [next]) >>== loop (n - 1)-	loop _ step = returnI step----- | @replicate n x = 'replicateM' n (return x)@------ Analogous to 'Prelude.replicate'.------ Since: 0.4.5--replicate :: Monad m => Integer -> a-          -> Enumerator a m b-replicate maxCount a = replicateM maxCount (return a)----- | Like 'repeatM', except the computation may terminate the stream by--- returning 'Nothing'.------ Since: 0.4.5--generateM :: Monad m => m (Maybe a)-          -> Enumerator a m b-generateM getNext = loop where-	loop (Continue k) = do-		next <- lift getNext-		case next of-			Nothing -> continue k-			Just x -> k (Chunks [x]) >>== loop-	loop step = returnI step----- | @concatMapM f@ applies /f/ to each input element and feeds the--- resulting outputs to the inner iteratee.------ Since: 0.4.5--concatMapM :: Monad m => (ao -> m [ai])-           -> Enumeratee ao ai m b-concatMapM f = checkDone (continue . step) where-	step k EOF = yield (Continue k) EOF-	step k (Chunks xs) = loop k xs-	-	loop k [] = continue (step k)-	loop k (x:xs) = do-		fx <- lift (f x)-		k (Chunks fx) >>==-			checkDoneEx (Chunks xs) (\k' -> loop k' xs)----- | @concatMap f = 'concatMapM' (return . f)@------ Since: 0.4.3--concatMap :: Monad m => (ao -> [ai])-          -> Enumeratee ao ai m b-concatMap f = concatMapM (return . f)----- | @map f = 'concatMap' (\x -> 'Prelude.map' f [x])@--map :: Monad m => (ao -> ai)-    -> Enumeratee ao ai m b-map f = concatMap (\x -> Prelude.map f [x])----- | @filter p = 'concatMap' (\x -> 'Prelude.filter' p [x])@------ Since: 0.4.5--filter :: Monad m => (a -> Bool)-       -> Enumeratee a a m b-filter p = concatMap (\x -> Prelude.filter p [x])----- | @mapM f = 'concatMapM' (\x -> 'Prelude.mapM' f [x])@------ Since: 0.4.3--mapM :: Monad m => (ao -> m ai)-     -> Enumeratee ao ai m b-mapM f = concatMapM (\x -> Prelude.mapM f [x])----- | @filterM p = 'concatMapM' (\x -> 'CM.filterM' p [x])@------ Since: 0.4.5--filterM :: Monad m => (a -> m Bool)-        -> Enumeratee a a m b-filterM p = concatMapM (\x -> CM.filterM p [x])-- -- | Print chunks as they're received from the enumerator, optionally -- printing empty chunks. @@ -589,6 +418,20 @@ 		yield () EOF  +-- | @'enumList' n xs@ enumerates /xs/ as a stream, passing /n/ inputs per+-- chunk.+--+-- Primarily useful for testing and debugging.++enumList :: Monad m => Integer -> [a] -> Enumerator a m b+enumList n = loop where+	loop xs (Continue k) | not (null xs) = let+		(s1, s2) = genericSplitAt n xs+		in k (Chunks s1) >>== loop s2+	loop _ step = returnI step+++ -- | Compose a list of 'Enumerator's using @'(>>==)'@  concatEnums :: Monad m => [Enumerator a m b]@@ -636,33 +479,8 @@ 	step k = i >>= \v -> k (Chunks [v]) >>== loop  --- | @enumList n xs@ enumerates /xs/ as a stream, passing /n/ inputs per--- chunk.------ Primarily useful for testing and debugging.--enumList :: Monad m => Integer -> [a] -> Enumerator a m b-enumList n = loop where-	loop xs (Continue k) | not (null xs) = let-		(s1, s2) = genericSplitAt n xs-		in k (Chunks s1) >>== loop s2-	loop _ step = returnI step----- | Run an iteratee until it finishes, and return either the final value--- (if it succeeded) or the error (if it failed).--run :: Monad m => Iteratee a m b-    -> m (Either Exc.SomeException b)-run i = do-	mStep <- runIteratee $ enumEOF ==<< i-	case mStep of-		Error err -> return $ Left err-		Yield x _ -> return $ Right x-		Continue _ -> error "run: divergent iteratee"----- | docs TODO+-- | Sends 'EOF' to its iteratee. Most clients should use 'run' or 'run_'+-- instead.  enumEOF :: Monad m => Enumerator a m b enumEOF (Yield x _) = yield x EOF@@ -672,15 +490,6 @@ 	check s = enumEOF s  --- | Like 'run', except errors are converted to exceptions and thrown.--- Primarily useful for small scripts or other simple cases.------ Since: 0.4.1--run_ :: Monad m => Iteratee a m b -> m b-run_ i = run i >>= either Exc.throw return-- -- | A common pattern in 'Enumeratee' implementations is to check whether -- the inner 'Iteratee' has finished, and if so, to return its output. -- 'checkDone' passes its parameter a continuation if the 'Iteratee'@@ -696,7 +505,7 @@ checkDoneEx extra _ step         = yield step extra  --- | @checkDone = 'checkDoneEx' ('Chunks' [])@+-- | @'checkDone' = 'checkDoneEx' ('Chunks' [])@ -- -- Use this for enumeratees which do not have an input buffer. @@ -706,7 +515,8 @@ checkDone = checkDoneEx (Chunks [])  --- | docs TODO+-- | Check whether a stream has reached EOF. Most clients should use+-- 'Data.Enumerator.List.head' instead.  isEOF :: Monad m => Iteratee a m Bool isEOF = continue $ \s -> case s of@@ -714,6 +524,7 @@ 	_ -> yield False s  + -- | Lift an 'Iteratee' onto a monad transformer, re-wrapping the -- 'Iteratee'&#x2019;s inner monadic values. --@@ -728,8 +539,7 @@ 		Error err -> Error err 		Continue k -> Continue (liftTrans . k) -{-# DEPRECATED liftI-     "Use 'Data.Enumerator.continue' instead" #-}+{-# DEPRECATED liftI "Use 'Data.Enumerator.continue' instead" #-}  -- | Deprecated in 0.4.5: use 'Data.Enumerator.continue' instead @@ -771,83 +581,222 @@ 	loop n (Chunks xs) = continue (loop (n + len xs)) 	loop n EOF = yield n EOF -{-# DEPRECATED head-     "Use 'Data.Enumerator.List.head' instead" #-} +{-# DEPRECATED head "Use 'Data.Enumerator.List.head' instead" #-}+ -- | Deprecated in 0.4.5: use 'Data.Enumerator.List.head' instead  head :: Monad m => Iteratee a m (Maybe a) head = EL.head -{-# DEPRECATED drop-     "Use 'Data.Enumerator.List.drop' instead" #-}+{-# DEPRECATED drop "Use 'Data.Enumerator.List.drop' instead" #-}  -- | Deprecated in 0.4.5: use 'Data.Enumerator.List.drop' instead  drop :: Monad m => Integer -> Iteratee a m () drop = EL.drop -{-# DEPRECATED dropWhile-     "Use 'Data.Enumerator.List.dropWhile' instead" #-}+{-# DEPRECATED dropWhile "Use 'Data.Enumerator.List.dropWhile' instead" #-}  -- | Deprecated in 0.4.5: use 'Data.Enumerator.List.dropWhile' instead  dropWhile :: Monad m => (a -> Bool) -> Iteratee a m () dropWhile = EL.dropWhile -{-# DEPRECATED span-     "Use 'Data.Enumerator.List.takeWhile' instead" #-}+{-# DEPRECATED span "Use 'Data.Enumerator.List.takeWhile' instead" #-}  -- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead  span :: Monad m => (a -> Bool) -> Iteratee a m [a] span = EL.takeWhile -{-# DEPRECATED break-     "Use 'Data.Enumerator.List.takeWhile' instead" #-}+{-# DEPRECATED break "Use 'Data.Enumerator.List.takeWhile' instead" #-}  -- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead  break :: Monad m => (a -> Bool) -> Iteratee a m [a] break p = EL.takeWhile (not . p) -{-# DEPRECATED consume-     "Use 'Data.Enumerator.List.consume' instead" #-}+{-# DEPRECATED consume "Use 'Data.Enumerator.List.consume' instead" #-}  -- | Deprecated in 0.4.5: use 'Data.Enumerator.List.consume' instead  consume :: Monad m => Iteratee a m [a] consume = EL.consume -{-# DEPRECATED liftFoldL-     "Use 'Data.Enumerator.foldl' instead" #-}+{-# DEPRECATED foldl "Use Data.Enumerator.List.fold instead" #-} --- | Deprecated in 0.4.5: use 'Data.Enumerator.foldl' instead+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead --+-- Since: 0.4.5++foldl :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldl step = continue . loop where+	fold = Prelude.foldl step+	loop acc stream = case stream of+		Chunks [] -> continue (loop acc)+		Chunks xs -> continue (loop (fold acc xs))+		EOF -> yield acc EOF++{-# DEPRECATED foldl' "Use Data.Enumerator.List.fold instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead+--+-- Since: 0.4.5++foldl' :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldl' = EL.fold++{-# DEPRECATED foldM "Use Data.Enumerator.List.foldM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.foldM' instead+--+-- Since: 0.4.5++foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b+foldM = EL.foldM++{-# DEPRECATED iterate "Use Data.Enumerator.List.iterate instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterate' instead+--+-- Since: 0.4.5++iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+iterate = EL.iterate++{-# DEPRECATED iterateM "Use Data.Enumerator.List.iterateM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterateM' instead+--+-- Since: 0.4.5++iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b+iterateM = EL.iterateM++{-# DEPRECATED repeat "Use Data.Enumerator.List.repeat instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeat' instead+--+-- Since: 0.4.5++repeat :: Monad m => a -> Enumerator a m b+repeat = EL.repeat++{-# DEPRECATED repeatM "Use Data.Enumerator.List.repeatM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeatM' instead+--+-- Since: 0.4.5++repeatM :: Monad m => m a -> Enumerator a m b+repeatM = EL.repeatM++{-# DEPRECATED replicate "Use Data.Enumerator.List.replicate instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicate' instead+--+-- Since: 0.4.5++replicate :: Monad m => Integer -> a -> Enumerator a m b+replicate = EL.replicate++{-# DEPRECATED replicateM "Use Data.Enumerator.List.replicateM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicateM' instead+--+-- Since: 0.4.5++replicateM :: Monad m => Integer -> m a -> Enumerator a m b+replicateM = EL.replicateM++{-# DEPRECATED generateM "Use Data.Enumerator.List.generateM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.generateM' instead+--+-- Since: 0.4.5++generateM :: Monad m => m (Maybe a) -> Enumerator a m b+generateM = EL.generateM++{-# DEPRECATED map "Use Data.Enumerator.List.map instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.map' instead++map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b+map = EL.map++{-# DEPRECATED mapM "Use Data.Enumerator.List.mapM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.mapM' instead+--+-- Since: 0.4.3++mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b+mapM = EL.mapM++{-# DEPRECATED concatMap "Use Data.Enumerator.List.concatMap instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMap' instead+--+-- Since: 0.4.3++concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b+concatMap = EL.concatMap++{-# DEPRECATED concatMapM "Use Data.Enumerator.List.concatMapM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMapM' instead+--+-- Since: 0.4.5++concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b+concatMapM = EL.concatMapM++{-# DEPRECATED filter "Use Data.Enumerator.List.filter instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filter' instead+--+-- Since: 0.4.5++filter :: Monad m => (a -> Bool) -> Enumeratee a a m b+filter = EL.filter++{-# DEPRECATED filterM "Use Data.Enumerator.List.filterM instead" #-}++-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filterM' instead+--+-- Since: 0.4.5++filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b+filterM = EL.filterM++{-# DEPRECATED liftFoldL "Use Data.Enumerator.List.fold instead" #-}++-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead+-- -- Since: 0.1.1  liftFoldL :: Monad m => (b -> a -> b) -> b           -> Iteratee a m b liftFoldL = Data.Enumerator.foldl -{-# DEPRECATED liftFoldL'-     "Use 'Data.Enumerator.foldl' ' instead" #-}+{-# DEPRECATED liftFoldL' "Use Data.Enumerator.List.fold instead" #-} --- | Deprecated in 0.4.5: use 'Data.Enumerator.foldl'' instead+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead -- -- Since: 0.1.1  liftFoldL' :: Monad m => (b -> a -> b) -> b            -> Iteratee a m b-liftFoldL' = Data.Enumerator.foldl'+liftFoldL' = EL.fold -{-# DEPRECATED liftFoldM-     "Use 'Data.Enumerator.foldM' instead" #-}+{-# DEPRECATED liftFoldM "Use Data.Enumerator.List.foldM instead" #-} --- | Deprecated in 0.4.5: use 'Data.Enumerator.foldM' instead+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.foldM' instead -- -- Since: 0.1.1  liftFoldM :: Monad m => (b -> a -> m b) -> b           -> Iteratee a m b-liftFoldM = Data.Enumerator.foldM+liftFoldM = EL.foldM
hs/Data/Enumerator.hs-boot view
@@ -9,3 +9,5 @@ newtype Iteratee a m b = Iteratee 	{ runIteratee :: m (Step a m b) 	}+type Enumerator a m b = Step a m b -> Iteratee a m b+type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b)
hs/Data/Enumerator/Binary.hs view
@@ -21,149 +21,263 @@  module Data.Enumerator.Binary ( -	  -- * Binary IO+	-- * IO 	  enumHandle+	, enumHandleRange 	, enumFile+	, enumFileRange 	, iterHandle-+	 	-- * List analogues+	+	-- ** Folds+	, fold+	, foldM+	+	-- ** Maps+	, Data.Enumerator.Binary.map+	, Data.Enumerator.Binary.mapM+	, Data.Enumerator.Binary.concatMap+	, concatMapM+	+	-- ** Infinite streams+	, Data.Enumerator.Binary.iterate+	, iterateM+	, Data.Enumerator.Binary.repeat+	, repeatM+	+	-- ** Bounded streams+	, Data.Enumerator.Binary.replicate+	, replicateM+	, generateM+	, unfold+	, unfoldM+	+	-- ** Filters+	, Data.Enumerator.Binary.filter+	, filterM+	+	-- ** Consumers+	, Data.Enumerator.Binary.take+	, takeWhile+	, consume+	+	-- ** Unsorted 	, Data.Enumerator.Binary.head 	, Data.Enumerator.Binary.drop 	, Data.Enumerator.Binary.dropWhile-	, Data.Enumerator.Binary.take-	, Data.Enumerator.Binary.takeWhile-	, Data.Enumerator.Binary.consume 	, require 	, isolate+	, splitWhen+	  	) where-import Prelude hiding (head, drop, takeWhile)-import Data.Enumerator hiding (head, drop)-import qualified Data.ByteString as B -import Data.Enumerator.Util (tryStep)-import qualified Control.Exception as Exc+import Prelude hiding (head, drop, takeWhile)+import Data.Enumerator hiding ( head, drop, iterateM, repeatM, replicateM+                              , generateM, filterM, consume, foldM+                              , concatMapM)+import Data.Enumerator.Util (tryIO) import Control.Monad.IO.Class (MonadIO)+import qualified Data.ByteString as B import qualified System.IO as IO+import Data.Function (fix)+import qualified Control.Exception as Exc import System.IO.Error (isEOFError)- import Data.Word (Word8)+import qualified Data.Enumerator.List as EL+import qualified Control.Monad as CM import qualified Data.ByteString.Lazy as BL+import Control.Monad.Trans.Class (lift)+import Control.Monad (liftM)  --- | Read bytes (in chunks of the given buffer size) from the handle, and--- stream them to an 'Iteratee'. If an exception occurs during file IO,--- enumeration will stop and 'Error' will be returned. Exceptions from the--- iteratee are not caught.++-- | Consume the entire input stream with a strict left fold, one byte+-- at a time. ----- This enumerator blocks until at least one byte is available from the--- handle, and might read less than the maximum buffer size in some--- cases.+-- Since: 0.4.8++fold :: Monad m => (b -> Word8 -> b) -> b+     -> Iteratee B.ByteString m b+fold step = EL.fold (B.foldl' step)+++-- | Consume the entire input stream with a strict monadic left fold, one+-- byte at a time. ----- The handle should be opened with no encoding, and in 'IO.ReadMode' or--- 'IO.ReadWriteMode'.+-- Since: 0.4.8 -enumHandle :: MonadIO m-           => Integer -- ^ Buffer size-           -> IO.Handle-           -> Enumerator B.ByteString m b-enumHandle bufferSize h = loop where-	loop (Continue k) = withBytes $ \bytes ->-		if B.null bytes-			then continue k-			else k (Chunks [bytes]) >>== loop-	-	loop step = returnI step+foldM :: Monad m => (b -> Word8 -> m b) -> b+      -> Iteratee B.ByteString m b+foldM step = EL.foldM (\b bytes -> CM.foldM step b (B.unpack bytes))+++-- | Enumerates a stream of bytes by repeatedly applying a function to+-- some state.+--+-- Similar to 'iterate'.+--+-- Since: 0.4.8++unfold :: Monad m => (s -> Maybe (Word8, s)) -> s -> Enumerator B.ByteString m b+unfold f = loop where+	loop s (Continue k) = case f s of+		Nothing -> continue k+		Just (b, s') -> k (Chunks [B.singleton b]) >>== loop s'+	loop _ step = returnI step+++-- | Enumerates a stream of bytes by repeatedly applying a computation to+-- some state.+--+-- Similar to 'iterateM'.+--+-- Since: 0.4.8++unfoldM :: Monad m => (s -> m (Maybe (Word8, s))) -> s -> Enumerator B.ByteString m b+unfoldM f = loop where+	loop s (Continue k) = do+		fs <- lift (f s)+		case fs of+			Nothing -> continue k+			Just (b, s') -> k (Chunks [B.singleton b]) >>== loop s'+	loop _ step = returnI step+++-- | @'map' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++map :: Monad m => (Word8 -> Word8) -> Enumeratee B.ByteString B.ByteString m b+map f = Data.Enumerator.Binary.concatMap (\x -> B.singleton (f x))+++-- | @'mapM' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++mapM :: Monad m => (Word8 -> m Word8) -> Enumeratee B.ByteString B.ByteString m b+mapM f = Data.Enumerator.Binary.concatMapM (\x -> liftM B.singleton (f x))+++-- | @'concatMap' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++concatMap :: Monad m => (Word8 -> B.ByteString) -> Enumeratee B.ByteString B.ByteString m b+concatMap f = Data.Enumerator.Binary.concatMapM (return . f)+++-- | @'concatMapM' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++concatMapM :: Monad m => (Word8 -> m B.ByteString) -> Enumeratee B.ByteString B.ByteString m b+concatMapM f = checkDone (continue . step) where+	step k EOF = yield (Continue k) EOF+	step k (Chunks xs) = loop k (BL.unpack (BL.fromChunks xs)) 	-	intSize = fromInteger bufferSize-	withBytes = tryStep $ do-		hasInput <- Exc.catch-			(IO.hWaitForInput h (-1))-			(\err -> if isEOFError err-				then return False-				else Exc.throwIO err)-		if hasInput-			then B.hGetNonBlocking h intSize-			else return B.empty+	loop k [] = continue (step k)+	loop k (x:xs) = do+		fx <- lift (f x)+		k (Chunks [fx]) >>==+			checkDoneEx (Chunks [B.pack xs]) (\k' -> loop k' xs)  --- | Opens a file path in binary mode, and passes the handle to 'enumHandle'.--- The file will be closed when the 'Iteratee' finishes.+-- | @'iterate' f x@ enumerates an infinite stream of repeated applications+-- of /f/ to /x/.+--+-- Analogous to 'Prelude.iterate'.+--+-- Since: 0.4.8 -enumFile :: FilePath -> Enumerator B.ByteString IO b-enumFile path = enum where-	withHandle = tryStep (IO.openBinaryFile path IO.ReadMode)-	enum step = withHandle $ \h -> do-		Iteratee $ Exc.finally-			(runIteratee (enumHandle 4096 h step))-			(IO.hClose h)+iterate :: Monad m => (Word8 -> Word8) -> Word8 -> Enumerator B.ByteString m b+iterate f = loop where+	loop byte (Continue k) = k (Chunks [B.singleton byte]) >>== loop (f byte)+	loop _ step = returnI step  --- | Read bytes from a stream and write them to a handle. If an exception--- occurs during file IO, enumeration will stop and 'Error' will be--- returned.+-- | Similar to 'iterate', except the iteration function is monadic. ----- The handle should be opened with no encoding, and in 'IO.WriteMode' or--- 'IO.ReadWriteMode'.+-- Since: 0.4.8 -iterHandle :: MonadIO m => IO.Handle-           -> Iteratee B.ByteString m ()-iterHandle h = continue step where-	step EOF = yield () EOF-	step (Chunks []) = continue step-	step (Chunks bytes) = let-		put = mapM_ (B.hPut h) bytes-		in tryStep put (\_ -> continue step)+iterateM :: Monad m => (Word8 -> m Word8) -> Word8 -> Enumerator B.ByteString m b+iterateM f base = loop (return base) where+	loop m_byte (Continue k) = do+		byte <- lift m_byte+		k (Chunks [B.singleton byte]) >>== loop (f byte)+	loop _ step = returnI step -toChunks :: BL.ByteString -> Stream B.ByteString-toChunks = Chunks . BL.toChunks +-- | Enumerates an infinite stream of a single byte.+--+-- Analogous to 'Prelude.repeat'.+--+-- Since: 0.4.8 --- | Get the next byte from the stream, or 'Nothing' if the stream has--- ended.+repeat :: Monad m => Word8 -> Enumerator B.ByteString m b+repeat byte = EL.repeat (B.singleton byte)+++-- | Enumerates an infinite stream of byte. Each byte is computed by the+-- underlying monad. ----- Since: 0.4.5+-- Since: 0.4.8 -head :: Monad m => Iteratee B.ByteString m (Maybe Word8)-head = continue loop where-	loop (Chunks xs) = case BL.uncons (BL.fromChunks xs) of-		Just (char, extra) -> yield (Just char) (toChunks extra)-		Nothing -> head-	loop EOF = yield Nothing EOF+repeatM :: Monad m => m Word8 -> Enumerator B.ByteString m b+repeatM next = EL.repeatM (liftM B.singleton next)  --- | @drop n@ ignores /n/ bytes of input from the stream.+-- | @'replicate' n x@ enumerates a stream containing /n/ copies of /x/. ----- Since: 0.4.5+-- Since: 0.4.8 -drop :: Monad m => Integer -> Iteratee B.ByteString m ()-drop n | n <= 0 = return ()-drop n = continue (loop n) where-	loop n' (Chunks xs) = iter where-		lazy = BL.fromChunks xs-		len = toInteger (BL.length lazy)-		iter = if len < n'-			then drop (n' - len)-			else yield () (toChunks (BL.drop (fromInteger n') lazy))-	loop _ EOF = yield () EOF+replicate :: Monad m => Integer -> Word8 -> Enumerator B.ByteString m b+replicate n byte = EL.replicate n (B.singleton byte)  --- | @dropWhile p@ ignores input from the stream until the first byte which--- does not match the predicate.+-- | @'replicateM' n m_x@ enumerates a stream of /n/ bytes, with each byte+-- computed by /m_x/. ----- Since: 0.4.5+-- Since: 0.4.8 -dropWhile :: Monad m => (Word8 -> Bool) -> Iteratee B.ByteString m ()-dropWhile p = continue loop where-	loop (Chunks xs) = iter where-		lazy = BL.dropWhile p (BL.fromChunks xs)-		iter = if BL.null lazy-			then continue loop-			else yield () (toChunks lazy)-	loop EOF = yield () EOF+replicateM :: Monad m => Integer -> m Word8 -> Enumerator B.ByteString m b+replicateM n next = EL.replicateM n (liftM B.singleton next)  --- | @take n@ extracts the next /n/ bytes from the stream, as a lazy+-- | Like 'repeatM', except the computation may terminate the stream by+-- returning 'Nothing'.+--+-- Since: 0.4.8++generateM :: Monad m => m (Maybe Word8) -> Enumerator B.ByteString m b+generateM next = EL.generateM (liftM (liftM B.singleton) next)+++-- | Applies a predicate to the stream. The inner iteratee only receives+-- characters for which the predicate is @True@.+--+-- Since: 0.4.8++filter :: Monad m => (Word8 -> Bool) -> Enumeratee B.ByteString B.ByteString m b+filter p = Data.Enumerator.Binary.concatMap (\x -> B.pack [x | p x])+++-- | Applies a monadic predicate to the stream. The inner iteratee only+-- receives bytes for which the predicate returns @True@.+--+-- Since: 0.4.8++filterM :: Monad m => (Word8 -> m Bool) -> Enumeratee B.ByteString B.ByteString m b+filterM p = Data.Enumerator.Binary.concatMapM (\x -> liftM B.pack (CM.filterM p [x]))+++-- | @'take' n@ extracts the next /n/ bytes from the stream, as a lazy -- ByteString. -- -- Since: 0.4.5@@ -183,7 +297,7 @@ 	loop acc _ EOF = yield (acc BL.empty) EOF  --- | @takeWhile p@ extracts input from the stream until the first byte which+-- | @'takeWhile' p@ extracts input from the stream until the first byte which -- does not match the predicate. -- -- Since: 0.4.5@@ -200,8 +314,7 @@ 	loop acc EOF = yield (acc BL.empty) EOF  --- | Read all remaining input from the stream, and return as a lazy--- ByteString.+-- | @'consume' = 'takeWhile' (const True)@ -- -- Since: 0.4.5 @@ -214,7 +327,51 @@ 	loop acc EOF = yield (acc BL.empty) EOF  --- | @require n@ buffers input until at least /n/ bytes are available, or+-- | Get the next byte from the stream, or 'Nothing' if the stream has+-- ended.+--+-- Since: 0.4.5++head :: Monad m => Iteratee B.ByteString m (Maybe Word8)+head = continue loop where+	loop (Chunks xs) = case BL.uncons (BL.fromChunks xs) of+		Just (char, extra) -> yield (Just char) (toChunks extra)+		Nothing -> head+	loop EOF = yield Nothing EOF+++-- | @'drop' n@ ignores /n/ bytes of input from the stream.+--+-- Since: 0.4.5++drop :: Monad m => Integer -> Iteratee B.ByteString m ()+drop n | n <= 0 = return ()+drop n = continue (loop n) where+	loop n' (Chunks xs) = iter where+		lazy = BL.fromChunks xs+		len = toInteger (BL.length lazy)+		iter = if len < n'+			then drop (n' - len)+			else yield () (toChunks (BL.drop (fromInteger n') lazy))+	loop _ EOF = yield () EOF+++-- | @'dropWhile' p@ ignores input from the stream until the first byte+-- which does not match the predicate.+--+-- Since: 0.4.5++dropWhile :: Monad m => (Word8 -> Bool) -> Iteratee B.ByteString m ()+dropWhile p = continue loop where+	loop (Chunks xs) = iter where+		lazy = BL.dropWhile p (BL.fromChunks xs)+		iter = if BL.null lazy+			then continue loop+			else yield () (toChunks lazy)+	loop EOF = yield () EOF+++-- | @'require' n@ buffers input until at least /n/ bytes are available, or -- throws an error if the stream ends early. -- -- Since: 0.4.5@@ -231,7 +388,7 @@ 	loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF")  --- | @isolate n@ reads at most /n/ bytes from the stream, and passes them+-- | @'isolate' n@ reads at most /n/ bytes from the stream, and passes them -- to its iteratee. If the iteratee finishes early, bytes continue to be -- consumed from the outer stream until /n/ have been consumed. --@@ -252,3 +409,159 @@ 				in k (toChunks s1) >>== (\step -> yield step (toChunks s2)) 	loop EOF = k EOF >>== (\step -> yield step EOF) isolate n step = drop n >> return step+++-- | Split on bytes satisfying a given predicate.+--+-- Since: 0.4.8++splitWhen :: Monad m => (Word8 -> Bool) -> Enumeratee B.ByteString B.ByteString m b+splitWhen p = loop where+	loop = checkDone step+	step k = isEOF >>= \eof -> if eof+		then yield (Continue k) EOF+		else do+			lazy <- takeWhile (not . p)+			let bytes = B.concat (BL.toChunks lazy)+			eof <- isEOF+			drop 1+			if BL.null lazy && eof+				then yield (Continue k) EOF+				else k (Chunks [bytes]) >>== loop++++-- | Read bytes (in chunks of the given buffer size) from the handle, and+-- stream them to an 'Iteratee'. If an exception occurs during file IO,+-- enumeration will stop and 'Error' will be returned. Exceptions from the+-- iteratee are not caught.+--+-- This enumerator blocks until at least one byte is available from the+-- handle, and might read less than the maximum buffer size in some+-- cases.+--+-- The handle should be opened with no encoding, and in 'IO.ReadMode' or+-- 'IO.ReadWriteMode'.+--+-- Since: 0.4.5++enumHandle :: MonadIO m+           => Integer -- ^ Buffer size+           -> IO.Handle+           -> Enumerator B.ByteString m b+enumHandle bufferSize h = do+	let intSize = fromInteger bufferSize+	+	fix $ \loop step -> case step of+		Continue k -> do+			bytes <- tryIO (getBytes h intSize)+			if B.null bytes+				then continue k+				else k (Chunks [bytes]) >>== loop+		_ -> returnI step+++-- | Read bytes (in chunks of the given buffer size) from the handle, and+-- stream them to an 'Iteratee'. If an exception occurs during file IO,+-- enumeration will stop and 'Error' will be returned. Exceptions from the+-- iteratee are not caught.+--+-- This enumerator blocks until at least one byte is available from the+-- handle, and might read less than the maximum buffer size in some+-- cases.+--+-- The handle should be opened with no encoding, and in 'IO.ReadMode' or+-- 'IO.ReadWriteMode'.+--+-- If an offset is specified, the handle will be seeked to that offset+-- before reading. If the handle cannot be seeked, an error will be+-- thrown.+--+-- If a maximum count is specified, the number of bytes read will not+-- exceed that count.+--+-- Since: 0.4.8++enumHandleRange :: MonadIO m+                => Integer -- ^ Buffer size+                -> Maybe Integer -- ^ Offset+                -> Maybe Integer -- ^ Maximum count+                -> IO.Handle+                -> Enumerator B.ByteString m b+enumHandleRange bufferSize offset count h s = seek >> enum where+	seek = case offset of+		Nothing -> return ()+		Just off -> tryIO (IO.hSeek h IO.AbsoluteSeek off)+	+	enum = case count of+		Just n -> loop n s+		Nothing -> enumHandle bufferSize h s+	+	loop n (Continue k) =+		let rem = fromInteger (min bufferSize n) in+		if rem <= 0+			then continue k+			else do+				bytes <- tryIO (getBytes h rem)+				if B.null bytes+					then continue k+					else k (Chunks [bytes]) >>== loop (n - (toInteger (B.length bytes)))+	loop _ step = returnI step++getBytes :: IO.Handle -> Int -> IO B.ByteString+getBytes h n = do+	hasInput <- Exc.catch+		(IO.hWaitForInput h (-1))+		(\err -> if isEOFError err+			then return False+			else Exc.throwIO err)+	if hasInput+		then B.hGetNonBlocking h n+		else return B.empty+++-- | Opens a file path in binary mode, and passes the handle to+-- 'enumHandle'. The file will be closed when enumeration finishes.+--+-- Since: 0.4.5++enumFile :: FilePath -> Enumerator B.ByteString IO b+enumFile path = enumFileRange path Nothing Nothing+++-- | Opens a file path in binary mode, and passes the handle to+-- 'enumHandleRange'. The file will be closed when enumeration finishes.+--+-- Since: 0.4.8++enumFileRange :: FilePath+              -> Maybe Integer -- ^ Offset+              -> Maybe Integer -- ^ Maximum count+              -> Enumerator B.ByteString IO b+enumFileRange path offset count step = do+	h <- tryIO (IO.openBinaryFile path IO.ReadMode)+	let iter = enumHandleRange 4096 offset count h step+	Iteratee (Exc.finally (runIteratee iter) (IO.hClose h))+++-- | Read bytes from a stream and write them to a handle. If an exception+-- occurs during file IO, enumeration will stop and 'Error' will be+-- returned.+--+-- The handle should be opened with no encoding, and in 'IO.WriteMode' or+-- 'IO.ReadWriteMode'.+--+-- Since: 0.4.5++iterHandle :: MonadIO m => IO.Handle+           -> Iteratee B.ByteString m ()+iterHandle h = continue step where+	step EOF = yield () EOF+	step (Chunks []) = continue step+	step (Chunks bytes) = do+		tryIO (mapM_ (B.hPut h) bytes)+		continue step+++toChunks :: BL.ByteString -> Stream B.ByteString+toChunks = Chunks . BL.toChunks
hs/Data/Enumerator/IO.hs view
@@ -14,8 +14,7 @@ -----------------------------------------------------------------------------  module Data.Enumerator.IO-	{-# DEPRECATED-	     "Use 'Data.Enumerator.Binary' instead" #-}+	{-# DEPRECATED "Use 'Data.Enumerator.Binary' instead" #-} 	( enumHandle 	, enumFile 	, iterHandle@@ -26,10 +25,9 @@ import qualified Data.ByteString as B import qualified System.IO as IO -{-# DEPRECATED enumHandle-     "Use 'Data.Enumerator.Binary.enumHandle' instead" #-}+{-# DEPRECATED enumHandle "Use 'Data.Enumerator.Binary.enumHandle' instead" #-} --- | Deprecated in 0.4.5: use 'Data.Enumerator.Binary.enumHandle' instead+-- | Deprecated in 0.4.5: use 'EB.enumHandle' instead  enumHandle :: MonadIO m            => Integer@@ -37,18 +35,16 @@            -> E.Enumerator B.ByteString m b enumHandle = EB.enumHandle -{-# DEPRECATED enumFile-     "Use 'Data.Enumerator.Binary.enumFile' instead" #-}+{-# DEPRECATED enumFile "Use 'Data.Enumerator.Binary.enumFile' instead" #-} --- | Deprecated in 0.4.5: use 'Data.Enumerator.Binary.enumFile' instead+-- | Deprecated in 0.4.5: use 'EB.enumFile' instead  enumFile :: FilePath -> E.Enumerator B.ByteString IO b enumFile = EB.enumFile -{-# DEPRECATED iterHandle-     "Use 'Data.Enumerator.Binary.iterHandle' instead" #-}+{-# DEPRECATED iterHandle "Use 'Data.Enumerator.Binary.iterHandle' instead" #-} --- | Deprecated in 0.4.5: use 'Data.Enumerator.Binary.iterHandle' instead+-- | Deprecated in 0.4.5: use 'EB.iterHandle' instead  iterHandle :: MonadIO m => IO.Handle            -> E.Iteratee B.ByteString m ()
hs/Data/Enumerator/List.hs view
@@ -21,64 +21,282 @@  module Data.Enumerator.List ( -	  head-	, drop-	, dropWhile-	, take+	-- * List analogues+	+	-- ** Folds+	  fold+	, foldM+	+	-- ** Maps+	, Data.Enumerator.List.map+	, Data.Enumerator.List.mapM+	, Data.Enumerator.List.concatMap+	, concatMapM+	+	-- ** Infinite streams+	, Data.Enumerator.List.iterate+	, iterateM+	, Data.Enumerator.List.repeat+	, repeatM+	+	-- ** Bounded streams+	, Data.Enumerator.List.replicate+	, replicateM+	, generateM+	, unfold+	, unfoldM+	+	-- ** Filters+	, Data.Enumerator.List.filter+	, filterM+	+	-- ** Consumers+	, Data.Enumerator.List.take 	, takeWhile 	, consume+	+	-- ** Unsorted+	, head+	, drop+	, Data.Enumerator.List.dropWhile 	, require 	, isolate+	, splitWhen  	) where-import Data.Enumerator hiding (consume, head, peek, drop, dropWhile)-import Control.Exception (ErrorCall(..))-import Prelude hiding (head, drop, dropWhile, take, takeWhile)++import Prelude hiding (head, drop, sequence, takeWhile)+import Data.Enumerator hiding ( concatMapM, iterateM, replicateM, head, drop+                              , foldM, repeatM, generateM, filterM, consume)+import Control.Monad.Trans.Class (lift)+import qualified Control.Monad as CM import qualified Data.List as L+import Control.Exception (ErrorCall(..))  --- | Get the next element from the stream, or 'Nothing' if the stream has--- ended.++-- | Consume the entire input stream with a strict left fold, one element+-- at a time. ----- Since: 0.4.5+-- Since: 0.4.8 -head :: Monad m => Iteratee a m (Maybe a)-head = continue loop where-	loop (Chunks []) = head-	loop (Chunks (x:xs)) = yield (Just x) (Chunks xs)-	loop EOF = yield Nothing EOF+fold :: Monad m => (b -> a -> b) -> b+       -> Iteratee a m b+fold step = continue . loop where+	f = L.foldl' step+	loop acc stream = case stream of+		Chunks [] -> continue (loop acc)+		Chunks xs -> continue (loop (f acc xs))+		EOF -> yield acc EOF  --- | @drop n@ ignores /n/ input elements from the stream.+-- | Consume the entire input stream with a strict monadic left fold, one+-- element at a time. ----- Since: 0.4.5+-- Since: 0.4.8 -drop :: Monad m => Integer -> Iteratee a m ()-drop n | n <= 0 = return ()-drop n = continue (loop n) where-	loop n' (Chunks xs) = iter where-		len = L.genericLength xs-		iter = if len < n'-			then drop (n' - len)-			else yield () (Chunks (L.genericDrop n' xs))-	loop _ EOF = yield () EOF+foldM :: Monad m => (b -> a -> m b) -> b+      -> Iteratee a m b+foldM step = continue . loop where+	f = CM.foldM step+	+	loop acc stream = acc `seq` case stream of+		Chunks [] -> continue (loop acc)+		Chunks xs -> lift (f acc xs) >>= continue . loop+		EOF -> yield acc EOF  --- | @dropWhile p@ ignores input from the stream until the first element--- which does not match the predicate.+-- | Enumerates a stream of elements by repeatedly applying a function to+-- some state. ----- Since: 0.4.5+-- Similar to 'iterate'.+--+-- Since: 0.4.8 -dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()-dropWhile p = continue loop where-	loop (Chunks xs) = case L.dropWhile p xs of-		[] -> continue loop-		xs' -> yield () (Chunks xs')-	loop EOF = yield () EOF+unfold :: Monad m => (s -> Maybe (a, s)) -> s -> Enumerator a m b+unfold f = loop where+	loop s (Continue k) = case f s of+		Nothing -> continue k+		Just (a, s') -> k (Chunks [a]) >>== loop s'+	loop _ step = returnI step  --- | @take n@ extracts the next /n/ elements from the stream, as a list.+-- | Enumerates a stream of elements by repeatedly applying a computation to+-- some state. --+-- Similar to 'iterateM'.+--+-- Since: 0.4.8++unfoldM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Enumerator a m b+unfoldM f = loop where+	loop s (Continue k) = do+		fs <- lift (f s)+		case fs of+			Nothing -> continue k+			Just (a, s') -> k (Chunks [a]) >>== loop s'+	loop _ step = returnI step+++-- | @'concatMapM' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++concatMapM :: Monad m => (ao -> m [ai])+           -> Enumeratee ao ai m b+concatMapM f = checkDone (continue . step) where+	step k EOF = yield (Continue k) EOF+	step k (Chunks xs) = loop k xs+	+	loop k [] = continue (step k)+	loop k (x:xs) = do+		fx <- lift (f x)+		k (Chunks fx) >>==+			checkDoneEx (Chunks xs) (\k' -> loop k' xs)+++-- | @'concatMap' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++concatMap :: Monad m => (ao -> [ai])+          -> Enumeratee ao ai m b+concatMap f = concatMapM (return . f)+++-- | @'map' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++map :: Monad m => (ao -> ai)+    -> Enumeratee ao ai m b+map f = Data.Enumerator.List.concatMap (\x -> [f x])+++-- | @'mapM' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++mapM :: Monad m => (ao -> m ai)+     -> Enumeratee ao ai m b+mapM f = concatMapM (\x -> Prelude.mapM f [x])+++-- | @'iterate' f x@ enumerates an infinite stream of repeated applications+-- of /f/ to /x/.+--+-- Analogous to 'Prelude.iterate'.+--+-- Since: 0.4.8++iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+iterate f = loop where+	loop a (Continue k) = k (Chunks [a]) >>== loop (f a)+	loop _ step = returnI step+++-- | Similar to 'iterate', except the iteration function is monadic.+--+-- Since: 0.4.8++iterateM :: Monad m => (a -> m a) -> a+         -> Enumerator a m b+iterateM f base = loop (return base) where+	loop m_a (Continue k) = do+		a <- lift m_a+		k (Chunks [a]) >>== loop (f a)+	loop _ step = returnI step+++-- | Enumerates an infinite stream of a single element.+--+-- Analogous to 'Prelude.repeat'.+--+-- Since: 0.4.8++repeat :: Monad m => a -> Enumerator a m b+repeat a = Data.Enumerator.List.iterate (const a) a+++-- | Enumerates an infinite stream of element. Each element is computed by+-- the underlying monad.+--+-- Since: 0.4.8++repeatM :: Monad m => m a -> Enumerator a m b+repeatM m_a step = do+	a <- lift m_a+	iterateM (const m_a) a step+++-- | @'replicateM' n m_x@ enumerates a stream of /n/ elements, with each+-- element computed by /m_x/.+--+-- Since: 0.4.8++replicateM :: Monad m => Integer -> m a+           -> Enumerator a m b+replicateM maxCount getNext = loop maxCount where+	loop 0 step = returnI step+	loop n (Continue k) = do+		next <- lift getNext+		k (Chunks [next]) >>== loop (n - 1)+	loop _ step = returnI step+++-- | @'replicate' n x@ enumerates a stream containing /n/ copies of /x/.+--+-- Analogous to 'Prelude.replicate'.+--+-- Since: 0.4.8++replicate :: Monad m => Integer -> a+          -> Enumerator a m b+replicate maxCount a = replicateM maxCount (return a)+++-- | Like 'repeatM', except the computation may terminate the stream by+-- returning 'Nothing'.+--+-- Since: 0.4.8++generateM :: Monad m => m (Maybe a)+          -> Enumerator a m b+generateM getNext = loop where+	loop (Continue k) = do+		next <- lift getNext+		case next of+			Nothing -> continue k+			Just x -> k (Chunks [x]) >>== loop+	loop step = returnI step+++-- | Applies a predicate to the stream. The inner iteratee only receives+-- elements for which the predicate is @True@.+--+-- Since: 0.4.8++filter :: Monad m => (a -> Bool)+       -> Enumeratee a a m b+filter p = Data.Enumerator.List.concatMap (\x -> [x | p x])+++-- | Applies a monadic predicate to the stream. The inner iteratee only+-- receives elements for which the predicate returns @True@.+--+-- Since: 0.4.8++filterM :: Monad m => (a -> m Bool)+        -> Enumeratee a a m b+filterM p = concatMapM (\x -> CM.filterM p [x])+++-- | @'take' n@ extracts the next /n/ elements from the stream, as a list.+-- -- Since: 0.4.5  take :: Monad m => Integer -> Iteratee a m [a]@@ -93,7 +311,7 @@ 	loop acc _ EOF = yield (acc []) EOF  --- | @takeWhile p@ extracts input from the stream until the first element+-- | @'takeWhile' p@ extracts input from the stream until the first element -- which does not match the predicate. -- -- Since: 0.4.5@@ -107,7 +325,7 @@ 	loop acc EOF = yield (acc []) EOF  --- | Read all remaining input elements from the stream, and return as a list.+-- | @'consume' = 'takeWhile' (const True)@ -- -- Since: 0.4.5 @@ -118,7 +336,47 @@ 	loop acc EOF = yield (acc []) EOF  --- | @require n@ buffers input until at least /n/ elements are available, or+-- | Get the next element from the stream, or 'Nothing' if the stream has+-- ended.+--+-- Since: 0.4.5++head :: Monad m => Iteratee a m (Maybe a)+head = continue loop where+	loop (Chunks []) = head+	loop (Chunks (x:xs)) = yield (Just x) (Chunks xs)+	loop EOF = yield Nothing EOF+++-- | @'drop' n@ ignores /n/ input elements from the stream.+--+-- Since: 0.4.5++drop :: Monad m => Integer -> Iteratee a m ()+drop n | n <= 0 = return ()+drop n = continue (loop n) where+	loop n' (Chunks xs) = iter where+		len = L.genericLength xs+		iter = if len < n'+			then drop (n' - len)+			else yield () (Chunks (L.genericDrop n' xs))+	loop _ EOF = yield () EOF+++-- | @'dropWhile' p@ ignores input from the stream until the first element+-- which does not match the predicate.+--+-- Since: 0.4.5++dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()+dropWhile p = continue loop where+	loop (Chunks xs) = case L.dropWhile p xs of+		[] -> continue loop+		xs' -> yield () (Chunks xs')+	loop EOF = yield () EOF+++-- | @'require' n@ buffers input until at least /n/ elements are available, or -- throws an error if the stream ends early. -- -- Since: 0.4.5@@ -133,7 +391,7 @@ 	loop _ _ EOF = throwError (ErrorCall "require: Unexpected EOF")  --- | @isolate n@ reads at most /n/ elements from the stream, and passes them+-- | @'isolate' n@ reads at most /n/ elements from the stream, and passes them -- to its iteratee. If the iteratee finishes early, elements continue to be -- consumed from the outer stream until /n/ have been consumed. --@@ -152,3 +410,14 @@ 			in k (Chunks s1) >>== (\step -> yield step (Chunks s2)) 	loop EOF = k EOF >>== (\step -> yield step EOF) isolate n step = drop n >> return step+++-- | Split on elements satisfying a given predicate.+--+-- Since: 0.4.8++splitWhen :: Monad m => (a -> Bool) -> Enumeratee a [a] m b+splitWhen p = sequence $ do+	as <- takeWhile (not . p)+	drop 1+	return as
hs/Data/Enumerator/List.hs-boot view
@@ -6,3 +6,18 @@ dropWhile :: Monad m => (a -> Bool) -> Iteratee a m () takeWhile :: Monad m => (a -> Bool) -> Iteratee a m [a] consume :: Monad m => Iteratee a m [a]+fold :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b+iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b+repeat :: Monad m => a -> Enumerator a m b+repeatM :: Monad m => m a -> Enumerator a m b+replicateM :: Monad m => Integer -> m a -> Enumerator a m b+replicate :: Monad m => Integer -> a -> Enumerator a m b+generateM :: Monad m => m (Maybe a) -> Enumerator a m b+map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b+mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b+concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b+concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b+filter :: Monad m => (a -> Bool) -> Enumeratee a a m b+filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b
hs/Data/Enumerator/Text.hs view
@@ -21,174 +21,282 @@  module Data.Enumerator.Text ( -	  -- * Text IO+	-- * IO 	  enumHandle 	, enumFile 	, iterHandle-+	 	-- * List analogues+	+	-- ** Folds+	, fold+	, foldM+	+	-- ** Maps+	, Data.Enumerator.Text.map+	, Data.Enumerator.Text.mapM+	, Data.Enumerator.Text.concatMap+	, concatMapM+	+	-- ** Infinite streams+	, Data.Enumerator.Text.iterate+	, iterateM+	, Data.Enumerator.Text.repeat+	, repeatM+	+	-- ** Bounded streams+	, Data.Enumerator.Text.replicate+	, replicateM+	, generateM+	, unfold+	, unfoldM+	+	-- ** Filters+	, Data.Enumerator.Text.filter+	, filterM+	+	-- ** Consumers+	, Data.Enumerator.Text.take+	, takeWhile+	, consume+	+	-- ** Unsorted 	, Data.Enumerator.Text.head 	, Data.Enumerator.Text.drop 	, Data.Enumerator.Text.dropWhile-	, Data.Enumerator.Text.take-	, Data.Enumerator.Text.takeWhile-	, Data.Enumerator.Text.consume 	, require 	, isolate--	  -- * Codecs+	, splitWhen+	, lines+	+	-- * Text codecs 	, Codec 	, encode 	, decode- 	, utf8- 	, utf16_le 	, utf16_be- 	, utf32_le 	, utf32_be- 	, ascii- 	, iso8859_1  	) where-import qualified Prelude-import Prelude hiding (head, drop, takeWhile)-import Data.Enumerator hiding (head, drop)-import qualified Data.Text as T -import Data.Enumerator.Util (tryStep)-import qualified Data.Text.IO as TIO--import qualified Control.Exception as Exc+import Prelude hiding (head, drop, takeWhile, lines)+import qualified Prelude+import Data.Enumerator hiding ( head, drop, generateM, filterM, consume+                              , concatMapM, iterateM, repeatM, replicateM+                              , foldM)+import Data.Enumerator.Util (tryIO, tSpanBy, tlSpanBy, reprWord, reprChar, textToStrict) import Control.Monad.IO.Class (MonadIO)+import qualified Control.Exception as Exc+import Control.Arrow (first)+import Data.Maybe (catMaybes)+import qualified Data.Text as T+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import qualified Data.Text.Encoding as TE+import Data.Word (Word8, Word16)+import Data.Bits ((.&.), (.|.), shiftL) import qualified System.IO as IO import System.IO.Error (isEOFError)-+import qualified Data.Text.IO as TIO+import Data.Char (ord)+import System.IO.Unsafe (unsafePerformIO) import qualified Data.Text.Lazy as TL+import qualified Data.Enumerator.List as EL+import qualified Control.Monad as CM+import Control.Monad.Trans.Class (lift)+import Control.Monad (liftM) -import qualified Data.ByteString as B-import Data.Enumerator.Util (tSpanBy, tlSpanBy, reprWord, reprChar) -import Control.Arrow (first)-import Data.Bits ((.&.), (.|.), shiftL)-import Data.Char (ord)-import Data.Word (Word8, Word16)-import qualified Data.ByteString.Char8 as B8-import qualified Data.Text.Encoding as TE -import Data.Maybe (catMaybes)+-- | Consume the entire input stream with a strict left fold, one character+-- at a time.+--+-- Since: 0.4.8 -import System.IO.Unsafe (unsafePerformIO)+fold :: Monad m => (b -> Char -> b) -> b+     -> Iteratee T.Text m b+fold step = EL.fold (T.foldl' step)  --- | Read lines of text from the handle, and stream them to an 'Iteratee'.--- If an exception occurs during file IO, enumeration will stop and 'Error'--- will be returned. Exceptions from the iteratee are not caught.+-- | Consume the entire input stream with a strict monadic left fold, one+-- character at a time. ----- The handle should be opened with an appropriate text encoding, and--- in 'IO.ReadMode' or 'IO.ReadWriteMode'.+-- Since: 0.4.8++foldM :: Monad m => (b -> Char -> m b) -> b+      -> Iteratee T.Text m b+foldM step = EL.foldM (\b txt -> CM.foldM step b (T.unpack txt))+++-- | Enumerates a stream of characters by repeatedly applying a function to+-- some state. ----- Since: 0.2+-- Similar to 'iterate'.+--+-- Since: 0.4.8 -enumHandle :: MonadIO m => IO.Handle-           -> Enumerator T.Text m b-enumHandle h = loop where-	loop (Continue k) = withText $ \maybeText ->-		case maybeText of+unfold :: Monad m => (s -> Maybe (Char, s)) -> s -> Enumerator T.Text m b+unfold f = loop where+	loop s (Continue k) = case f s of+		Nothing -> continue k+		Just (c, s') -> k (Chunks [T.singleton c]) >>== loop s'+	loop _ step = returnI step+++-- | Enumerates a stream of characters by repeatedly applying a computation+-- to some state.+--+-- Similar to 'iterateM'.+--+-- Since: 0.4.8++unfoldM :: Monad m => (s -> m (Maybe (Char, s))) -> s -> Enumerator T.Text m b+unfoldM f = loop where+	loop s (Continue k) = do+		fs <- lift (f s)+		case fs of 			Nothing -> continue k-			Just text -> k (Chunks [text]) >>== loop+			Just (c, s') -> k (Chunks [T.singleton c]) >>== loop s'+	loop _ step = returnI step+++-- | @'map' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++map :: Monad m => (Char -> Char) -> Enumeratee T.Text T.Text m b+map f = Data.Enumerator.Text.concatMap (\x -> T.singleton (f x))+++-- | @'mapM' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++mapM :: Monad m => (Char -> m Char) -> Enumeratee T.Text T.Text m b+mapM f = Data.Enumerator.Text.concatMapM (\x -> liftM T.singleton (f x))+++-- | @'concatMap' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++concatMap :: Monad m => (Char -> T.Text) -> Enumeratee T.Text T.Text m b+concatMap f = Data.Enumerator.Text.concatMapM (return . f)+++-- | @'concatMapM' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8++concatMapM :: Monad m => (Char -> m T.Text) -> Enumeratee T.Text T.Text m b+concatMapM f = checkDone (continue . step) where+	step k EOF = yield (Continue k) EOF+	step k (Chunks xs) = loop k (TL.unpack (TL.fromChunks xs)) 	-	loop step = returnI step-	withText = tryStep $ Exc.catch-		(Just `fmap` TIO.hGetLine h)-		(\err -> if isEOFError err-			then return Nothing-			else Exc.throwIO err)+	loop k [] = continue (step k)+	loop k (x:xs) = do+		fx <- lift (f x)+		k (Chunks [fx]) >>==+			checkDoneEx (Chunks [T.pack xs]) (\k' -> loop k' xs)  --- | Opens a file path in text mode, and passes the handle to 'enumHandle'.--- The file will be closed when the 'Iteratee' finishes.+-- | @'iterate' f x@ enumerates an infinite stream of repeated applications+-- of /f/ to /x/. ----- Since: 0.2+-- Analogous to 'Prelude.iterate'.+--+-- Since: 0.4.8 -enumFile :: FilePath -> Enumerator T.Text IO b-enumFile path = enum where-	withHandle = tryStep (IO.openFile path IO.ReadMode)-	enum step = withHandle $ \h -> Iteratee $ Exc.finally-		(runIteratee (enumHandle h step))-		(IO.hClose h)+iterate :: Monad m => (Char -> Char) -> Char -> Enumerator T.Text m b+iterate f = loop where+	loop char (Continue k) = k (Chunks [T.singleton char]) >>== loop (f char)+	loop _ step = returnI step  --- | Read text from a stream and write it to a handle. If an exception--- occurs during file IO, enumeration will stop and 'Error' will be--- returned.+-- | Similar to 'iterate', except the iteration function is monadic. ----- The handle should be opened with an appropriate text encoding, and--- in 'IO.WriteMode' or 'IO.ReadWriteMode'.+-- Since: 0.4.8++iterateM :: Monad m => (Char -> m Char) -> Char -> Enumerator T.Text m b+iterateM f base = loop (return base) where+	loop m_char (Continue k) = do+		char <- lift m_char+		k (Chunks [T.singleton char]) >>== loop (f char)+	loop _ step = returnI step+++-- | Enumerates an infinite stream of a single character. ----- Since: 0.2+-- Analogous to 'Prelude.repeat'.+--+-- Since: 0.4.8 -iterHandle :: MonadIO m => IO.Handle-           -> Iteratee T.Text m ()-iterHandle h = continue step where-	step EOF = yield () EOF-	step (Chunks []) = continue step-	step (Chunks chunks) = let-		put = mapM_ (TIO.hPutStr h) chunks-		in tryStep put (\_ -> continue step)+repeat :: Monad m => Char -> Enumerator T.Text m b+repeat char = EL.repeat (T.singleton char) -toChunks :: TL.Text -> Stream T.Text-toChunks = Chunks . TL.toChunks +-- | Enumerates an infinite stream of characters. Each character is computed+-- by the underlying monad.+--+-- Since: 0.4.8 --- | Get the next character from the stream, or 'Nothing' if the stream has--- ended.+repeatM :: Monad m => m Char -> Enumerator T.Text m b+repeatM next = EL.repeatM (liftM T.singleton next)+++-- | @'replicate' n x@ enumerates a stream containing /n/ copies of /x/. ----- Since: 0.4.5+-- Since: 0.4.8 -head :: Monad m => Iteratee T.Text m (Maybe Char)-head = continue loop where-	loop (Chunks xs) = case TL.uncons (TL.fromChunks xs) of-		Just (char, extra) -> yield (Just char) (toChunks extra)-		Nothing -> head-	loop EOF = yield Nothing EOF+replicate :: Monad m => Integer -> Char -> Enumerator T.Text m b+replicate n byte = EL.replicate n (T.singleton byte)  --- | @drop n@ ignores /n/ characters of input from the stream.+-- | @'replicateM' n m_x@ enumerates a stream of /n/ characters, with each+-- character computed by /m_x/. ----- Since: 0.4.5+-- Since: 0.4.8 -drop :: Monad m => Integer -> Iteratee T.Text m ()-drop n | n <= 0 = return ()-drop n = continue (loop n) where-	loop n' (Chunks xs) = iter where-		lazy = TL.fromChunks xs-		len = toInteger (TL.length lazy)-		iter = if len < n'-			then drop (n' - len)-			else yield () (toChunks (TL.drop (fromInteger n') lazy))-	loop _ EOF = yield () EOF+replicateM :: Monad m => Integer -> m Char -> Enumerator T.Text m b+replicateM n next = EL.replicateM n (liftM T.singleton next)  --- | @dropWhile p@ ignores input from the stream until the first character--- which does not match the predicate.+-- | Like 'repeatM', except the computation may terminate the stream by+-- returning 'Nothing'. ----- Since: 0.4.5+-- Since: 0.4.8 -dropWhile :: Monad m => (Char -> Bool) -> Iteratee T.Text m ()-dropWhile p = continue loop where-	loop (Chunks xs) = iter where-		lazy = TL.dropWhile p (TL.fromChunks xs)-		iter = if TL.null lazy-			then continue loop-			else yield () (toChunks lazy)-	loop EOF = yield () EOF+generateM :: Monad m => m (Maybe Char) -> Enumerator T.Text m b+generateM next = EL.generateM (liftM (liftM T.singleton) next)  --- | @take n@ extracts the next /n/ characters from the stream, as a lazy+-- | Applies a predicate to the stream. The inner iteratee only receives+-- characters for which the predicate is @True@.+--+-- Since: 0.4.8++filter :: Monad m => (Char -> Bool) -> Enumeratee T.Text T.Text m b+filter p = Data.Enumerator.Text.concatMap (\x -> T.pack [x | p x])+++-- | Applies a monadic predicate to the stream. The inner iteratee only+-- receives characters for which the predicate returns @True@.+--+-- Since: 0.4.8++filterM :: Monad m => (Char -> m Bool) -> Enumeratee T.Text T.Text m b+filterM p = Data.Enumerator.Text.concatMapM (\x -> liftM T.pack (CM.filterM p [x]))+++-- | @'take' n@ extracts the next /n/ characters from the stream, as a lazy -- Text. -- -- Since: 0.4.5@@ -208,7 +316,7 @@ 	loop acc _ EOF = yield (acc TL.empty) EOF  --- | @takeWhile p@ extracts input from the stream until the first character+-- | @'takeWhile' p@ extracts input from the stream until the first character -- which does not match the predicate. -- -- Since: 0.4.5@@ -225,8 +333,7 @@ 	loop acc EOF = yield (acc TL.empty) EOF  --- | Read all remaining input from the stream, and return as a lazy--- Text.+-- | @'consume' = 'takeWhile' (const True)@ -- -- Since: 0.4.5 @@ -239,7 +346,51 @@ 	loop acc EOF = yield (acc TL.empty) EOF  --- | @require n@ buffers input until at least /n/ characters are available,+-- | Get the next character from the stream, or 'Nothing' if the stream has+-- ended.+--+-- Since: 0.4.5++head :: Monad m => Iteratee T.Text m (Maybe Char)+head = continue loop where+	loop (Chunks xs) = case TL.uncons (TL.fromChunks xs) of+		Just (char, extra) -> yield (Just char) (toChunks extra)+		Nothing -> head+	loop EOF = yield Nothing EOF+++-- | @'drop' n@ ignores /n/ characters of input from the stream.+--+-- Since: 0.4.5++drop :: Monad m => Integer -> Iteratee T.Text m ()+drop n | n <= 0 = return ()+drop n = continue (loop n) where+	loop n' (Chunks xs) = iter where+		lazy = TL.fromChunks xs+		len = toInteger (TL.length lazy)+		iter = if len < n'+			then drop (n' - len)+			else yield () (toChunks (TL.drop (fromInteger n') lazy))+	loop _ EOF = yield () EOF+++-- | @'dropWhile' p@ ignores input from the stream until the first character+-- which does not match the predicate.+--+-- Since: 0.4.5++dropWhile :: Monad m => (Char -> Bool) -> Iteratee T.Text m ()+dropWhile p = continue loop where+	loop (Chunks xs) = iter where+		lazy = TL.dropWhile p (TL.fromChunks xs)+		iter = if TL.null lazy+			then continue loop+			else yield () (toChunks lazy)+	loop EOF = yield () EOF+++-- | @'require' n@ buffers input until at least /n/ characters are available, -- or throws an error if the stream ends early. -- -- Since: 0.4.5@@ -256,7 +407,7 @@ 	loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF")  --- | @isolate n@ reads at most /n/ characters from the stream, and passes+-- | @'isolate' n@ reads at most /n/ characters from the stream, and passes -- them to its iteratee. If the iteratee finishes early, characters continue -- to be consumed from the outer stream until /n/ have been consumed. --@@ -278,6 +429,93 @@ 	loop EOF = k EOF >>== (\step -> yield step EOF) isolate n step = drop n >> return step ++-- | Split on characters satisfying a given predicate.+--+-- Since: 0.4.8++splitWhen :: Monad m => (Char -> Bool) -> Enumeratee T.Text T.Text m b+splitWhen p = loop where+	loop = checkDone step+	step k = isEOF >>= \eof -> if eof+		then yield (Continue k) EOF+		else do+			lazy <- takeWhile (not . p)+			let text = textToStrict lazy+			eof <- isEOF+			drop 1+			if TL.null lazy && eof+				then yield (Continue k) EOF+				else k (Chunks [text]) >>== loop+++-- | @'lines' = 'splitWhen' (== '\n')@+--+-- Since: 0.4.8++lines :: Monad m => Enumeratee T.Text T.Text m b+lines = splitWhen (== '\n')++++-- | Read lines of text from the handle, and stream them to an 'Iteratee'.+-- If an exception occurs during file IO, enumeration will stop and 'Error'+-- will be returned. Exceptions from the iteratee are not caught.+--+-- The handle should be opened with an appropriate text encoding, and+-- in 'IO.ReadMode' or 'IO.ReadWriteMode'.+--+-- Since: 0.2++enumHandle :: MonadIO m => IO.Handle+           -> Enumerator T.Text m b+enumHandle h = loop where+	loop (Continue k) = do+		maybeText <- tryIO getText+		case maybeText of+			Nothing -> continue k+			Just text -> k (Chunks [text]) >>== loop+	+	loop step = returnI step+	getText = Exc.catch+		(Just `fmap` TIO.hGetLine h)+		(\err -> if isEOFError err+			then return Nothing+			else Exc.throwIO err)+++-- | Opens a file path in text mode, and passes the handle to 'enumHandle'.+-- The file will be closed when the 'Iteratee' finishes.+--+-- Since: 0.2++enumFile :: FilePath -> Enumerator T.Text IO b+enumFile path step = do+	h <- tryIO (IO.openFile path IO.ReadMode)+	Iteratee $ Exc.finally+		(runIteratee (enumHandle h step))+		(IO.hClose h)+++-- | Read text from a stream and write it to a handle. If an exception+-- occurs during file IO, enumeration will stop and 'Error' will be+-- returned.+--+-- The handle should be opened with an appropriate text encoding, and+-- in 'IO.WriteMode' or 'IO.ReadWriteMode'.+--+-- Since: 0.2++iterHandle :: MonadIO m => IO.Handle+           -> Iteratee T.Text m ()+iterHandle h = continue step where+	step EOF = yield () EOF+	step (Chunks []) = continue step+	step (Chunks chunks) = do+		tryIO (mapM_ (TIO.hPutStr h) chunks)+		continue step++ data Codec = Codec 	{ codecName :: T.Text 	, codecEncode@@ -545,3 +783,7 @@ maybeDecode (a, b) = case tryEvaluate a of 	Left _ -> Nothing 	Right _ -> Just (a, b)+++toChunks :: TL.Text -> Stream T.Text+toChunks = Chunks . TL.toChunks
hs/Data/Enumerator/Util.hs view
@@ -12,12 +12,12 @@ import qualified Control.Exception as Exc import Numeric (showIntAtBase) -tryStep :: MonadIO m => IO t -> (t -> Iteratee a m b) -> Iteratee a m b-tryStep get io = do-	tried <- liftIO (Exc.try get)-	case tried of-		Right t -> io t-		Left err -> throwError (err :: Exc.SomeException)+tryIO :: MonadIO m => IO b -> Iteratee a m b+tryIO io = Iteratee $ do+	tried <- liftIO (Exc.try io)+	return $ case tried of+		Right b -> Yield b (Chunks [])+		Left err -> Error err  pad0 :: Int -> String -> String pad0 size str = padded where@@ -40,4 +40,11 @@ #else tSpanBy = T.spanBy tlSpanBy = TL.spanBy+#endif++textToStrict :: TL.Text -> T.Text+#if MIN_VERSION_text(0,8,0)+textToStrict = TL.toStrict+#else+textToStrict = T.concat . TL.toChunks #endif
− scripts/cabal-dist
@@ -1,57 +0,0 @@-#!/bin/bash-if [ ! -f 'enumerator.cabal' ]; then-	echo -n "Can't find enumerator.cabal; please run this script as"-	echo -n " ./scripts/cabal-dist from within the enumerator source"-	echo " directory"-	exit 1-fi--XZ=$(which xz)-XELATEX=$(which xelatex)-if [ -d 'cabal-dev' ]; then-	CABAL=$(which cabal-dev)-	PATH="$PATH:$PWD/cabal-dev/bin/"-else-	CABAL=$(which cabal)-fi--ANANSI=$(which anansi)-if [ -z "$ANANSI" ]; then-	echo "Can't find 'anansi' executable; make sure it exists on your "'$PATH'-	exit 1-fi--VERSION=$(awk '/^version:/{print $2}' enumerator.cabal)--echo "Building dist for enumerator-$VERSION using $CABAL"--rm -rf hs dist-anansi --noline -o hs src/enumerator.anansi || exit 1-$CABAL configure || exit 1-$CABAL build || exit 1-$CABAL sdist || exit 1-mv "dist/enumerator-$VERSION.tar.gz" "./enumerator_$VERSION.tar.gz"-if [ -n "$XZ" ]; then-  gzip -dfc "enumerator_$VERSION.tar.gz" > "enumerator_$VERSION.tar"-  xz -f -C sha256 -9 "enumerator_$VERSION.tar"-fi--if [ -n "$XELATEX" ]; then-  rm -f *.{aux,tex,idx,log,out,toc,pdf}-  anansi -w -l latex-noweb -o enumerator.tex src/enumerator.anansi || exit 1-  xelatex enumerator.tex > /dev/null || exit 1-  xelatex enumerator.tex > /dev/null || exit 1--  mv enumerator.pdf "enumerator_$VERSION.pdf"-fi--echo ""-echo "============================================================"-if [ -n "$XELATEX" ]; then-	echo "  woven source        : enumerator_$VERSION.pdf"-fi-echo "  source tarball (gz) : enumerator_$VERSION.tar.gz"-if [ -n "$XZ" ]; then-	echo "  source archive (xz) : enumerator_$VERSION.tar.xz"-fi-echo "============================================================"
+ scripts/common.bash view
@@ -0,0 +1,63 @@+PATH="$PATH:$PWD/cabal-dev/bin/"++VERSION=$(awk '/^version:/{print $2}' enumerator.cabal)++CABAL_DEV=$(which cabal-dev)+ANANSI=$(which anansi)+XELATEX=$(which xelatex)+XZ=$(which xz)++require_cabal_dev()+{+	if [ -z "$CABAL_DEV" ]; then+		echo "Can't find 'cabal-dev' executable; make sure it exists on your "'$PATH'+		echo "Cowardly refusing to fuck with the global package database"+		exit 1+	fi+}++require_anansi()+{+	if [ -z "$ANANSI" ]; then+		echo "Can't find 'anansi' executable; running '$CABAL_DEV install anansi'"+		require_cabal_dev+		$CABAL_DEV install anansi &> /dev/null+		if [ "$?" -ne "0" ]; then+			echo "Installation failed; please install Anansi manually somehow"+			exit 1+		fi+		ANANSI=$(which anansi)+		echo "Success; anansi = $ANANSI"+	fi+}++require_xelatex()+{+	if [ -z "$XELATEX" ]; then+		echo "Can't find 'xelatex' executable; make sure it exists on your "'$PATH'+		exit 1+	fi+}++make_pdf()+{+	require_anansi+	require_xelatex+	+	rm -f *.{aux,tex,idx,log,out,toc,pdf}+	$ANANSI -w -l latex-noweb -o enumerator.tex src/enumerator.anansi || exit 1+	$XELATEX enumerator.tex > /dev/null || exit 1+	$XELATEX enumerator.tex > /dev/null || exit 1+	rm -f *.{aux,tex,idx,log,out,toc}+	mv enumerator.pdf "enumerator_$VERSION.pdf"+}++clean_dev_install()+{+	require_anansi+	require_cabal_dev+	+	rm -rf hs dist+	$ANANSI -o hs src/enumerator.anansi || exit 1+	$CABAL_DEV install || exit 1+}
+ scripts/dist view
@@ -0,0 +1,42 @@+#!/bin/bash+if [ ! -f 'enumerator.cabal' ]; then+	echo -n "Can't find enumerator.cabal; please run this script as"+	echo -n " ./scripts/dist from within the enumerator source"+	echo " directory"+	exit 1+fi++. scripts/common.bash++require_anansi+require_cabal_dev++echo "Building dist for enumerator_$VERSION using $CABAL_DEV"++rm -rf hs dist+$ANANSI --noline -o hs src/enumerator.anansi || exit 1+$CABAL_DEV configure || exit 1+$CABAL_DEV build || exit 1+$CABAL_DEV sdist || exit 1++mv "dist/enumerator-$VERSION.tar.gz" "./enumerator_$VERSION.tar.gz"+ln -f "./enumerator_$VERSION.tar.gz" "./enumerator-$VERSION.tar.gz"+if [ -n "$XZ" ]; then+	gzip -dfc "enumerator_$VERSION.tar.gz" > "enumerator_$VERSION.tar"+	xz -f -C sha256 -9 "enumerator_$VERSION.tar"+fi++if [ -n "$XELATEX" ]; then+	make_pdf+fi++echo ""+echo "============================================================"+if [ -n "$XELATEX" ]; then+	echo "  woven source        : enumerator_$VERSION.pdf"+fi+echo "  source tarball (gz) : enumerator_$VERSION.tar.gz"+if [ -n "$XZ" ]; then+	echo "  source archive (xz) : enumerator_$VERSION.tar.xz"+fi+echo "============================================================"
+ scripts/haddock view
@@ -0,0 +1,17 @@+#!/bin/bash+if [ ! -f 'enumerator.cabal' ]; then+	echo -n "Can't find enumerator.cabal; please run this script as"+	echo -n " ./scripts/haddock from within the enumerator source"+	echo " directory"+	exit 1+fi++. scripts/common.bash++require_anansi+require_cabal_dev++rm -rf hs dist+$ANANSI --noline -o hs src/enumerator.anansi || exit 1+$CABAL_DEV configure || exit 1+$CABAL_DEV haddock || exit 1
+ scripts/latex view
@@ -0,0 +1,11 @@+#!/bin/bash+if [ ! -f 'enumerator.cabal' ]; then+	echo -n "Can't find enumerator.cabal; please run this script as"+	echo -n " ./scripts/latex from within the enumerator source"+	echo " directory"+	exit 1+fi++. scripts/common.bash++make_pdf
+ scripts/run-benchmarks view
@@ -0,0 +1,21 @@+#!/bin/bash+if [ ! -f 'enumerator.cabal' ]; then+	echo -n "Can't find enumerator.cabal; please run this script as"+	echo -n " ./scripts/run-benchmarks from within the enumerator source"+	echo " directory"+	exit 1+fi++. scripts/common.bash++require_anansi+require_cabal_dev++clean_dev_install++pushd tests+rm -rf dist+$CABAL_DEV -s ../cabal-dev install || exit 1+popd++cabal-dev/bin/enumerator_benchmarks $@
scripts/run-tests view
@@ -1,31 +1,21 @@ #!/bin/bash if [ ! -f 'enumerator.cabal' ]; then 	echo -n "Can't find enumerator.cabal; please run this script as"-	echo -n " ./scripts/make-tests from within the enumerator source"+	echo -n " ./scripts/run-tests from within the enumerator source" 	echo " directory" 	exit 1 fi -CABAL=$(which cabal-dev)-if [ -z "$CABAL" ]; then-	echo -n "Can't find 'cabal-dev'; cowardly refusing to fuck with the"-	echo " global package database"-fi-PATH="$PATH:$PWD/cabal-dev/bin/"--ANANSI=$(which anansi)-if [ -z "$ANANSI" ]; then-	echo "Can't find 'anansi' executable; make sure it exists on your "'$PATH'-	exit 1-fi+. scripts/common.bash -rm -rf hs dist-anansi -o hs src/enumerator.anansi || exit 1+require_anansi+require_cabal_dev -$CABAL install || exit 1+clean_dev_install  pushd tests-$CABAL -s ../cabal-dev install || exit 1+rm -rf dist+$CABAL_DEV -s ../cabal-dev install || exit 1 popd  cabal-dev/bin/enumerator_tests
src/api-docs.anansi view
@@ -103,7 +103,7 @@ :  :d apidoc Data.Enumerator.($$)--- | @($$) = (==\<\<)@+-- | @'($$)' = '(==\<\<)'@ -- -- This might be easier to read when passing a chain of iteratees to an -- enumerator.@@ -112,17 +112,17 @@ :  :d apidoc Data.Enumerator.(<==<)--- | @(\<==\<) = flip (>==>)@+-- | @'(\<==\<)' = flip '(>==>)'@ -- -- Since: 0.1.1 :  :d apidoc Data.Enumerator.(==<<)--- | @(==\<\<) = flip (\>\>==)@+-- | @'(==\<\<)' = flip '(\>\>==)'@ :  :d apidoc Data.Enumerator.(>==>)--- | @(>==>) e1 e2 s = e1 s >>== e2@+-- | @'(>==>)' e1 e2 s = e1 s '>>==' e2@ -- -- Since: 0.1.1 :@@ -200,7 +200,7 @@ :  :d apidoc Data.Enumerator.checkDone--- | @checkDone = 'checkDoneEx' ('Chunks' [])@+-- | @'checkDone' = 'checkDoneEx' ('Chunks' [])@ -- -- Use this for enumeratees which do not have an input buffer. :@@ -219,14 +219,13 @@ :  :d apidoc Data.Enumerator.concatMap--- | @concatMap f = 'concatMapM' (return . f)@+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMap' instead -- -- Since: 0.4.3 :  :d apidoc Data.Enumerator.concatMapM--- | @concatMapM f@ applies /f/ to each input element and feeds the--- resulting outputs to the inner iteratee.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMapM' instead -- -- Since: 0.4.5 :@@ -236,7 +235,7 @@ :  :d apidoc Data.Enumerator.continue--- | @continue k = 'returnI' ('Continue' k)@+-- | @'continue' k = 'returnI' ('Continue' k)@ :  :d apidoc Data.Enumerator.drop@@ -248,52 +247,49 @@ :  :d apidoc Data.Enumerator.enumEOF--- | docs TODO+-- | Sends 'EOF' to its iteratee. Most clients should use 'run' or 'run_'+-- instead. :  :d apidoc Data.Enumerator.enumList--- | @enumList n xs@ enumerates /xs/ as a stream, passing /n/ inputs per+-- | @'enumList' n xs@ enumerates /xs/ as a stream, passing /n/ inputs per -- chunk. -- -- Primarily useful for testing and debugging. :  :d apidoc Data.Enumerator.filter--- | @filter p = 'concatMap' (\x -> 'Prelude.filter' p [x])@+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filter' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.filterM--- | @filterM p = 'concatMapM' (\x -> 'CM.filterM' p [x])@+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filterM' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.foldl--- | Run the entire input stream through a pure left fold, yielding when--- there is no more input.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.foldl'--- | Run the entire input stream through a pure strict left fold, yielding--- when there is no more input.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.foldM--- | Run the entire input stream through a monadic left fold, yielding--- when there is no more input.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.foldM' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.generateM--- | Like 'repeatM', except the computation may terminate the stream by--- returning 'Nothing'.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.generateM' instead -- -- Since: 0.4.5 :@@ -303,20 +299,18 @@ :  :d apidoc Data.Enumerator.isEOF--- | docs TODO+-- | Check whether a stream has reached EOF. Most clients should use+-- 'Data.Enumerator.List.head' instead. :  :d apidoc Data.Enumerator.iterate--- | @iterate f x@ enumerates an infinite stream of repeated applications--- of /f/ to /x/.------ Analogous to 'Prelude.iterate'.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterate' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.iterateM--- | Similar to 'iterate', except the iteration function is monadic.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterateM' instead -- -- Since: 0.4.5 :@@ -344,19 +338,19 @@ :  :d apidoc Data.Enumerator.liftFoldL--- | Deprecated in 0.4.5: use 'Data.Enumerator.foldl' instead+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead -- -- Since: 0.1.1 :  :d apidoc Data.Enumerator.liftFoldL'--- | Deprecated in 0.4.5: use 'Data.Enumerator.foldl'' instead+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead -- -- Since: 0.1.1 :  :d apidoc Data.Enumerator.liftFoldM--- | Deprecated in 0.4.5: use 'Data.Enumerator.foldM' instead+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.foldM' instead -- -- Since: 0.1.1 :@@ -373,11 +367,11 @@ :  :d apidoc Data.Enumerator.map--- | @map f = 'concatMap' (\x -> 'Prelude.map' f [x])@+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.map' instead :  :d apidoc Data.Enumerator.mapM--- | @mapM f = 'concatMapM' (\x -> 'Prelude.mapM' f [x])@+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.mapM' instead -- -- Since: 0.4.3 :@@ -393,37 +387,31 @@ :  :d apidoc Data.Enumerator.repeat--- | Enumerates an infinite stream of the provided value.------ Analogous to 'Prelude.repeat'.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeat' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.repeatM--- | Enumerates an infinite stream by running the provided computation and--- passing each result to the iteratee.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeatM' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.replicate--- | @replicate n x = 'replicateM' n (return x)@------ Analogous to 'Prelude.replicate'.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicate' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.replicateM--- | @replicateM n m_x@ enumerates a stream of /n/ input elements; each--- element is generated by running the input computation /m_x/ once.+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicateM' instead -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.returnI--- | @returnI step = 'Iteratee' (return step)@+-- | @'returnI' step = 'Iteratee' (return step)@ :  :d apidoc Data.Enumerator.run@@ -448,38 +436,69 @@ :  :d apidoc Data.Enumerator.throwError--- | @throwError exc = 'returnI' ('Error' ('Exc.toException' exc))@+-- | @'throwError' exc = 'returnI' ('Error' ('Exc.toException' exc))@ :  :d apidoc Data.Enumerator.yield--- | @yield x extra = 'returnI' ('Yield' x extra)@+-- | @'yield' x extra = 'returnI' ('Yield' x extra)@+--+-- WARNING: due to the current encoding of iteratees in this library,+-- careless use of the 'yield' primitive may violate the monad laws.+-- To prevent this, always make sure that an iteratee never yields+-- extra data unless it has received at least one input element.+--+-- More strictly, iteratees may not yield data that they did not+-- receive as input. Don't use 'yield' to &#x201c;inject&#x201d; elements+-- into the stream. : +:d apidoc Data.Enumerator.Binary.concatMap+-- | @'concatMap' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.concatMapM+-- | @'concatMapM' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Binary.consume--- | Read all remaining input from the stream, and return as a lazy--- ByteString.+-- | @'consume' = 'takeWhile' (const True)@ -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.Binary.drop--- | @drop n@ ignores /n/ bytes of input from the stream.+-- | @'drop' n@ ignores /n/ bytes of input from the stream. -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.Binary.dropWhile--- | @dropWhile p@ ignores input from the stream until the first byte which--- does not match the predicate.+-- | @'dropWhile' p@ ignores input from the stream until the first byte+-- which does not match the predicate. -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.Binary.enumFile--- | Opens a file path in binary mode, and passes the handle to 'enumHandle'.--- The file will be closed when the 'Iteratee' finishes.+-- | Opens a file path in binary mode, and passes the handle to+-- 'enumHandle'. The file will be closed when enumeration finishes.+--+-- Since: 0.4.5 : +:d apidoc Data.Enumerator.Binary.enumFileRange+-- | Opens a file path in binary mode, and passes the handle to+-- 'enumHandleRange'. The file will be closed when enumeration finishes.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Binary.enumHandle -- | Read bytes (in chunks of the given buffer size) from the handle, and -- stream them to an 'Iteratee'. If an exception occurs during file IO,@@ -492,8 +511,68 @@ -- -- The handle should be opened with no encoding, and in 'IO.ReadMode' or -- 'IO.ReadWriteMode'.+--+-- Since: 0.4.5 : +:d apidoc Data.Enumerator.Binary.enumHandleRange+-- | Read bytes (in chunks of the given buffer size) from the handle, and+-- stream them to an 'Iteratee'. If an exception occurs during file IO,+-- enumeration will stop and 'Error' will be returned. Exceptions from the+-- iteratee are not caught.+--+-- This enumerator blocks until at least one byte is available from the+-- handle, and might read less than the maximum buffer size in some+-- cases.+--+-- The handle should be opened with no encoding, and in 'IO.ReadMode' or+-- 'IO.ReadWriteMode'.+--+-- If an offset is specified, the handle will be seeked to that offset+-- before reading. If the handle cannot be seeked, an error will be+-- thrown.+--+-- If a maximum count is specified, the number of bytes read will not+-- exceed that count.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.filter+-- | Applies a predicate to the stream. The inner iteratee only receives+-- characters for which the predicate is @True@.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.filterM+-- | Applies a monadic predicate to the stream. The inner iteratee only+-- receives bytes for which the predicate returns @True@.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.fold+-- | Consume the entire input stream with a strict left fold, one byte+-- at a time.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.foldM+-- | Consume the entire input stream with a strict monadic left fold, one+-- byte at a time.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.generateM+-- | Like 'repeatM', except the computation may terminate the stream by+-- returning 'Nothing'.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Binary.head -- | Get the next byte from the stream, or 'Nothing' if the stream has -- ended.@@ -502,13 +581,28 @@ :  :d apidoc Data.Enumerator.Binary.isolate--- | @isolate n@ reads at most /n/ bytes from the stream, and passes them+-- | @'isolate' n@ reads at most /n/ bytes from the stream, and passes them -- to its iteratee. If the iteratee finishes early, bytes continue to be -- consumed from the outer stream until /n/ have been consumed. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.Binary.iterate+-- | @'iterate' f x@ enumerates an infinite stream of repeated applications+-- of /f/ to /x/.+--+-- Analogous to 'Prelude.iterate'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.iterateM+-- | Similar to 'iterate', except the iteration function is monadic.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Binary.iterHandle -- | Read bytes from a stream and write them to a handle. If an exception -- occurs during file IO, enumeration will stop and 'Error' will be@@ -516,60 +610,176 @@ -- -- The handle should be opened with no encoding, and in 'IO.WriteMode' or -- 'IO.ReadWriteMode'.+--+-- Since: 0.4.5 : +:d apidoc Data.Enumerator.Binary.map+-- | @'map' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.mapM+-- | @'mapM' f@ applies /f/ to each input byte and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.repeat+-- | Enumerates an infinite stream of a single byte.+--+-- Analogous to 'Prelude.repeat'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.repeatM+-- | Enumerates an infinite stream of byte. Each byte is computed by the+-- underlying monad.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.replicate+-- | @'replicate' n x@ enumerates a stream containing /n/ copies of /x/.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.replicateM+-- | @'replicateM' n m_x@ enumerates a stream of /n/ bytes, with each byte+-- computed by /m_x/.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Binary.require--- | @require n@ buffers input until at least /n/ bytes are available, or+-- | @'require' n@ buffers input until at least /n/ bytes are available, or -- throws an error if the stream ends early. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.Binary.splitWhen+-- | Split on bytes satisfying a given predicate.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Binary.take--- | @take n@ extracts the next /n/ bytes from the stream, as a lazy+-- | @'take' n@ extracts the next /n/ bytes from the stream, as a lazy -- ByteString. -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.Binary.takeWhile--- | @takeWhile p@ extracts input from the stream until the first byte which+-- | @'takeWhile' p@ extracts input from the stream until the first byte which -- does not match the predicate. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.Binary.unfold+-- | Enumerates a stream of bytes by repeatedly applying a function to+-- some state.+--+-- Similar to 'iterate'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Binary.unfoldM+-- | Enumerates a stream of bytes by repeatedly applying a computation to+-- some state.+--+-- Similar to 'iterateM'.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.IO.enumFile--- | Deprecated in 0.4.5: use 'Data.Enumerator.Binary.enumFile' instead+-- | Deprecated in 0.4.5: use 'EB.enumFile' instead :  :d apidoc Data.Enumerator.IO.enumHandle--- | Deprecated in 0.4.5: use 'Data.Enumerator.Binary.enumHandle' instead+-- | Deprecated in 0.4.5: use 'EB.enumHandle' instead :  :d apidoc Data.Enumerator.IO.iterHandle--- | Deprecated in 0.4.5: use 'Data.Enumerator.Binary.iterHandle' instead+-- | Deprecated in 0.4.5: use 'EB.iterHandle' instead : +:d apidoc Data.Enumerator.List.concatMap+-- | @'concatMap' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.concatMapM+-- | @'concatMapM' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+: :d apidoc Data.Enumerator.List.consume--- | Read all remaining input elements from the stream, and return as a list.+-- | @'consume' = 'takeWhile' (const True)@ -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.List.drop--- | @drop n@ ignores /n/ input elements from the stream.+-- | @'drop' n@ ignores /n/ input elements from the stream. -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.List.dropWhile--- | @dropWhile p@ ignores input from the stream until the first element+-- | @'dropWhile' p@ ignores input from the stream until the first element -- which does not match the predicate. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.List.filter+-- | Applies a predicate to the stream. The inner iteratee only receives+-- elements for which the predicate is @True@.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.filterM+-- | Applies a monadic predicate to the stream. The inner iteratee only+-- receives elements for which the predicate returns @True@.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.fold+-- | Consume the entire input stream with a strict left fold, one element+-- at a time.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.foldM+-- | Consume the entire input stream with a strict monadic left fold, one+-- element at a time.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.generateM+-- | Like 'repeatM', except the computation may terminate the stream by+-- returning 'Nothing'.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.List.head -- | Get the next element from the stream, or 'Nothing' if the stream has -- ended.@@ -578,42 +788,136 @@ :  :d apidoc Data.Enumerator.List.isolate--- | @isolate n@ reads at most /n/ elements from the stream, and passes them+-- | @'isolate' n@ reads at most /n/ elements from the stream, and passes them -- to its iteratee. If the iteratee finishes early, elements continue to be -- consumed from the outer stream until /n/ have been consumed. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.List.iterate+-- | @'iterate' f x@ enumerates an infinite stream of repeated applications+-- of /f/ to /x/.+--+-- Analogous to 'Prelude.iterate'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.iterateM+-- | Similar to 'iterate', except the iteration function is monadic.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.map+-- | @'map' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.mapM+-- | @'mapM' f@ applies /f/ to each input element and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.repeat+-- | Enumerates an infinite stream of a single element.+--+-- Analogous to 'Prelude.repeat'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.repeatM+-- | Enumerates an infinite stream of element. Each element is computed by+-- the underlying monad.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.replicate+-- | @'replicate' n x@ enumerates a stream containing /n/ copies of /x/.+--+-- Analogous to 'Prelude.replicate'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.replicateM+-- | @'replicateM' n m_x@ enumerates a stream of /n/ elements, with each+-- element computed by /m_x/.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.List.require--- | @require n@ buffers input until at least /n/ elements are available, or+-- | @'require' n@ buffers input until at least /n/ elements are available, or -- throws an error if the stream ends early. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.List.splitWhen+-- | Split on elements satisfying a given predicate.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.List.take--- | @take n@ extracts the next /n/ elements from the stream, as a list.+-- | @'take' n@ extracts the next /n/ elements from the stream, as a list. -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.List.takeWhile--- | @takeWhile p@ extracts input from the stream until the first element+-- | @'takeWhile' p@ extracts input from the stream until the first element -- which does not match the predicate. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.List.unfold+-- | Enumerates a stream of elements by repeatedly applying a function to+-- some state.+--+-- Similar to 'iterate'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.List.unfoldM+-- | Enumerates a stream of elements by repeatedly applying a computation to+-- some state.+--+-- Similar to 'iterateM'.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Text.Codec--- | docs TODO+-- | Since: 0.2+:++:d apidoc Data.Enumerator.Text.concatMap+-- | @'concatMap' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee. ----- Since: 0.2+-- Since: 0.4.8 : +:d apidoc Data.Enumerator.Text.concatMapM+-- | @'concatMapM' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Text.consume--- | Read all remaining input from the stream, and return as a lazy--- Text.+-- | @'consume' = 'takeWhile' (const True)@ -- -- Since: 0.4.5 :@@ -626,13 +930,13 @@ :  :d apidoc Data.Enumerator.Text.drop--- | @drop n@ ignores /n/ characters of input from the stream.+-- | @'drop' n@ ignores /n/ characters of input from the stream. -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.Text.dropWhile--- | @dropWhile p@ ignores input from the stream until the first character+-- | @'dropWhile' p@ ignores input from the stream until the first character -- which does not match the predicate. -- -- Since: 0.4.5@@ -663,6 +967,41 @@ -- Since: 0.2 : +:d apidoc Data.Enumerator.Text.filter+-- | Applies a predicate to the stream. The inner iteratee only receives+-- characters for which the predicate is @True@.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.filterM+-- | Applies a monadic predicate to the stream. The inner iteratee only+-- receives characters for which the predicate returns @True@.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.fold+-- | Consume the entire input stream with a strict left fold, one character+-- at a time.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.foldM+-- | Consume the entire input stream with a strict monadic left fold, one+-- character at a time.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.generateM+-- | Like 'repeatM', except the computation may terminate the stream by+-- returning 'Nothing'.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Text.head -- | Get the next character from the stream, or 'Nothing' if the stream has -- ended.@@ -671,13 +1010,28 @@ :  :d apidoc Data.Enumerator.Text.isolate--- | @isolate n@ reads at most /n/ characters from the stream, and passes+-- | @'isolate' n@ reads at most /n/ characters from the stream, and passes -- them to its iteratee. If the iteratee finishes early, characters continue -- to be consumed from the outer stream until /n/ have been consumed. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.Text.iterate+-- | @'iterate' f x@ enumerates an infinite stream of repeated applications+-- of /f/ to /x/.+--+-- Analogous to 'Prelude.iterate'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.iterateM+-- | Similar to 'iterate', except the iteration function is monadic.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Text.iterHandle -- | Read text from a stream and write it to a handle. If an exception -- occurs during file IO, enumeration will stop and 'Error' will be@@ -689,23 +1043,95 @@ -- Since: 0.2 : +:d apidoc Data.Enumerator.Text.lines+-- | @'lines' = 'splitWhen' (== '\n')@+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.map+-- | @'map' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.mapM+-- | @'mapM' f@ applies /f/ to each input character and feeds the+-- resulting outputs to the inner iteratee.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.repeat+-- | Enumerates an infinite stream of a single character.+--+-- Analogous to 'Prelude.repeat'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.repeatM+-- | Enumerates an infinite stream of characters. Each character is computed+-- by the underlying monad.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.replicate+-- | @'replicate' n x@ enumerates a stream containing /n/ copies of /x/.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.replicateM+-- | @'replicateM' n m_x@ enumerates a stream of /n/ characters, with each+-- character computed by /m_x/.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Text.require--- | @require n@ buffers input until at least /n/ characters are available,+-- | @'require' n@ buffers input until at least /n/ characters are available, -- or throws an error if the stream ends early. -- -- Since: 0.4.5 : +:d apidoc Data.Enumerator.Text.splitWhen+-- | Split on characters satisfying a given predicate.+--+-- Since: 0.4.8+:+ :d apidoc Data.Enumerator.Text.take--- | @take n@ extracts the next /n/ characters from the stream, as a lazy+-- | @'take' n@ extracts the next /n/ characters from the stream, as a lazy -- Text. -- -- Since: 0.4.5 :  :d apidoc Data.Enumerator.Text.takeWhile--- | @takeWhile p@ extracts input from the stream until the first character+-- | @'takeWhile' p@ extracts input from the stream until the first character -- which does not match the predicate. -- -- Since: 0.4.5+:++:d apidoc Data.Enumerator.Text.unfold+-- | Enumerates a stream of characters by repeatedly applying a function to+-- some state.+--+-- Similar to 'iterate'.+--+-- Since: 0.4.8+:++:d apidoc Data.Enumerator.Text.unfoldM+-- | Enumerates a stream of characters by repeatedly applying a computation+-- to some state.+--+-- Similar to 'iterateM'.+--+-- Since: 0.4.8 :
− src/binary.anansi
@@ -1,222 +0,0 @@-\section{Binary}--:f Data/Enumerator/Binary.hs-|Data.Enumerator.Binary module header|-module Data.Enumerator.Binary (-	|Data.Enumerator.Binary exports|-	) where-import Prelude hiding (head, drop, takeWhile)-import Data.Enumerator hiding (head, drop)-import qualified Data.ByteString as B-|Data.Enumerator.Binary imports|-:--\subsection{IO}--{\tt enumHandle} and {\tt enumFile} are rough analogues of-{\tt hGetContents} and {\tt readFile} from the standard library, except-they operate only in binary mode.--Any exceptions thrown while reading or writing data are caught and reported-using {\tt throwError}, so errors can be handled in pure iteratees.--:d Data.Enumerator.Binary imports-import Data.Enumerator.Util (tryStep)-import qualified Control.Exception as Exc-import Control.Monad.IO.Class (MonadIO)-import qualified System.IO as IO-import System.IO.Error (isEOFError)-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.enumHandle|-enumHandle :: MonadIO m-           => Integer -- ^ Buffer size-           -> IO.Handle-           -> Enumerator B.ByteString m b-enumHandle bufferSize h = loop where-	loop (Continue k) = withBytes $ \bytes ->-		if B.null bytes-			then continue k-			else k (Chunks [bytes]) >>== loop-	-	loop step = returnI step-	-	intSize = fromInteger bufferSize-	withBytes = tryStep $ do-		hasInput <- Exc.catch-			(IO.hWaitForInput h (-1))-			(\err -> if isEOFError err-				then return False-				else Exc.throwIO err)-		if hasInput-			then B.hGetNonBlocking h intSize-			else return B.empty-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.enumFile|-enumFile :: FilePath -> Enumerator B.ByteString IO b-enumFile path = enum where-	withHandle = tryStep (IO.openBinaryFile path IO.ReadMode)-	enum step = withHandle $ \h -> do-		Iteratee $ Exc.finally-			(runIteratee (enumHandle 4096 h step))-			(IO.hClose h)-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.iterHandle|-iterHandle :: MonadIO m => IO.Handle-           -> Iteratee B.ByteString m ()-iterHandle h = continue step where-	step EOF = yield () EOF-	step (Chunks []) = continue step-	step (Chunks bytes) = let-		put = mapM_ (B.hPut h) bytes-		in tryStep put (\_ -> continue step)-:--:d Data.Enumerator.Binary exports-  -- * Binary IO-  enumHandle-, enumFile-, iterHandle-:--\subsection{List analogues}--:d Data.Enumerator.Binary imports-import Data.Word (Word8)-import qualified Data.ByteString.Lazy as BL-:--:f Data/Enumerator/Binary.hs-toChunks :: BL.ByteString -> Stream B.ByteString-toChunks = Chunks . BL.toChunks-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.head|-head :: Monad m => Iteratee B.ByteString m (Maybe Word8)-head = continue loop where-	loop (Chunks xs) = case BL.uncons (BL.fromChunks xs) of-		Just (char, extra) -> yield (Just char) (toChunks extra)-		Nothing -> head-	loop EOF = yield Nothing EOF-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.drop|-drop :: Monad m => Integer -> Iteratee B.ByteString m ()-drop n | n <= 0 = return ()-drop n = continue (loop n) where-	loop n' (Chunks xs) = iter where-		lazy = BL.fromChunks xs-		len = toInteger (BL.length lazy)-		iter = if len < n'-			then drop (n' - len)-			else yield () (toChunks (BL.drop (fromInteger n') lazy))-	loop _ EOF = yield () EOF-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.dropWhile|-dropWhile :: Monad m => (Word8 -> Bool) -> Iteratee B.ByteString m ()-dropWhile p = continue loop where-	loop (Chunks xs) = iter where-		lazy = BL.dropWhile p (BL.fromChunks xs)-		iter = if BL.null lazy-			then continue loop-			else yield () (toChunks lazy)-	loop EOF = yield () EOF-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.take|-take :: Monad m => Integer -> Iteratee B.ByteString m BL.ByteString-take n | n <= 0 = return BL.empty-take n = continue (loop id n) where-	loop acc n' (Chunks xs) = iter where-		lazy = BL.fromChunks xs-		len = toInteger (BL.length lazy)-		-		iter = if len < n'-			then continue (loop (acc . (BL.append lazy)) (n' - len))-			else let-				(xs', extra) = BL.splitAt (fromInteger n') lazy-				in yield (acc xs') (toChunks extra)-	loop acc _ EOF = yield (acc BL.empty) EOF-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.takeWhile|-takeWhile :: Monad m => (Word8 -> Bool) -> Iteratee B.ByteString m BL.ByteString-takeWhile p = continue (loop id) where-	loop acc (Chunks []) = continue (loop acc)-	loop acc (Chunks xs) = iter where-		lazy = BL.fromChunks xs-		(xs', extra) = BL.span p lazy-		iter = if BL.null extra-			then continue (loop (acc . (BL.append lazy)))-			else yield (acc xs') (toChunks extra)-	loop acc EOF = yield (acc BL.empty) EOF-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.consume|-consume :: Monad m => Iteratee B.ByteString m BL.ByteString-consume = continue (loop id) where-	loop acc (Chunks []) = continue (loop acc)-	loop acc (Chunks xs) = iter where-		lazy = BL.fromChunks xs-		iter = continue (loop (acc . (BL.append lazy)))-	loop acc EOF = yield (acc BL.empty) EOF-:--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.require|-require :: Monad m => Integer -> Iteratee B.ByteString m ()-require n | n <= 0 = return ()-require n = continue (loop id n) where-	loop acc n' (Chunks xs) = iter where-		lazy = BL.fromChunks xs-		len = toInteger (BL.length lazy)-		iter = if len < n'-			then continue (loop (acc . (BL.append lazy)) (n' - len))-			else yield () (toChunks (acc lazy))-	loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF")-:--Same caveats as {\tt Data.Enumerator.List.isolate}--:f Data/Enumerator/Binary.hs-|apidoc Data.Enumerator.Binary.isolate|-isolate :: Monad m => Integer -> Enumeratee B.ByteString B.ByteString m b-isolate n step | n <= 0 = return step-isolate n (Continue k) = continue loop where-	loop (Chunks []) = continue loop-	loop (Chunks xs) = iter where-		lazy = BL.fromChunks xs-		len = toInteger (BL.length lazy)-		-		iter = if len <= n-			then k (Chunks xs) >>== isolate (n - len)-			else let-				(s1, s2) = BL.splitAt (fromInteger n) lazy-				in k (toChunks s1) >>== (\step -> yield step (toChunks s2))-	loop EOF = k EOF >>== (\step -> yield step EOF)-isolate n step = drop n >> return step-:--:d Data.Enumerator.Binary exports--- * List analogues-, Data.Enumerator.Binary.head-, Data.Enumerator.Binary.drop-, Data.Enumerator.Binary.dropWhile-, Data.Enumerator.Binary.take-, Data.Enumerator.Binary.takeWhile-, Data.Enumerator.Binary.consume-, require-, isolate-:
− src/compat.anansi
@@ -1,237 +0,0 @@-\section{Compatibility}--Version 0.4.5 of this library introduced some substantial reorganization-and renamings; this section implements compatibility shims, so the API-remains stable.--:d Data.Enumerator exports--- * Compatibility-:--\subsection{Obsolete functions}--These are functions which seemed like good ideas, or were defined by other-enumerator/iteratee libraries, but turned out to be basically useless. At-least, I've never figured out what they're good for.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.liftTrans|-liftTrans :: (Monad m, MonadTrans t, Monad (t m)) =>-             Iteratee a m b -> Iteratee a (t m) b-liftTrans iter = Iteratee $ do-	step <- lift (runIteratee iter)-	return $ case step of-		Yield x cs -> Yield x cs-		Error err -> Error err-		Continue k -> Continue (liftTrans . k)-:--:f Data/Enumerator.hs-{-# DEPRECATED liftI-     "Use 'Data.Enumerator.continue' instead" #-}-|apidoc Data.Enumerator.liftI|-liftI :: Monad m => (Stream a -> Step a m b)-      -> Iteratee a m b-liftI k = continue (returnI . k)-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.peek|-peek :: Monad m => Iteratee a m (Maybe a)-peek = continue loop where-	loop (Chunks []) = continue loop-	loop chunk@(Chunks (x:_)) = yield (Just x) chunk-	loop EOF = yield Nothing EOF-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.last|-last :: Monad m => Iteratee a m (Maybe a)-last = continue (loop Nothing) where-	loop ret (Chunks xs) = continue . loop $ case xs of-		[] -> ret-		_ -> Just (Prelude.last xs)-	loop ret EOF = yield ret EOF-:--:d Data.Enumerator imports-import Data.List (genericLength)-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.length|-length :: Monad m => Iteratee a m Integer-length = continue (loop 0) where-	len = genericLength-	loop n (Chunks xs) = continue (loop (n + len xs))-	loop n EOF = yield n EOF-:--:d Data.Enumerator exports--- ** Obsolete functions-, liftTrans-, liftI-, peek-, Data.Enumerator.last-, Data.Enumerator.length-:--\subsection{Aliases}--In previous library versions, several list-based iteratees were defined in-{\tt Data.Enumerator}. They are now defined in {\tt Data.Enumerator.List};-because these functions use core enumerator types, a bit of module-gymnastics is required to get everything compiling properly.--:f Data/Enumerator.hs-boot-module Data.Enumerator where-import qualified Control.Exception as Exc-data Stream a-data Step a m b-	= Continue (Stream a -> Iteratee a m b)-	| Yield b (Stream a)-	| Error Exc.SomeException-newtype Iteratee a m b = Iteratee-	{ runIteratee :: m (Step a m b)-	}-:--:f Data/Enumerator/List.hs-boot-module Data.Enumerator.List where-import {-# SOURCE #-} Data.Enumerator-head :: Monad m => Iteratee a m (Maybe a)-drop :: Monad m => Integer -> Iteratee a m ()-dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()-takeWhile :: Monad m => (a -> Bool) -> Iteratee a m [a]-consume :: Monad m => Iteratee a m [a]-:--:d Data.Enumerator imports-import {-# SOURCE #-} qualified Data.Enumerator.List as EL-:--These {\tt .hs-boot} files are enough for {\tt Data.Enumerator} to re-export-the list functions under old names, with appropriate deprecation warnings.--:f Data/Enumerator.hs-{-# DEPRECATED head-     "Use 'Data.Enumerator.List.head' instead" #-}-|apidoc Data.Enumerator.head|-head :: Monad m => Iteratee a m (Maybe a)-head = EL.head--{-# DEPRECATED drop-     "Use 'Data.Enumerator.List.drop' instead" #-}-|apidoc Data.Enumerator.drop|-drop :: Monad m => Integer -> Iteratee a m ()-drop = EL.drop--{-# DEPRECATED dropWhile-     "Use 'Data.Enumerator.List.dropWhile' instead" #-}-|apidoc Data.Enumerator.dropWhile|-dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()-dropWhile = EL.dropWhile--{-# DEPRECATED span-     "Use 'Data.Enumerator.List.takeWhile' instead" #-}-|apidoc Data.Enumerator.span|-span :: Monad m => (a -> Bool) -> Iteratee a m [a]-span = EL.takeWhile--{-# DEPRECATED break-     "Use 'Data.Enumerator.List.takeWhile' instead" #-}-|apidoc Data.Enumerator.break|-break :: Monad m => (a -> Bool) -> Iteratee a m [a]-break p = EL.takeWhile (not . p)--{-# DEPRECATED consume-     "Use 'Data.Enumerator.List.consume' instead" #-}-|apidoc Data.Enumerator.consume|-consume :: Monad m => Iteratee a m [a]-consume = EL.consume-:--:d Data.Enumerator exports--- ** Deprecated aliases-, Data.Enumerator.head-, Data.Enumerator.drop-, Data.Enumerator.dropWhile-, Data.Enumerator.span-, Data.Enumerator.break-, Data.Enumerator.consume-:--0.4.5 also saw the pure-fold enumerators renamed, to match other functions-based on {\tt Prelude} names.--:f Data/Enumerator.hs-{-# DEPRECATED liftFoldL-     "Use 'Data.Enumerator.foldl' instead" #-}-|apidoc Data.Enumerator.liftFoldL|-liftFoldL :: Monad m => (b -> a -> b) -> b-          -> Iteratee a m b-liftFoldL = Data.Enumerator.foldl--{-# DEPRECATED liftFoldL'-     "Use 'Data.Enumerator.foldl' ' instead" #-}-|apidoc Data.Enumerator.liftFoldL'|-liftFoldL' :: Monad m => (b -> a -> b) -> b-           -> Iteratee a m b-liftFoldL' = Data.Enumerator.foldl'--{-# DEPRECATED liftFoldM-     "Use 'Data.Enumerator.foldM' instead" #-}-|apidoc Data.Enumerator.liftFoldM|-liftFoldM :: Monad m => (b -> a -> m b) -> b-          -> Iteratee a m b-liftFoldM = Data.Enumerator.foldM-:--:d Data.Enumerator exports-, liftFoldL-, liftFoldL'-, liftFoldM-:--\clearpage-Finally, the {\tt Data.Enumerator.IO} module was moved to-{\tt Data.Enumerator.Binary}, and altered to include many more functions-related to binary and {\tt ByteString} processing.--:f Data/Enumerator/IO.hs-|Data.Enumerator.IO module header|-module Data.Enumerator.IO-	{-# DEPRECATED-	     "Use 'Data.Enumerator.Binary' instead" #-}-	( enumHandle-	, enumFile-	, iterHandle-	) where-import qualified Data.Enumerator as E-import qualified Data.Enumerator.Binary as EB-import Control.Monad.IO.Class (MonadIO)-import qualified Data.ByteString as B-import qualified System.IO as IO--{-# DEPRECATED enumHandle-     "Use 'Data.Enumerator.Binary.enumHandle' instead" #-}-|apidoc Data.Enumerator.IO.enumHandle|-enumHandle :: MonadIO m-           => Integer-           -> IO.Handle-           -> E.Enumerator B.ByteString m b-enumHandle = EB.enumHandle--{-# DEPRECATED enumFile-     "Use 'Data.Enumerator.Binary.enumFile' instead" #-}-|apidoc Data.Enumerator.IO.enumFile|-enumFile :: FilePath -> E.Enumerator B.ByteString IO b-enumFile = EB.enumFile--{-# DEPRECATED iterHandle-     "Use 'Data.Enumerator.Binary.iterHandle' instead" #-}-|apidoc Data.Enumerator.IO.iterHandle|-iterHandle :: MonadIO m => IO.Handle-           -> E.Iteratee B.ByteString m ()-iterHandle = EB.iterHandle-:
+ src/compatibility.anansi view
@@ -0,0 +1,287 @@+\section{Legacy compatibility}++Version 0.4.5 of this library introduced some substantial reorganization+and renamings; this section implements compatibility shims, so the API+remains stable.++\subsection{Obsolete functions}++These are functions which seemed like good ideas, or were defined by other+enumerator/iteratee libraries, but turned out to be basically useless. At+least, I've never figured out what they're good for.++:d compatibility: obsolete+|apidoc Data.Enumerator.liftTrans|+liftTrans :: (Monad m, MonadTrans t, Monad (t m)) =>+             Iteratee a m b -> Iteratee a (t m) b+liftTrans iter = Iteratee $ do+	step <- lift (runIteratee iter)+	return $ case step of+		Yield x cs -> Yield x cs+		Error err -> Error err+		Continue k -> Continue (liftTrans . k)+:++:d compatibility: obsolete+{-# DEPRECATED liftI "Use 'Data.Enumerator.continue' instead" #-}+|apidoc Data.Enumerator.liftI|+liftI :: Monad m => (Stream a -> Step a m b)+      -> Iteratee a m b+liftI k = continue (returnI . k)+:++:d compatibility: obsolete+|apidoc Data.Enumerator.peek|+peek :: Monad m => Iteratee a m (Maybe a)+peek = continue loop where+	loop (Chunks []) = continue loop+	loop chunk@(Chunks (x:_)) = yield (Just x) chunk+	loop EOF = yield Nothing EOF+:++:d compatibility: obsolete+|apidoc Data.Enumerator.last|+last :: Monad m => Iteratee a m (Maybe a)+last = continue (loop Nothing) where+	loop ret (Chunks xs) = continue . loop $ case xs of+		[] -> ret+		_ -> Just (Prelude.last xs)+	loop ret EOF = yield ret EOF+:++:d compatibility: obsolete+|apidoc Data.Enumerator.length|+length :: Monad m => Iteratee a m Integer+length = continue (loop 0) where+	len = genericLength+	loop n (Chunks xs) = continue (loop (n + len xs))+	loop n EOF = yield n EOF+:++\subsection{Aliases}++In previous library versions, several list-based iteratees were defined in+{\tt Data.Enumerator}. They are now defined in {\tt Data.Enumerator.List};+because these functions use core enumerator types, a bit of module+gymnastics is required to get everything compiling properly.++:f Data/Enumerator.hs-boot+module Data.Enumerator where+import qualified Control.Exception as Exc+data Stream a+data Step a m b+	= Continue (Stream a -> Iteratee a m b)+	| Yield b (Stream a)+	| Error Exc.SomeException+newtype Iteratee a m b = Iteratee+	{ runIteratee :: m (Step a m b)+	}+type Enumerator a m b = Step a m b -> Iteratee a m b+type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b)+:++:f Data/Enumerator/List.hs-boot+module Data.Enumerator.List where+import {-# SOURCE #-} Data.Enumerator+head :: Monad m => Iteratee a m (Maybe a)+drop :: Monad m => Integer -> Iteratee a m ()+dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()+takeWhile :: Monad m => (a -> Bool) -> Iteratee a m [a]+consume :: Monad m => Iteratee a m [a]+fold :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b+iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b+repeat :: Monad m => a -> Enumerator a m b+repeatM :: Monad m => m a -> Enumerator a m b+replicateM :: Monad m => Integer -> m a -> Enumerator a m b+replicate :: Monad m => Integer -> a -> Enumerator a m b+generateM :: Monad m => m (Maybe a) -> Enumerator a m b+map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b+mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b+concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b+concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b+filter :: Monad m => (a -> Bool) -> Enumeratee a a m b+filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b+:++These {\tt .hs-boot} files are enough for {\tt Data.Enumerator} to re-export+the list functions under old names, with appropriate deprecation warnings.++:d compatibility: aliases+{-# DEPRECATED head "Use 'Data.Enumerator.List.head' instead" #-}+|apidoc Data.Enumerator.head|+head :: Monad m => Iteratee a m (Maybe a)+head = EL.head++{-# DEPRECATED drop "Use 'Data.Enumerator.List.drop' instead" #-}+|apidoc Data.Enumerator.drop|+drop :: Monad m => Integer -> Iteratee a m ()+drop = EL.drop++{-# DEPRECATED dropWhile "Use 'Data.Enumerator.List.dropWhile' instead" #-}+|apidoc Data.Enumerator.dropWhile|+dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()+dropWhile = EL.dropWhile++{-# DEPRECATED span "Use 'Data.Enumerator.List.takeWhile' instead" #-}+|apidoc Data.Enumerator.span|+span :: Monad m => (a -> Bool) -> Iteratee a m [a]+span = EL.takeWhile++{-# DEPRECATED break "Use 'Data.Enumerator.List.takeWhile' instead" #-}+|apidoc Data.Enumerator.break|+break :: Monad m => (a -> Bool) -> Iteratee a m [a]+break p = EL.takeWhile (not . p)++{-# DEPRECATED consume "Use 'Data.Enumerator.List.consume' instead" #-}+|apidoc Data.Enumerator.consume|+consume :: Monad m => Iteratee a m [a]+consume = EL.consume++{-# DEPRECATED foldl "Use Data.Enumerator.List.fold instead" #-}+|apidoc Data.Enumerator.foldl|+foldl :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldl step = continue . loop where+	fold = Prelude.foldl step+	loop acc stream = case stream of+		Chunks [] -> continue (loop acc)+		Chunks xs -> continue (loop (fold acc xs))+		EOF -> yield acc EOF++{-# DEPRECATED foldl' "Use Data.Enumerator.List.fold instead" #-}+|apidoc Data.Enumerator.foldl'|+foldl' :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldl' = EL.fold++{-# DEPRECATED foldM "Use Data.Enumerator.List.foldM instead" #-}+|apidoc Data.Enumerator.foldM|+foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b+foldM = EL.foldM++{-# DEPRECATED iterate "Use Data.Enumerator.List.iterate instead" #-}+|apidoc Data.Enumerator.iterate|+iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+iterate = EL.iterate++{-# DEPRECATED iterateM "Use Data.Enumerator.List.iterateM instead" #-}+|apidoc Data.Enumerator.iterateM|+iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b+iterateM = EL.iterateM++{-# DEPRECATED repeat "Use Data.Enumerator.List.repeat instead" #-}+|apidoc Data.Enumerator.repeat|+repeat :: Monad m => a -> Enumerator a m b+repeat = EL.repeat++{-# DEPRECATED repeatM "Use Data.Enumerator.List.repeatM instead" #-}+|apidoc Data.Enumerator.repeatM|+repeatM :: Monad m => m a -> Enumerator a m b+repeatM = EL.repeatM++{-# DEPRECATED replicate "Use Data.Enumerator.List.replicate instead" #-}+|apidoc Data.Enumerator.replicate|+replicate :: Monad m => Integer -> a -> Enumerator a m b+replicate = EL.replicate++{-# DEPRECATED replicateM "Use Data.Enumerator.List.replicateM instead" #-}+|apidoc Data.Enumerator.replicateM|+replicateM :: Monad m => Integer -> m a -> Enumerator a m b+replicateM = EL.replicateM++{-# DEPRECATED generateM "Use Data.Enumerator.List.generateM instead" #-}+|apidoc Data.Enumerator.generateM|+generateM :: Monad m => m (Maybe a) -> Enumerator a m b+generateM = EL.generateM++{-# DEPRECATED map "Use Data.Enumerator.List.map instead" #-}+|apidoc Data.Enumerator.map|+map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b+map = EL.map++{-# DEPRECATED mapM "Use Data.Enumerator.List.mapM instead" #-}+|apidoc Data.Enumerator.mapM|+mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b+mapM = EL.mapM++{-# DEPRECATED concatMap "Use Data.Enumerator.List.concatMap instead" #-}+|apidoc Data.Enumerator.concatMap|+concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b+concatMap = EL.concatMap++{-# DEPRECATED concatMapM "Use Data.Enumerator.List.concatMapM instead" #-}+|apidoc Data.Enumerator.concatMapM|+concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b+concatMapM = EL.concatMapM++{-# DEPRECATED filter "Use Data.Enumerator.List.filter instead" #-}+|apidoc Data.Enumerator.filter|+filter :: Monad m => (a -> Bool) -> Enumeratee a a m b+filter = EL.filter++{-# DEPRECATED filterM "Use Data.Enumerator.List.filterM instead" #-}+|apidoc Data.Enumerator.filterM|+filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b+filterM = EL.filterM+:++0.4.5 also saw the pure-fold enumerators renamed, to match other functions+based on {\tt Prelude} names.++:d compatibility: aliases+{-# DEPRECATED liftFoldL "Use Data.Enumerator.List.fold instead" #-}+|apidoc Data.Enumerator.liftFoldL|+liftFoldL :: Monad m => (b -> a -> b) -> b+          -> Iteratee a m b+liftFoldL = Data.Enumerator.foldl++{-# DEPRECATED liftFoldL' "Use Data.Enumerator.List.fold instead" #-}+|apidoc Data.Enumerator.liftFoldL'|+liftFoldL' :: Monad m => (b -> a -> b) -> b+           -> Iteratee a m b+liftFoldL' = EL.fold++{-# DEPRECATED liftFoldM "Use Data.Enumerator.List.foldM instead" #-}+|apidoc Data.Enumerator.liftFoldM|+liftFoldM :: Monad m => (b -> a -> m b) -> b+          -> Iteratee a m b+liftFoldM = EL.foldM+:++Finally, the {\tt Data.Enumerator.IO} module was moved to+{\tt Data.Enumerator.Binary}, and altered to include many more functions+related to binary and {\tt ByteString} processing.++:f Data/Enumerator/IO.hs+|Data.Enumerator.IO module header|+module Data.Enumerator.IO+	{-# DEPRECATED "Use 'Data.Enumerator.Binary' instead" #-}+	( enumHandle+	, enumFile+	, iterHandle+	) where+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import Control.Monad.IO.Class (MonadIO)+import qualified Data.ByteString as B+import qualified System.IO as IO++{-# DEPRECATED enumHandle "Use 'Data.Enumerator.Binary.enumHandle' instead" #-}+|apidoc Data.Enumerator.IO.enumHandle|+enumHandle :: MonadIO m+           => Integer+           -> IO.Handle+           -> E.Enumerator B.ByteString m b+enumHandle = EB.enumHandle++{-# DEPRECATED enumFile "Use 'Data.Enumerator.Binary.enumFile' instead" #-}+|apidoc Data.Enumerator.IO.enumFile|+enumFile :: FilePath -> E.Enumerator B.ByteString IO b+enumFile = EB.enumFile++{-# DEPRECATED iterHandle "Use 'Data.Enumerator.Binary.iterHandle' instead" #-}+|apidoc Data.Enumerator.IO.iterHandle|+iterHandle :: MonadIO m => IO.Handle+           -> E.Iteratee B.ByteString m ()+iterHandle = EB.iterHandle+:
src/enumerator.anansi view
@@ -2,22 +2,25 @@ :# :# See license.txt for details -:option tab-size 2+:option tab-size 8  \documentclass{article}  \usepackage{color} \usepackage{hyperref}-\usepackage{noweb} \usepackage{indentfirst} \usepackage{amsmath} \usepackage{multicol}+\usepackage{comment} -\noweboptions{smallcode}+\usepackage{latex/noweb}+\usepackage[margin=3cm]{latex/geometry} -% Smaller margins-\usepackage[left=1cm,top=1cm,right=1cm]{geometry}+\usepackage{titlesec}+\newcommand{\subsectionbreak}{\clearpage} +% \noweboptions{smallcode}+ % Remove boxes from hyperlinks \hypersetup{     colorlinks,@@ -27,59 +30,23 @@  \newcommand{\io}{{\sc i/o}} -\title{enumerator\_0.4.6}+\title{enumerator\_0.4.8} \author{John Millikin\\         \href{mailto:"John Millikin" <jmillikin@gmail.com>}{\tt jmillikin@gmail.com}}-\date{February 03, 2011}+\date{March 19, 2011}  \begin{document} +\newgeometry{left=1.1cm,top=1cm,right=1.1cm}+ \maketitle  \setlength{\parskip}{5pt plus 1pt}+\setlength{\columnsep}{0.8cm}  \begin{multicols}{2}-\section*{Abstract} -Typical buffer-based incremental \io{} is based around a single loop, which-reads data from some source (such as a socket or file), transforms it, and-generates one or more outputs (such as a line count, {\sc http} responses,-or modified file).  Although efficient and safe, these loops are all-single-purpose; it is difficult or impossible to compose buffer-based-processing loops.--Haskell's concept of ``lazy \io{}'' allows pure code to operate on data from-an external source. However, lazy \io{} has several shortcomings. Most notably,-resources such as memory and file handles can be retained for arbitrarily-long periods of time, causing unpredictable performance and error conditions.--Enumerators are an efficient, predictable, and safe alternative to lazy \io{}.-Discovered by Oleg \mbox{Kiselyov}, they allow large datasets to be processed-in near-constant space by pure code. Although somewhat more complex to write,-using enumerators instead of lazy \io{} produces more correct programs.--This library contains an enumerator implementation for Haskell, designed to-be both simple and efficient. Three core types are defined, along with-numerous helper functions:--\begin{itemize}--\item {\it Iteratee\/}: Data sinks, analogous to left folds. Iteratees consume-a sequence of \emph{input} values, and generate a single \emph{output} value.-Many iteratees are designed to perform side effects (such as printing to-{\tt stdout}), so they can also be used as monad transformers.--\item {\it Enumerator\/}: Data sources, which generate input sequences. Typical-enumerators read from a file handle, socket, random number generator, or-other external stream. To operate, enumerators are passed an iteratee, and-provide that iteratee with input until either the iteratee has completed its-computation, or {\sc eof}.--\item {\it Enumeratee\/}: Data transformers, which operate as both enumerators and-iteratees. Enumeratees read from an \emph{outer} enumerator, and provide the-transformed data to an \emph{inner} iteratee.--\end{itemize}+:include summary.anansi  \noindent Homepage: \href{http://john-millikin.com/software/enumerator/}                          {\small \tt http://john-millikin.com/software/enumerator/}@@ -89,31 +56,37 @@ \setlength{\parskip}{4pt plus 1pt} \end{multicols} +\restoregeometry+ \newpage-\begin{multicols*}{2} :include types.anansi  \newpage :include primitives.anansi-\end{multicols*}  \newpage-:include list.anansi+:include list-analogues.anansi  \newpage-:include binary.anansi+:include io.anansi  \newpage-:include text.anansi+:include text-codecs.anansi  \newpage-:include util.anansi+:include utilities.anansi +\appendix+ \newpage-\begin{multicols*}{2}-:include compat.anansi-\end{multicols*}+:include public-interface.anansi +\newpage+:include compatibility.anansi++% exclude API docs from LaTeX output, since they're generally uninteresting+\begin{comment} :include api-docs.anansi+\end{comment}  \end{document}
+ src/io.anansi view
@@ -0,0 +1,148 @@+\section{IO}++\subsection{Binary IO}++{\tt enumHandle} and {\tt enumFile} are rough analogues of+{\tt hGetContents} and {\tt readFile} from the standard library, except+they operate only in binary mode.++Any exceptions thrown while reading or writing data are caught and reported+using {\tt throwError}, so errors can be handled in pure iteratees.++:d binary IO+|apidoc Data.Enumerator.Binary.enumHandle|+enumHandle :: MonadIO m+           => Integer -- ^ Buffer size+           -> IO.Handle+           -> Enumerator B.ByteString m b+enumHandle bufferSize h = do+	let intSize = fromInteger bufferSize+	+	fix $ \loop step -> case step of+		Continue k -> do+			bytes <- tryIO (getBytes h intSize)+			if B.null bytes+				then continue k+				else k (Chunks [bytes]) >>== loop+		_ -> returnI step+:++:d binary IO+|apidoc Data.Enumerator.Binary.enumHandleRange|+enumHandleRange :: MonadIO m+                => Integer -- ^ Buffer size+                -> Maybe Integer -- ^ Offset+                -> Maybe Integer -- ^ Maximum count+                -> IO.Handle+                -> Enumerator B.ByteString m b+enumHandleRange bufferSize offset count h s = seek >> enum where+	seek = case offset of+		Nothing -> return ()+		Just off -> tryIO (IO.hSeek h IO.AbsoluteSeek off)+	+	enum = case count of+		Just n -> loop n s+		Nothing -> enumHandle bufferSize h s+	+	loop n (Continue k) =+		let rem = fromInteger (min bufferSize n) in+		if rem <= 0+			then continue k+			else do+				bytes <- tryIO (getBytes h rem)+				if B.null bytes+					then continue k+					else k (Chunks [bytes]) >>== loop (n - (toInteger (B.length bytes)))+	loop _ step = returnI step+:++:d binary IO+getBytes :: IO.Handle -> Int -> IO B.ByteString+getBytes h n = do+	hasInput <- Exc.catch+		(IO.hWaitForInput h (-1))+		(\err -> if isEOFError err+			then return False+			else Exc.throwIO err)+	if hasInput+		then B.hGetNonBlocking h n+		else return B.empty+:++:d binary IO+|apidoc Data.Enumerator.Binary.enumFile|+enumFile :: FilePath -> Enumerator B.ByteString IO b+enumFile path = enumFileRange path Nothing Nothing+:++:d binary IO+|apidoc Data.Enumerator.Binary.enumFileRange|+enumFileRange :: FilePath+              -> Maybe Integer -- ^ Offset+              -> Maybe Integer -- ^ Maximum count+              -> Enumerator B.ByteString IO b+enumFileRange path offset count step = do+	h <- tryIO (IO.openBinaryFile path IO.ReadMode)+	let iter = enumHandleRange 4096 offset count h step+	Iteratee (Exc.finally (runIteratee iter) (IO.hClose h))+:++:d binary IO+|apidoc Data.Enumerator.Binary.iterHandle|+iterHandle :: MonadIO m => IO.Handle+           -> Iteratee B.ByteString m ()+iterHandle h = continue step where+	step EOF = yield () EOF+	step (Chunks []) = continue step+	step (Chunks bytes) = do+		tryIO (mapM_ (B.hPut h) bytes)+		continue step+:++\subsection{Text IO}++Reading text is similar to reading bytes, but the enumerators have slightly+different behavior -- instead of reading in fixed-size chunks of data, the+text enumerators read in lines. This matches similar text-based {\sc api}s,+such as Python's {\tt xreadlines()}.++:d text IO+|apidoc Data.Enumerator.Text.enumHandle|+enumHandle :: MonadIO m => IO.Handle+           -> Enumerator T.Text m b+enumHandle h = loop where+	loop (Continue k) = do+		maybeText <- tryIO getText+		case maybeText of+			Nothing -> continue k+			Just text -> k (Chunks [text]) >>== loop+	+	loop step = returnI step+	getText = Exc.catch+		(Just `fmap` TIO.hGetLine h)+		(\err -> if isEOFError err+			then return Nothing+			else Exc.throwIO err)+:++:d text IO+|apidoc Data.Enumerator.Text.enumFile|+enumFile :: FilePath -> Enumerator T.Text IO b+enumFile path step = do+	h <- tryIO (IO.openFile path IO.ReadMode)+	Iteratee $ Exc.finally+		(runIteratee (enumHandle h step))+		(IO.hClose h)+:++:d text IO+|apidoc Data.Enumerator.Text.iterHandle|+iterHandle :: MonadIO m => IO.Handle+           -> Iteratee T.Text m ()+iterHandle h = continue step where+	step EOF = yield () EOF+	step (Chunks []) = continue step+	step (Chunks chunks) = do+		tryIO (mapM_ (TIO.hPutStr h) chunks)+		continue step+:
+ src/list-analogues.anansi view
@@ -0,0 +1,812 @@+\section{List analogues}++\subsection{Folds}++Since iteratees are semantically a left-fold, there are many existing+folds that can be lifted to iteratees. The {\tt foldl}, {\tt foldl'}, and+{\tt foldM} functions work like their standard library namesakes, but+construct iteratees instead. These iteratees are not as complex as what can+be created using {\tt Yield} and {\tt Continue}, but cover many common cases.++Each fold consumes input from the stream until {\sc eof}, when it yields its+current accumulator.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.fold|+fold :: Monad m => (b -> a -> b) -> b+       -> Iteratee a m b+fold step = continue . loop where+	f = L.foldl' step+	loop acc stream = case stream of+		Chunks [] -> continue (loop acc)+		Chunks xs -> continue (loop (f acc xs))+		EOF -> yield acc EOF+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.foldM|+foldM :: Monad m => (b -> a -> m b) -> b+      -> Iteratee a m b+foldM step = continue . loop where+	f = CM.foldM step+	+	loop acc stream = acc `seq` case stream of+		Chunks [] -> continue (loop acc)+		Chunks xs -> lift (f acc xs) >>= continue . loop+		EOF -> yield acc EOF+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.fold|+fold :: Monad m => (b -> Word8 -> b) -> b+     -> Iteratee B.ByteString m b+fold step = EL.fold (B.foldl' step)++|apidoc Data.Enumerator.Binary.foldM|+foldM :: Monad m => (b -> Word8 -> m b) -> b+      -> Iteratee B.ByteString m b+foldM step = EL.foldM (\b bytes -> CM.foldM step b (B.unpack bytes))+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.fold|+fold :: Monad m => (b -> Char -> b) -> b+     -> Iteratee T.Text m b+fold step = EL.fold (T.foldl' step)++|apidoc Data.Enumerator.Text.foldM|+foldM :: Monad m => (b -> Char -> m b) -> b+      -> Iteratee T.Text m b+foldM step = EL.foldM (\b txt -> CM.foldM step b (T.unpack txt))+:++\subsection{Unfolds}++:d element-oriented list analogues+|apidoc Data.Enumerator.List.unfold|+unfold :: Monad m => (s -> Maybe (a, s)) -> s -> Enumerator a m b+unfold f = loop where+	loop s (Continue k) = case f s of+		Nothing -> continue k+		Just (a, s') -> k (Chunks [a]) >>== loop s'+	loop _ step = returnI step+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.unfold|+unfold :: Monad m => (s -> Maybe (Word8, s)) -> s -> Enumerator B.ByteString m b+unfold f = loop where+	loop s (Continue k) = case f s of+		Nothing -> continue k+		Just (b, s') -> k (Chunks [B.singleton b]) >>== loop s'+	loop _ step = returnI step+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.unfold|+unfold :: Monad m => (s -> Maybe (Char, s)) -> s -> Enumerator T.Text m b+unfold f = loop where+	loop s (Continue k) = case f s of+		Nothing -> continue k+		Just (c, s') -> k (Chunks [T.singleton c]) >>== loop s'+	loop _ step = returnI step+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.unfoldM|+unfoldM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Enumerator a m b+unfoldM f = loop where+	loop s (Continue k) = do+		fs <- lift (f s)+		case fs of+			Nothing -> continue k+			Just (a, s') -> k (Chunks [a]) >>== loop s'+	loop _ step = returnI step+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.unfoldM|+unfoldM :: Monad m => (s -> m (Maybe (Word8, s))) -> s -> Enumerator B.ByteString m b+unfoldM f = loop where+	loop s (Continue k) = do+		fs <- lift (f s)+		case fs of+			Nothing -> continue k+			Just (b, s') -> k (Chunks [B.singleton b]) >>== loop s'+	loop _ step = returnI step+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.unfoldM|+unfoldM :: Monad m => (s -> m (Maybe (Char, s))) -> s -> Enumerator T.Text m b+unfoldM f = loop where+	loop s (Continue k) = do+		fs <- lift (f s)+		case fs of+			Nothing -> continue k+			Just (c, s') -> k (Chunks [T.singleton c]) >>== loop s'+	loop _ step = returnI step+:++\subsection{Maps}++Enumeratees are conceptually similar to a monadic {\tt concatMap}; each+outer input element is converted to a list of inner inputs, which are passed+to the inner iteratee. Error handling and performance considerations+make most real-life enumeratees more complex, but some don't need the extra+design.++The {\tt checkDone} and {\tt checkDoneEx} functions referenced here are+defined later, with other utilities.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.concatMapM|+concatMapM :: Monad m => (ao -> m [ai])+           -> Enumeratee ao ai m b+concatMapM f = checkDone (continue . step) where+	step k EOF = yield (Continue k) EOF+	step k (Chunks xs) = loop k xs+	+	loop k [] = continue (step k)+	loop k (x:xs) = do+		fx <- lift (f x)+		k (Chunks fx) >>==+			checkDoneEx (Chunks xs) (\k' -> loop k' xs)+:++Once {\tt concatMapM} is defined, similar enumeratees can be easily created+via small wrappers.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.concatMap|+concatMap :: Monad m => (ao -> [ai])+          -> Enumeratee ao ai m b+concatMap f = concatMapM (return . f)++|apidoc Data.Enumerator.List.map|+map :: Monad m => (ao -> ai)+    -> Enumeratee ao ai m b+map f = Data.Enumerator.List.concatMap (\x -> [f x])++|apidoc Data.Enumerator.List.mapM|+mapM :: Monad m => (ao -> m ai)+     -> Enumeratee ao ai m b+mapM f = concatMapM (\x -> Prelude.mapM f [x])+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.map|+map :: Monad m => (Word8 -> Word8) -> Enumeratee B.ByteString B.ByteString m b+map f = Data.Enumerator.Binary.concatMap (\x -> B.singleton (f x))++|apidoc Data.Enumerator.Binary.mapM|+mapM :: Monad m => (Word8 -> m Word8) -> Enumeratee B.ByteString B.ByteString m b+mapM f = Data.Enumerator.Binary.concatMapM (\x -> liftM B.singleton (f x))++|apidoc Data.Enumerator.Binary.concatMap|+concatMap :: Monad m => (Word8 -> B.ByteString) -> Enumeratee B.ByteString B.ByteString m b+concatMap f = Data.Enumerator.Binary.concatMapM (return . f)++|apidoc Data.Enumerator.Binary.concatMapM|+concatMapM :: Monad m => (Word8 -> m B.ByteString) -> Enumeratee B.ByteString B.ByteString m b+concatMapM f = checkDone (continue . step) where+	step k EOF = yield (Continue k) EOF+	step k (Chunks xs) = loop k (BL.unpack (BL.fromChunks xs))+	+	loop k [] = continue (step k)+	loop k (x:xs) = do+		fx <- lift (f x)+		k (Chunks [fx]) >>==+			checkDoneEx (Chunks [B.pack xs]) (\k' -> loop k' xs)+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.map|+map :: Monad m => (Char -> Char) -> Enumeratee T.Text T.Text m b+map f = Data.Enumerator.Text.concatMap (\x -> T.singleton (f x))++|apidoc Data.Enumerator.Text.mapM|+mapM :: Monad m => (Char -> m Char) -> Enumeratee T.Text T.Text m b+mapM f = Data.Enumerator.Text.concatMapM (\x -> liftM T.singleton (f x))++|apidoc Data.Enumerator.Text.concatMap|+concatMap :: Monad m => (Char -> T.Text) -> Enumeratee T.Text T.Text m b+concatMap f = Data.Enumerator.Text.concatMapM (return . f)++|apidoc Data.Enumerator.Text.concatMapM|+concatMapM :: Monad m => (Char -> m T.Text) -> Enumeratee T.Text T.Text m b+concatMapM f = checkDone (continue . step) where+	step k EOF = yield (Continue k) EOF+	step k (Chunks xs) = loop k (TL.unpack (TL.fromChunks xs))+	+	loop k [] = continue (step k)+	loop k (x:xs) = do+		fx <- lift (f x)+		k (Chunks [fx]) >>==+			checkDoneEx (Chunks [T.pack xs]) (\k' -> loop k' xs)+:++\subsection{Infinite streams}++{\tt iterate} and {\tt iterateM} apply a function repeatedly to the base+input, passing the results through as a stream.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.iterate|+iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+iterate f = loop where+	loop a (Continue k) = k (Chunks [a]) >>== loop (f a)+	loop _ step = returnI step+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.iterate|+iterate :: Monad m => (Word8 -> Word8) -> Word8 -> Enumerator B.ByteString m b+iterate f = loop where+	loop byte (Continue k) = k (Chunks [B.singleton byte]) >>== loop (f byte)+	loop _ step = returnI step+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.iterate|+iterate :: Monad m => (Char -> Char) -> Char -> Enumerator T.Text m b+iterate f = loop where+	loop char (Continue k) = k (Chunks [T.singleton char]) >>== loop (f char)+	loop _ step = returnI step+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.iterateM|+iterateM :: Monad m => (a -> m a) -> a+         -> Enumerator a m b+iterateM f base = loop (return base) where+	loop m_a (Continue k) = do+		a <- lift m_a+		k (Chunks [a]) >>== loop (f a)+	loop _ step = returnI step+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.iterateM|+iterateM :: Monad m => (Word8 -> m Word8) -> Word8 -> Enumerator B.ByteString m b+iterateM f base = loop (return base) where+	loop m_byte (Continue k) = do+		byte <- lift m_byte+		k (Chunks [B.singleton byte]) >>== loop (f byte)+	loop _ step = returnI step+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.iterateM|+iterateM :: Monad m => (Char -> m Char) -> Char -> Enumerator T.Text m b+iterateM f base = loop (return base) where+	loop m_char (Continue k) = do+		char <- lift m_char+		k (Chunks [T.singleton char]) >>== loop (f char)+	loop _ step = returnI step+:++{\tt repeat} and {\tt repeatM} create infinite streams, where each input+is a single value.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.repeat|+repeat :: Monad m => a -> Enumerator a m b+repeat a = Data.Enumerator.List.iterate (const a) a+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.repeatM|+repeatM :: Monad m => m a -> Enumerator a m b+repeatM m_a step = do+	a <- lift m_a+	iterateM (const m_a) a step+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.repeat|+repeat :: Monad m => Word8 -> Enumerator B.ByteString m b+repeat byte = EL.repeat (B.singleton byte)++|apidoc Data.Enumerator.Binary.repeatM|+repeatM :: Monad m => m Word8 -> Enumerator B.ByteString m b+repeatM next = EL.repeatM (liftM B.singleton next)+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.repeat|+repeat :: Monad m => Char -> Enumerator T.Text m b+repeat char = EL.repeat (T.singleton char)++|apidoc Data.Enumerator.Text.repeatM|+repeatM :: Monad m => m Char -> Enumerator T.Text m b+repeatM next = EL.repeatM (liftM T.singleton next)+:++\subsection{Bounded streams}++{\tt replicate} and {\tt replicateM} create streams containing a given+quantity of the input value.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.replicateM|+replicateM :: Monad m => Integer -> m a+           -> Enumerator a m b+replicateM maxCount getNext = loop maxCount where+	loop 0 step = returnI step+	loop n (Continue k) = do+		next <- lift getNext+		k (Chunks [next]) >>== loop (n - 1)+	loop _ step = returnI step+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.replicate|+replicate :: Monad m => Integer -> a+          -> Enumerator a m b+replicate maxCount a = replicateM maxCount (return a)+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.replicate|+replicate :: Monad m => Integer -> Word8 -> Enumerator B.ByteString m b+replicate n byte = EL.replicate n (B.singleton byte)++|apidoc Data.Enumerator.Binary.replicateM|+replicateM :: Monad m => Integer -> m Word8 -> Enumerator B.ByteString m b+replicateM n next = EL.replicateM n (liftM B.singleton next)+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.replicate|+replicate :: Monad m => Integer -> Char -> Enumerator T.Text m b+replicate n byte = EL.replicate n (T.singleton byte)++|apidoc Data.Enumerator.Text.replicateM|+replicateM :: Monad m => Integer -> m Char -> Enumerator T.Text m b+replicateM n next = EL.replicateM n (liftM T.singleton next)+:++{\tt generateM} runs a monadic computation until it returns {\tt Nothing},+which signals the end of enumeration.++Note that when the enumerator is finished, it does not send {\tt EOF} to+the iteratee. Instead, it returns a continuation, so additional enumerators+may add their own input to the stream.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.generateM|+generateM :: Monad m => m (Maybe a)+          -> Enumerator a m b+generateM getNext = loop where+	loop (Continue k) = do+		next <- lift getNext+		case next of+			Nothing -> continue k+			Just x -> k (Chunks [x]) >>== loop+	loop step = returnI step+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.generateM|+generateM :: Monad m => m (Maybe Word8) -> Enumerator B.ByteString m b+generateM next = EL.generateM (liftM (liftM B.singleton) next)+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.generateM|+generateM :: Monad m => m (Maybe Char) -> Enumerator T.Text m b+generateM next = EL.generateM (liftM (liftM T.singleton) next)+:++\subsection{Filters}++:d element-oriented list analogues+|apidoc Data.Enumerator.List.filter|+filter :: Monad m => (a -> Bool)+       -> Enumeratee a a m b+filter p = Data.Enumerator.List.concatMap (\x -> [x | p x])+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.filterM|+filterM :: Monad m => (a -> m Bool)+        -> Enumeratee a a m b+filterM p = concatMapM (\x -> CM.filterM p [x])+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.filter|+filter :: Monad m => (Word8 -> Bool) -> Enumeratee B.ByteString B.ByteString m b+filter p = Data.Enumerator.Binary.concatMap (\x -> B.pack [x | p x])++|apidoc Data.Enumerator.Binary.filterM|+filterM :: Monad m => (Word8 -> m Bool) -> Enumeratee B.ByteString B.ByteString m b+filterM p = Data.Enumerator.Binary.concatMapM (\x -> liftM B.pack (CM.filterM p [x]))+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.filter|+filter :: Monad m => (Char -> Bool) -> Enumeratee T.Text T.Text m b+filter p = Data.Enumerator.Text.concatMap (\x -> T.pack [x | p x])++|apidoc Data.Enumerator.Text.filterM|+filterM :: Monad m => (Char -> m Bool) -> Enumeratee T.Text T.Text m b+filterM p = Data.Enumerator.Text.concatMapM (\x -> liftM T.pack (CM.filterM p [x]))+:++\subsection{Consumers}++:d element-oriented list analogues+|apidoc Data.Enumerator.List.take|+take :: Monad m => Integer -> Iteratee a m [a]+take n | n <= 0 = return []+take n = continue (loop id n) where+	len = L.genericLength+	loop acc n' (Chunks xs)+		| len xs < n' = continue (loop (acc . (xs ++)) (n' - len xs))+		| otherwise   = let+			(xs', extra) = L.genericSplitAt n' xs+			in yield (acc xs') (Chunks extra)+	loop acc _ EOF = yield (acc []) EOF+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.take|+take :: Monad m => Integer -> Iteratee B.ByteString m BL.ByteString+take n | n <= 0 = return BL.empty+take n = continue (loop id n) where+	loop acc n' (Chunks xs) = iter where+		lazy = BL.fromChunks xs+		len = toInteger (BL.length lazy)+		+		iter = if len < n'+			then continue (loop (acc . (BL.append lazy)) (n' - len))+			else let+				(xs', extra) = BL.splitAt (fromInteger n') lazy+				in yield (acc xs') (toChunks extra)+	loop acc _ EOF = yield (acc BL.empty) EOF+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.take|+take :: Monad m => Integer -> Iteratee T.Text m TL.Text+take n | n <= 0 = return TL.empty+take n = continue (loop id n) where+	loop acc n' (Chunks xs) = iter where+		lazy = TL.fromChunks xs+		len = toInteger (TL.length lazy)+		+		iter = if len < n'+			then continue (loop (acc . (TL.append lazy)) (n' - len))+			else let+				(xs', extra) = TL.splitAt (fromInteger n') lazy+				in yield (acc xs') (toChunks extra)+	loop acc _ EOF = yield (acc TL.empty) EOF+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.takeWhile|+takeWhile :: Monad m => (a -> Bool) -> Iteratee a m [a]+takeWhile p = continue (loop id) where+	loop acc (Chunks []) = continue (loop acc)+	loop acc (Chunks xs) = case Prelude.span p xs of+		(_, []) -> continue (loop (acc . (xs ++)))+		(xs', extra) -> yield (acc xs') (Chunks extra)+	loop acc EOF = yield (acc []) EOF+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.takeWhile|+takeWhile :: Monad m => (Word8 -> Bool) -> Iteratee B.ByteString m BL.ByteString+takeWhile p = continue (loop id) where+	loop acc (Chunks []) = continue (loop acc)+	loop acc (Chunks xs) = iter where+		lazy = BL.fromChunks xs+		(xs', extra) = BL.span p lazy+		iter = if BL.null extra+			then continue (loop (acc . (BL.append lazy)))+			else yield (acc xs') (toChunks extra)+	loop acc EOF = yield (acc BL.empty) EOF+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.takeWhile|+takeWhile :: Monad m => (Char -> Bool) -> Iteratee T.Text m TL.Text+takeWhile p = continue (loop id) where+	loop acc (Chunks []) = continue (loop acc)+	loop acc (Chunks xs) = iter where+		lazy = TL.fromChunks xs+		(xs', extra) = tlSpanBy p lazy+		iter = if TL.null extra+			then continue (loop (acc . (TL.append lazy)))+			else yield (acc xs') (toChunks extra)+	loop acc EOF = yield (acc TL.empty) EOF+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.consume|+consume :: Monad m => Iteratee a m [a]+consume = continue (loop id) where+	loop acc (Chunks []) = continue (loop acc)+	loop acc (Chunks xs) = continue (loop (acc . (xs ++)))+	loop acc EOF = yield (acc []) EOF+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.consume|+consume :: Monad m => Iteratee B.ByteString m BL.ByteString+consume = continue (loop id) where+	loop acc (Chunks []) = continue (loop acc)+	loop acc (Chunks xs) = iter where+		lazy = BL.fromChunks xs+		iter = continue (loop (acc . (BL.append lazy)))+	loop acc EOF = yield (acc BL.empty) EOF+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.consume|+consume :: Monad m => Iteratee T.Text m TL.Text+consume = continue (loop id) where+	loop acc (Chunks []) = continue (loop acc)+	loop acc (Chunks xs) = iter where+		lazy = TL.fromChunks xs+		iter = continue (loop (acc . (TL.append lazy)))+	loop acc EOF = yield (acc TL.empty) EOF+:++\subsection{Unsorted}++:d element-oriented list analogues+|apidoc Data.Enumerator.List.head|+head :: Monad m => Iteratee a m (Maybe a)+head = continue loop where+	loop (Chunks []) = head+	loop (Chunks (x:xs)) = yield (Just x) (Chunks xs)+	loop EOF = yield Nothing EOF+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.head|+head :: Monad m => Iteratee B.ByteString m (Maybe Word8)+head = continue loop where+	loop (Chunks xs) = case BL.uncons (BL.fromChunks xs) of+		Just (char, extra) -> yield (Just char) (toChunks extra)+		Nothing -> head+	loop EOF = yield Nothing EOF+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.head|+head :: Monad m => Iteratee T.Text m (Maybe Char)+head = continue loop where+	loop (Chunks xs) = case TL.uncons (TL.fromChunks xs) of+		Just (char, extra) -> yield (Just char) (toChunks extra)+		Nothing -> head+	loop EOF = yield Nothing EOF+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.drop|+drop :: Monad m => Integer -> Iteratee a m ()+drop n | n <= 0 = return ()+drop n = continue (loop n) where+	loop n' (Chunks xs) = iter where+		len = L.genericLength xs+		iter = if len < n'+			then drop (n' - len)+			else yield () (Chunks (L.genericDrop n' xs))+	loop _ EOF = yield () EOF+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.drop|+drop :: Monad m => Integer -> Iteratee B.ByteString m ()+drop n | n <= 0 = return ()+drop n = continue (loop n) where+	loop n' (Chunks xs) = iter where+		lazy = BL.fromChunks xs+		len = toInteger (BL.length lazy)+		iter = if len < n'+			then drop (n' - len)+			else yield () (toChunks (BL.drop (fromInteger n') lazy))+	loop _ EOF = yield () EOF+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.drop|+drop :: Monad m => Integer -> Iteratee T.Text m ()+drop n | n <= 0 = return ()+drop n = continue (loop n) where+	loop n' (Chunks xs) = iter where+		lazy = TL.fromChunks xs+		len = toInteger (TL.length lazy)+		iter = if len < n'+			then drop (n' - len)+			else yield () (toChunks (TL.drop (fromInteger n') lazy))+	loop _ EOF = yield () EOF+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.dropWhile|+dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()+dropWhile p = continue loop where+	loop (Chunks xs) = case L.dropWhile p xs of+		[] -> continue loop+		xs' -> yield () (Chunks xs')+	loop EOF = yield () EOF+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.dropWhile|+dropWhile :: Monad m => (Word8 -> Bool) -> Iteratee B.ByteString m ()+dropWhile p = continue loop where+	loop (Chunks xs) = iter where+		lazy = BL.dropWhile p (BL.fromChunks xs)+		iter = if BL.null lazy+			then continue loop+			else yield () (toChunks lazy)+	loop EOF = yield () EOF+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.dropWhile|+dropWhile :: Monad m => (Char -> Bool) -> Iteratee T.Text m ()+dropWhile p = continue loop where+	loop (Chunks xs) = iter where+		lazy = TL.dropWhile p (TL.fromChunks xs)+		iter = if TL.null lazy+			then continue loop+			else yield () (toChunks lazy)+	loop EOF = yield () EOF+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.require|+require :: Monad m => Integer -> Iteratee a m ()+require n | n <= 0 = return ()+require n = continue (loop id n) where+	len = L.genericLength+	loop acc n' (Chunks xs)+		| len xs < n' = continue (loop (acc . (xs ++)) (n' - len xs))+		| otherwise   = yield () (Chunks (acc xs))+	loop _ _ EOF = throwError (ErrorCall "require: Unexpected EOF")+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.require|+require :: Monad m => Integer -> Iteratee B.ByteString m ()+require n | n <= 0 = return ()+require n = continue (loop id n) where+	loop acc n' (Chunks xs) = iter where+		lazy = BL.fromChunks xs+		len = toInteger (BL.length lazy)+		iter = if len < n'+			then continue (loop (acc . (BL.append lazy)) (n' - len))+			else yield () (toChunks (acc lazy))+	loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF")+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.require|+require :: Monad m => Integer -> Iteratee T.Text m ()+require n | n <= 0 = return ()+require n = continue (loop id n) where+	loop acc n' (Chunks xs) = iter where+		lazy = TL.fromChunks xs+		len = toInteger (TL.length lazy)+		iter = if len < n'+			then continue (loop (acc . (TL.append lazy)) (n' - len))+			else yield () (toChunks (acc lazy))+	loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF")+:++Note: {\tt isolate} has some odd behavior regarding extra input in the+inner iteratee. Depending on how large the chunks are, extra input might+be returned in the {\tt Step}, or dropped.++This doesn't matter if {\tt joinI} is used, but might if a user is poking+around inside the {\tt Step}. Eventually, enumeratees will be modified to+avoid exposing its internal iteratee state.++:d element-oriented list analogues+|apidoc Data.Enumerator.List.isolate|+isolate :: Monad m => Integer -> Enumeratee a a m b+isolate n step | n <= 0 = return step+isolate n (Continue k) = continue loop where+	len = L.genericLength+	+	loop (Chunks []) = continue loop+	loop (Chunks xs)+		| len xs <= n = k (Chunks xs) >>== isolate (n - len xs)+		| otherwise = let+			(s1, s2) = L.genericSplitAt n xs+			in k (Chunks s1) >>== (\step -> yield step (Chunks s2))+	loop EOF = k EOF >>== (\step -> yield step EOF)+isolate n step = drop n >> return step+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.isolate|+isolate :: Monad m => Integer -> Enumeratee B.ByteString B.ByteString m b+isolate n step | n <= 0 = return step+isolate n (Continue k) = continue loop where+	loop (Chunks []) = continue loop+	loop (Chunks xs) = iter where+		lazy = BL.fromChunks xs+		len = toInteger (BL.length lazy)+		+		iter = if len <= n+			then k (Chunks xs) >>== isolate (n - len)+			else let+				(s1, s2) = BL.splitAt (fromInteger n) lazy+				in k (toChunks s1) >>== (\step -> yield step (toChunks s2))+	loop EOF = k EOF >>== (\step -> yield step EOF)+isolate n step = drop n >> return step+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.isolate|+isolate :: Monad m => Integer -> Enumeratee T.Text T.Text m b+isolate n step | n <= 0 = return step+isolate n (Continue k) = continue loop where+	loop (Chunks []) = continue loop+	loop (Chunks xs) = iter where+		lazy = TL.fromChunks xs+		len = toInteger (TL.length lazy)+		+		iter = if len <= n+			then k (Chunks xs) >>== isolate (n - len)+			else let+				(s1, s2) = TL.splitAt (fromInteger n) lazy+				in k (toChunks s1) >>== (\step -> yield step (toChunks s2))+	loop EOF = k EOF >>== (\step -> yield step EOF)+isolate n step = drop n >> return step+:++:d element-oriented list analogues+|apidoc Data.Enumerator.List.splitWhen|+splitWhen :: Monad m => (a -> Bool) -> Enumeratee a [a] m b+splitWhen p = sequence $ do+	as <- takeWhile (not . p)+	drop 1+	return as+:++:d byte-oriented list analogues+|apidoc Data.Enumerator.Binary.splitWhen|+splitWhen :: Monad m => (Word8 -> Bool) -> Enumeratee B.ByteString B.ByteString m b+splitWhen p = loop where+	loop = checkDone step+	step k = isEOF >>= \eof -> if eof+		then yield (Continue k) EOF+		else do+			lazy <- takeWhile (not . p)+			let bytes = B.concat (BL.toChunks lazy)+			eof <- isEOF+			drop 1+			if BL.null lazy && eof+				then yield (Continue k) EOF+				else k (Chunks [bytes]) >>== loop+:++:d text-oriented list analogues+|apidoc Data.Enumerator.Text.splitWhen|+splitWhen :: Monad m => (Char -> Bool) -> Enumeratee T.Text T.Text m b+splitWhen p = loop where+	loop = checkDone step+	step k = isEOF >>= \eof -> if eof+		then yield (Continue k) EOF+		else do+			lazy <- takeWhile (not . p)+			let text = textToStrict lazy+			eof <- isEOF+			drop 1+			if TL.null lazy && eof+				then yield (Continue k) EOF+				else k (Chunks [text]) >>== loop++|apidoc Data.Enumerator.Text.lines|+lines :: Monad m => Enumeratee T.Text T.Text m b+lines = splitWhen (== '\n')+:
− src/list.anansi
@@ -1,155 +0,0 @@-\section{Lists}--:f Data/Enumerator/List.hs-|Data.Enumerator.List module header|-module Data.Enumerator.List (-	|Data.Enumerator.List exports|-	) where-import Data.Enumerator hiding (consume, head, peek, drop, dropWhile)-import Control.Exception (ErrorCall(..))-import Prelude hiding (head, drop, dropWhile, take, takeWhile)-import qualified Data.List as L-:--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.head|-head :: Monad m => Iteratee a m (Maybe a)-head = continue loop where-	loop (Chunks []) = head-	loop (Chunks (x:xs)) = yield (Just x) (Chunks xs)-	loop EOF = yield Nothing EOF-:--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.drop|-drop :: Monad m => Integer -> Iteratee a m ()-drop n | n <= 0 = return ()-drop n = continue (loop n) where-	loop n' (Chunks xs) = iter where-		len = L.genericLength xs-		iter = if len < n'-			then drop (n' - len)-			else yield () (Chunks (L.genericDrop n' xs))-	loop _ EOF = yield () EOF-:--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.dropWhile|-dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()-dropWhile p = continue loop where-	loop (Chunks xs) = case L.dropWhile p xs of-		[] -> continue loop-		xs' -> yield () (Chunks xs')-	loop EOF = yield () EOF-:--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.take|-take :: Monad m => Integer -> Iteratee a m [a]-take n | n <= 0 = return []-take n = continue (loop id n) where-	len = L.genericLength-	loop acc n' (Chunks xs)-		| len xs < n' = continue (loop (acc . (xs ++)) (n' - len xs))-		| otherwise   = let-			(xs', extra) = L.genericSplitAt n' xs-			in yield (acc xs') (Chunks extra)-	loop acc _ EOF = yield (acc []) EOF-:--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.takeWhile|-takeWhile :: Monad m => (a -> Bool) -> Iteratee a m [a]-takeWhile p = continue (loop id) where-	loop acc (Chunks []) = continue (loop acc)-	loop acc (Chunks xs) = case Prelude.span p xs of-		(_, []) -> continue (loop (acc . (xs ++)))-		(xs', extra) -> yield (acc xs') (Chunks extra)-	loop acc EOF = yield (acc []) EOF-:--:# NOTE: peeking properly is currently impossible with the current design of-:# 'Stream'. Once it's updated to support EOF with "final data", peek can be-:# re-enabled-:#-:# :d Data/Enumerator/List.hs-:# |apidoc Data.Enumerator.List.peek|-:# peek :: Monad m => Integer -> Iteratee a m [a]-:# peek n | n <= 0 = return []-:# peek n = continue (loop id n) where-:# 	len = L.genericLength-:# 	loop acc n' (Chunks xs)-:# 		| len xs < n' = continue (loop (acc . (xs ++)) (n' - len xs))-:# 		| otherwise   = let-:# 			xs' = L.genericTake n' xs-:# 			in yield (acc xs') (Chunks (acc xs))-:# 	loop acc _ EOF = yield (acc []) EOF-:# :-:# -:# :d Data/Enumerator/List.hs (disabled)-:# |apidoc Data.Enumerator.List.peekWhile|-:# peekWhile :: Monad m => (a -> Bool) -> Iteratee a m [a]-:# peekWhile p = continue (loop id) where-:# 	loop acc (Chunks []) = continue (loop acc)-:# 	loop acc (Chunks xs) = case Prelude.span p xs of-:# 		(_, []) -> continue (loop (acc . (xs ++)))-:# 		(xs', _) -> yield (acc xs') (Chunks (acc xs))-:# 	loop acc EOF = yield (acc []) EOF-:# :--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.consume|-consume :: Monad m => Iteratee a m [a]-consume = continue (loop id) where-	loop acc (Chunks []) = continue (loop acc)-	loop acc (Chunks xs) = continue (loop (acc . (xs ++)))-	loop acc EOF = yield (acc []) EOF-:--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.require|-require :: Monad m => Integer -> Iteratee a m ()-require n | n <= 0 = return ()-require n = continue (loop id n) where-	len = L.genericLength-	loop acc n' (Chunks xs)-		| len xs < n' = continue (loop (acc . (xs ++)) (n' - len xs))-		| otherwise   = yield () (Chunks (acc xs))-	loop _ _ EOF = throwError (ErrorCall "require: Unexpected EOF")-:--Note: {\tt isolate} has some odd behavior regarding extra input in the-inner iteratee. Depending on how large the chunks are, extra input might-be returned in the {\tt Step}, or dropped.--This doesn't matter if {\tt joinI} is used, but might if a user is poking-around inside the {\tt Step}. Eventually, enumeratees will be modified to-avoid exposing its internal iteratee state.--:f Data/Enumerator/List.hs-|apidoc Data.Enumerator.List.isolate|-isolate :: Monad m => Integer -> Enumeratee a a m b-isolate n step | n <= 0 = return step-isolate n (Continue k) = continue loop where-	len = L.genericLength-	-	loop (Chunks []) = continue loop-	loop (Chunks xs)-		| len xs <= n = k (Chunks xs) >>== isolate (n - len xs)-		| otherwise = let-			(s1, s2) = L.genericSplitAt n xs-			in k (Chunks s1) >>== (\step -> yield step (Chunks s2))-	loop EOF = k EOF >>== (\step -> yield step EOF)-isolate n step = drop n >> return step-:--:d Data.Enumerator.List exports-  head-, drop-, dropWhile-, take-, takeWhile-, consume-, require-, isolate-:
src/primitives.anansi view
@@ -1,9 +1,85 @@ \section{Primitives} -:d Data.Enumerator exports--- * Primitives+\subsection{Operators}++Because {\tt Iteratee a m b} is semantically equivalent to+{\tt m (Step a m b)}, several of the monadic combinators ({\tt (>>=)},+{\tt (>=>)}, etc) are useful to save typing when constructing enumerators+and enumeratees. {\tt (>>==)} corresponds to {\tt (>>=)}, {\tt (>==>)} to+{\tt (>=>)}, and so on.++:d iteratee operators+infixl 1 >>==+infixr 1 ==<<+infixr 0 $$+infixr 1 >==>+infixr 1 <==<++|apidoc Data.Enumerator.(>>==)|+(>>==) :: Monad m+       => Iteratee a m b+       -> (Step a m b -> Iteratee a' m b')+       -> Iteratee a' m b'+i >>== f = Iteratee (runIteratee i >>= runIteratee . f)++|apidoc Data.Enumerator.(==<<)|+(==<<) :: Monad m+       => (Step a m b -> Iteratee a' m b')+       -> Iteratee a m b+       -> Iteratee a' m b'+(==<<) = flip (>>==)++|apidoc Data.Enumerator.($$)|+($$) :: Monad m+     => (Step a m b -> Iteratee a' m b')+     -> Iteratee a m b+     -> Iteratee a' m b'+($$) = (==<<)++|apidoc Data.Enumerator.(>==>)|+(>==>) :: Monad m+       => Enumerator a m b+       -> (Step a m b -> Iteratee a' m b')+       -> Step a m b+       -> Iteratee a' m b'+(>==>) e1 e2 s = e1 s >>== e2++|apidoc Data.Enumerator.(<==<)|+(<==<) :: Monad m+       => (Step a m b -> Iteratee a' m b')+       -> Enumerator a m b+       -> Step a m b+       -> Iteratee a' m b'+(<==<) = flip (>==>) : +\subsection{Running iteratees}++To simplify running iteratees, {\tt run} sends {\tt EOF} and then examines+the result. It is not possible for the result to be {\tt Continue}, because+{\tt enumEOF} calls {\tt error} for divergent iteratees.++:d primitives+|apidoc Data.Enumerator.run|+run :: Monad m => Iteratee a m b+    -> m (Either Exc.SomeException b)+run i = do+	mStep <- runIteratee $ enumEOF ==<< i+	case mStep of+		Error err -> return $ Left err+		Yield x _ -> return $ Right x+		Continue _ -> error "run: divergent iteratee"+:++{\tt run\_} is even more simplified; it's used in simple scripts, where the+user doesn't care about error handling.++:d primitives+|apidoc Data.Enumerator.run_|+run_ :: Monad m => Iteratee a m b -> m b+run_ i = run i >>= either Exc.throw return+:+ \subsection{Error handling}  Most real-world applications have to deal with error conditions; however,@@ -16,10 +92,9 @@ Instances for the {\tt MonadError} class are provided in auxiliary libraries, to avoid extraneous dependencies. -:f Data/Enumerator.hs+:d primitives |apidoc Data.Enumerator.throwError|-throwError :: (Monad m, Exc.Exception e) => e-           -> Iteratee a m b+throwError :: (Monad m, Exc.Exception e) => e -> Iteratee a m b throwError exc = returnI (Error (Exc.toException exc)) : @@ -30,287 +105,14 @@ This limitation means that {\tt catchError} is mostly only useful for transforming or logging errors, not ignoring them. -:f Data/Enumerator.hs+:d primitives |apidoc Data.Enumerator.catchError|-catchError :: Monad m => Iteratee a m b+catchError :: Monad m+           => Iteratee a m b            -> (Exc.SomeException -> Iteratee a m b)            -> Iteratee a m b catchError iter h = iter >>== step where 	step (Yield b as) = yield b as 	step (Error err) = h err 	step (Continue k) = continue (\s -> k s >>== step)-:--:d Data.Enumerator exports--- ** Error handling-, throwError-, catchError-:--\subsection{Iteratees}--Since iteratees are semantically a left-fold, there are many existing-folds that can be lifted to iteratees. The {\tt foldl}, {\tt foldl'}, and-{\tt foldM} functions work like their standard library namesakes, but-construct iteratees instead. These iteratees are not as complex as what can-be created using {\tt Yield} and {\tt Continue}, but cover many common cases.--Each fold consumes input from the stream until {\sc eof}, when it yields its-current accumulator.--:d Data.Enumerator imports-import Data.List (foldl')-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.foldl|-foldl :: Monad m => (b -> a -> b) -> b-      -> Iteratee a m b-foldl step = continue . loop where-	fold = Prelude.foldl step-	loop acc stream = case stream of-		Chunks [] -> continue (loop acc)-		Chunks xs -> continue (loop (fold acc xs))-		EOF -> yield acc EOF-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.foldl'|-foldl' :: Monad m => (b -> a -> b) -> b-       -> Iteratee a m b-foldl' step = continue . loop where-	fold = Data.List.foldl' step-	loop acc stream = case stream of-		Chunks [] -> continue (loop acc)-		Chunks xs -> continue (loop (fold acc xs))-		EOF -> yield acc EOF-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.foldM|-foldM :: Monad m => (b -> a -> m b) -> b-      -> Iteratee a m b-foldM step = continue . loop where-	fold acc = lift . CM.foldM step acc-	-	loop acc stream = case stream of-		Chunks [] -> continue (loop acc)-		Chunks xs -> fold acc xs >>= continue . loop-		EOF -> yield acc EOF-:--:d Data.Enumerator exports--- ** Iteratees-, Data.Enumerator.foldl-, Data.Enumerator.foldl'-, Data.Enumerator.foldM-:--\subsection{Enumerators}--At their simplest, enumerators just check to see whether their received step-can accept any more input. If so, input is generated somehow, fed to the step,-and its result checked again. Most enumerators are defined using a-worker/wrapper pair, for efficiency and readability.--Here we define a number of enumerators based on functions from-{\tt Data.List}. Each generator has a monadic and non-monadic form, to-demonstrate how side effects might be ordered with respect to the iteratee's-processing.--{\tt iterate} and {\tt iterateM} apply a function repeatedly to the base-input, passing the results through as a stream.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.iterate|-iterate :: Monad m => (a -> a) -> a -> Enumerator a m b-iterate f = loop where-	loop a (Continue k) = k (Chunks [a]) >>== loop (f a)-	loop _ step = returnI step-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.iterateM|-iterateM :: Monad m => (a -> m a) -> a-         -> Enumerator a m b-iterateM f base = loop (return base) where-	loop m_a (Continue k) = do-		a <- lift m_a-		k (Chunks [a]) >>== loop (f a)-	loop _ step = returnI step-:--{\tt repeat} and {\tt repeatM} create infinite streams, where each input-is a single value.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.repeat|-repeat :: Monad m => a -> Enumerator a m b-repeat a = Data.Enumerator.iterate (const a) a-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.repeatM|-repeatM :: Monad m => m a -> Enumerator a m b-repeatM m_a step = do-	a <- lift m_a-	iterateM (const m_a) a step-:--{\tt replicate} and {\tt replicateM} create streams containing a given-quantity of the input value.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.replicateM|-replicateM :: Monad m => Integer -> m a-           -> Enumerator a m b-replicateM maxCount getNext = loop maxCount where-	loop 0 step = returnI step-	loop n (Continue k) = do-		next <- lift getNext-		k (Chunks [next]) >>== loop (n - 1)-	loop _ step = returnI step-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.replicate|-replicate :: Monad m => Integer -> a-          -> Enumerator a m b-replicate maxCount a = replicateM maxCount (return a)-:--{\tt generateM} runs a monadic computation until it returns {\tt Nothing},-which signals the end of enumeration.--Note that when the enumerator is finished, it does not send {\tt EOF} to-the iteratee. Instead, it returns a continuation, so additional enumerators-may add their own input to the stream.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.generateM|-generateM :: Monad m => m (Maybe a)-          -> Enumerator a m b-generateM getNext = loop where-	loop (Continue k) = do-		next <- lift getNext-		case next of-			Nothing -> continue k-			Just x -> k (Chunks [x]) >>== loop-	loop step = returnI step-:--:d Data.Enumerator exports--- ** Enumerators-, Data.Enumerator.iterate-, iterateM-, Data.Enumerator.repeat-, repeatM-, Data.Enumerator.replicate-, replicateM-, generateM-:--\subsection{Enumeratees}--Enumeratees are conceptually similar to a monadic {\tt concatMap}; each-outer input element is converted to a list of inner inputs, which are passed-to the inner iteratee. Error handling and performance considerations-make most real-life enumeratees more complex, but some don't need the extra-design.--The {\tt checkDone} and {\tt checkDoneEx} functions referenced here are-defined later, with other utilities.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.concatMapM|-concatMapM :: Monad m => (ao -> m [ai])-           -> Enumeratee ao ai m b-concatMapM f = checkDone (continue . step) where-	step k EOF = yield (Continue k) EOF-	step k (Chunks xs) = loop k xs-	-	loop k [] = continue (step k)-	loop k (x:xs) = do-		fx <- lift (f x)-		k (Chunks fx) >>==-			checkDoneEx (Chunks xs) (\k' -> loop k' xs)-:--Once {\tt concatMapM} is defined, similar enumeratees can be easily created-via small wrappers.--:d excluded Prelude imports-concatMap,-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.concatMap|-concatMap :: Monad m => (ao -> [ai])-          -> Enumeratee ao ai m b-concatMap f = concatMapM (return . f)-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.map|-map :: Monad m => (ao -> ai)-    -> Enumeratee ao ai m b-map f = concatMap (\x -> Prelude.map f [x])-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.filter|-filter :: Monad m => (a -> Bool)-       -> Enumeratee a a m b-filter p = concatMap (\x -> Prelude.filter p [x])-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.mapM|-mapM :: Monad m => (ao -> m ai)-     -> Enumeratee ao ai m b-mapM f = concatMapM (\x -> Prelude.mapM f [x])-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.filterM|-filterM :: Monad m => (a -> m Bool)-        -> Enumeratee a a m b-filterM p = concatMapM (\x -> CM.filterM p [x])-:--:d Data.Enumerator exports--- ** Enumeratees-, Data.Enumerator.map-, Data.Enumerator.concatMap-, Data.Enumerator.filter-, Data.Enumerator.mapM-, concatMapM-, Data.Enumerator.filterM-:--\subsection{Debugging}--Debugging enumerator-based code is mostly a question of what inputs are-being passed around. {\tt printChunks} prints out exactly what chunks are-being sent from an enumerator.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.printChunks|-printChunks :: (MonadIO m, Show a)-            => Bool -- ^ Print empty chunks-            -> Iteratee a m ()-printChunks printEmpty = continue loop where-	loop (Chunks xs) = do-		let hide = null xs && not printEmpty-		CM.unless hide (liftIO (print xs))-		continue loop-	-	loop EOF = do-		liftIO (putStrLn "EOF")-		yield () EOF-:--:d Data.Enumerator exports--- ** Debugging-, printChunks :
+ src/public-interface.anansi view
@@ -0,0 +1,362 @@+\section{Public interface}++:f Data/Enumerator.hs+|Data.Enumerator module header|+module Data.Enumerator (+	|Data.Enumerator exports|+	) where+|Data.Enumerator imports|++|types and instances|+|supplemental instances|+|primitives|+|iteratee operators|+|utilities for testing and debugging|+|unsorted utilities|+|compatibility: obsolete|+|compatibility: aliases|+:++:f Data/Enumerator/Binary.hs+|Data.Enumerator.Binary module header|+module Data.Enumerator.Binary (+	|Data.Enumerator.Binary exports|+	) where+|Data.Enumerator.Binary imports|+|byte-oriented list analogues|+|binary IO|++toChunks :: BL.ByteString -> Stream B.ByteString+toChunks = Chunks . BL.toChunks+:++:f Data/Enumerator/List.hs+|Data.Enumerator.List module header|+module Data.Enumerator.List (+	|Data.Enumerator.List exports|+	) where+|Data.Enumerator.List imports|+|element-oriented list analogues|+:++:f Data/Enumerator/Text.hs+|Data.Enumerator.Text module header|+module Data.Enumerator.Text (+	|Data.Enumerator.Text exports|+	) where+|Data.Enumerator.Text imports|+|text-oriented list analogues|+|text IO|+|text codecs|++toChunks :: TL.Text -> Stream T.Text+toChunks = Chunks . TL.toChunks+:++:d Data.Enumerator imports+import qualified Control.Exception as Exc+import Data.Monoid (Monoid, mempty, mappend, mconcat)+import Control.Monad.Trans.Class (MonadTrans, lift)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Applicative as A+import qualified Control.Monad as CM+import Data.Function (fix)+import {-# SOURCE #-} qualified Data.Enumerator.List as EL+import Data.List (genericLength)+:++:d Data.Enumerator.Binary imports+import Prelude hiding (head, drop, takeWhile)+import Data.Enumerator hiding ( head, drop, iterateM, repeatM, replicateM+                              , generateM, filterM, consume, foldM+                              , concatMapM)+import Data.Enumerator.Util (tryIO)+import Control.Monad.IO.Class (MonadIO)+import qualified Data.ByteString as B+import qualified System.IO as IO+import Data.Function (fix)+import qualified Control.Exception as Exc+import System.IO.Error (isEOFError)+import Data.Word (Word8)+import qualified Data.Enumerator.List as EL+import qualified Control.Monad as CM+import qualified Data.ByteString.Lazy as BL+import Control.Monad.Trans.Class (lift)+import Control.Monad (liftM)+:++:d Data.Enumerator.List imports+import Prelude hiding (head, drop, sequence, takeWhile)+import Data.Enumerator hiding ( concatMapM, iterateM, replicateM, head, drop+                              , foldM, repeatM, generateM, filterM, consume)+import Control.Monad.Trans.Class (lift)+import qualified Control.Monad as CM+import qualified Data.List as L+import Control.Exception (ErrorCall(..))+:++:d Data.Enumerator.Text imports+import Prelude hiding (head, drop, takeWhile, lines)+import qualified Prelude+import Data.Enumerator hiding ( head, drop, generateM, filterM, consume+                              , concatMapM, iterateM, repeatM, replicateM+                              , foldM)+import Data.Enumerator.Util (tryIO, tSpanBy, tlSpanBy, reprWord, reprChar, textToStrict)+import Control.Monad.IO.Class (MonadIO)+import qualified Control.Exception as Exc+import Control.Arrow (first)+import Data.Maybe (catMaybes)+import qualified Data.Text as T+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import qualified Data.Text.Encoding as TE+import Data.Word (Word8, Word16)+import Data.Bits ((.&.), (.|.), shiftL)+import qualified System.IO as IO+import System.IO.Error (isEOFError)+import qualified Data.Text.IO as TIO+import Data.Char (ord)+import System.IO.Unsafe (unsafePerformIO)+import qualified Data.Text.Lazy as TL+import qualified Data.Enumerator.List as EL+import qualified Control.Monad as CM+import Control.Monad.Trans.Class (lift)+import Control.Monad (liftM)+:++:d Data.Enumerator exports+-- * Types+  Stream (..)+, Iteratee (..)+, Step (..)+, Enumerator+, Enumeratee++-- * Primitives+, returnI+, continue+, yield++-- ** Operators+, (>>==)+, (==<<)+, ($$)+, (>==>)+, (<==<)++-- ** Running iteratees+, run+, run_++-- ** Error handling+, throwError+, catchError++-- * Miscellaneous+, concatEnums+, joinI+, joinE+, Data.Enumerator.sequence+, enumEOF+, checkDoneEx+, checkDone+, isEOF++-- ** Testing and debugging+, printChunks+, enumList++-- * Legacy compatibility++-- ** Obsolete+, liftTrans+, liftI+, peek+, Data.Enumerator.last+, Data.Enumerator.length++-- ** Aliases+, Data.Enumerator.head+, Data.Enumerator.drop+, Data.Enumerator.dropWhile+, Data.Enumerator.span+, Data.Enumerator.break+, consume+, Data.Enumerator.foldl+, Data.Enumerator.foldl'+, foldM+, Data.Enumerator.iterate+, iterateM+, Data.Enumerator.repeat+, repeatM+, Data.Enumerator.replicate+, replicateM+, generateM+, Data.Enumerator.map+, Data.Enumerator.mapM+, Data.Enumerator.concatMap+, concatMapM+, Data.Enumerator.filter+, filterM+, liftFoldL+, liftFoldL'+, liftFoldM+:++:d Data.Enumerator.Binary exports+-- * IO+  enumHandle+, enumHandleRange+, enumFile+, enumFileRange+, iterHandle++-- * List analogues++-- ** Folds+, fold+, foldM++-- ** Maps+, Data.Enumerator.Binary.map+, Data.Enumerator.Binary.mapM+, Data.Enumerator.Binary.concatMap+, concatMapM++-- ** Infinite streams+, Data.Enumerator.Binary.iterate+, iterateM+, Data.Enumerator.Binary.repeat+, repeatM++-- ** Bounded streams+, Data.Enumerator.Binary.replicate+, replicateM+, generateM+, unfold+, unfoldM++-- ** Filters+, Data.Enumerator.Binary.filter+, filterM++-- ** Consumers+, Data.Enumerator.Binary.take+, takeWhile+, consume++-- ** Unsorted+, Data.Enumerator.Binary.head+, Data.Enumerator.Binary.drop+, Data.Enumerator.Binary.dropWhile+, require+, isolate+, splitWhen++:++:d Data.Enumerator.List exports+-- * List analogues++-- ** Folds+  fold+, foldM++-- ** Maps+, Data.Enumerator.List.map+, Data.Enumerator.List.mapM+, Data.Enumerator.List.concatMap+, concatMapM++-- ** Infinite streams+, Data.Enumerator.List.iterate+, iterateM+, Data.Enumerator.List.repeat+, repeatM++-- ** Bounded streams+, Data.Enumerator.List.replicate+, replicateM+, generateM+, unfold+, unfoldM++-- ** Filters+, Data.Enumerator.List.filter+, filterM++-- ** Consumers+, Data.Enumerator.List.take+, takeWhile+, consume++-- ** Unsorted+, head+, drop+, Data.Enumerator.List.dropWhile+, require+, isolate+, splitWhen+:++:d Data.Enumerator.Text exports+-- * IO+  enumHandle+, enumFile+, iterHandle++-- * List analogues++-- ** Folds+, fold+, foldM++-- ** Maps+, Data.Enumerator.Text.map+, Data.Enumerator.Text.mapM+, Data.Enumerator.Text.concatMap+, concatMapM++-- ** Infinite streams+, Data.Enumerator.Text.iterate+, iterateM+, Data.Enumerator.Text.repeat+, repeatM++-- ** Bounded streams+, Data.Enumerator.Text.replicate+, replicateM+, generateM+, unfold+, unfoldM++-- ** Filters+, Data.Enumerator.Text.filter+, filterM++-- ** Consumers+, Data.Enumerator.Text.take+, takeWhile+, consume++-- ** Unsorted+, Data.Enumerator.Text.head+, Data.Enumerator.Text.drop+, Data.Enumerator.Text.dropWhile+, require+, isolate+, splitWhen+, lines++-- * Text codecs+, Codec+, encode+, decode+, utf8+, utf16_le+, utf16_be+, utf32_le+, utf32_be+, ascii+, iso8859_1+:
+ src/summary.anansi view
@@ -0,0 +1,41 @@+\section*{Summary}++Typical buffer-based incremental \io{} is based around a single loop, which+reads data from some source (such as a socket or file), transforms it, and+generates one or more outputs (such as a line count, {\sc http} responses,+or modified file).  Although efficient and safe, these loops are all+single-purpose; it is difficult or impossible to compose buffer-based+processing loops.++Haskell's concept of ``lazy \io{}'' allows pure code to operate on data from+an external source. However, lazy \io{} has several shortcomings. Most notably,+resources such as memory and file handles can be retained for arbitrarily+long periods of time, causing unpredictable performance and error conditions.++Enumerators are an efficient, predictable, and safe alternative to lazy \io{}.+Discovered by Oleg \mbox{Kiselyov}, they allow large datasets to be processed+in near-constant space by pure code. Although somewhat more complex to write,+using enumerators instead of lazy \io{} produces more correct programs.++This library contains an enumerator implementation for Haskell, designed to+be both simple and efficient. Three core types are defined, along with+numerous helper functions:++\begin{itemize}++\item {\it Iteratee\/}: Data sinks, analogous to left folds. Iteratees consume+a sequence of \emph{input} values, and generate a single \emph{output} value.+Many iteratees are designed to perform side effects (such as printing to+{\tt stdout}), so they can also be used as monad transformers.++\item {\it Enumerator\/}: Data sources, which generate input sequences. Typical+enumerators read from a file handle, socket, random number generator, or+other external stream. To operate, enumerators are passed an iteratee, and+provide that iteratee with input until either the iteratee has completed its+computation, or {\sc eof}.++\item {\it Enumeratee\/}: Data transformers, which operate as both enumerators and+iteratees. Enumeratees read from an \emph{outer} enumerator, and provide the+transformed data to an \emph{inner} iteratee.++\end{itemize}
+ src/text-codecs.anansi view
@@ -0,0 +1,339 @@+\section{Text Codecs}++Many protocols need the non-blocking input behavior of binary \io{}, but+are defined in terms of unicode characters. The {\tt encode} and+{\tt decode} enumeratees allow text-based protocols to be easily parsed+from a binary input source.++Most common codecs ({\sc utf-8}, {\sc iso-8859-1}, {\sc ascii}) are+supported; more complex codecs can be implemented by bindings to libraries+such as libicu.++All of the codecs here are incremental; that is, they try to read as much+data as possible, but no more. This allows iteratees to read partial data+if the input stream contains invalid data.++:d text codecs+data Codec = Codec+	{ codecName :: T.Text+	, codecEncode+		:: T.Text+		-> (B.ByteString, Maybe (Exc.SomeException, T.Text))+	, codecDecode+		:: B.ByteString+		-> (T.Text, Either+			(Exc.SomeException, B.ByteString)+			B.ByteString)+	}++instance Show Codec where+	showsPrec d c = showParen (d > 10) $+		showString "Codec " . shows (codecName c)+:++:d text codecs+|apidoc Data.Enumerator.Text.encode|+encode :: Monad m => Codec+       -> Enumeratee T.Text B.ByteString m b+encode codec = checkDone (continue . step) where+	step k EOF = yield (Continue k) EOF+	step k (Chunks xs) = loop k xs+	+	loop k [] = continue (step k)+	loop k (x:xs) = let+		(bytes, extra) = codecEncode codec x+		extraChunks = Chunks $ case extra of+			Nothing -> xs+			Just (_, text) -> text:xs+		+		checkError k' = case extra of+			Nothing -> loop k' xs+			Just (exc, _) -> throwError exc+		+		in if B.null bytes+			then checkError k+			else k (Chunks [bytes]) >>==+				checkDoneEx extraChunks checkError+:++:d text codecs+|apidoc Data.Enumerator.Text.decode|+decode :: Monad m => Codec+       -> Enumeratee B.ByteString T.Text m b+decode codec = checkDone (continue . step B.empty) where+	step _   k EOF = yield (Continue k) EOF+	step acc k (Chunks xs) = loop acc k xs+	+	loop acc k [] = continue (step acc k)+	loop acc k (x:xs) = let+		(text, extra) = codecDecode codec (B.append acc x)+		extraChunks = Chunks (either snd id extra : xs)+		+		checkError k' = case extra of+			Left (exc, _) -> throwError exc+			Right bytes -> loop bytes k' xs+		+		in if T.null text+			then checkError k+			else k (Chunks [text]) >>==+				checkDoneEx extraChunks checkError+:++The variable-width decoders all follow the same basic pattern. First,+they examine their input to calculate how many bytes the decoder+function should accept. Next they try to decode it -- if the input+is valid, decoding is finished.++If the input is invalid, trying to decode the full input will throw+an exception. When an exception is caught, decoding is passed off to+{\tt splitSlowly} for a more careful parse. The input is reduced until+the decoder can parse something, and the rest of the bytes are stored+for later. An error will only be thrown if the iteratee requires input,+but there are no valid bytes remaining.++:d text codecs+byteSplits :: B.ByteString+           -> [(B.ByteString, B.ByteString)]+byteSplits bytes = loop (B.length bytes) where+	loop 0 = [(B.empty, bytes)]+	loop n = B.splitAt n bytes : loop (n - 1)+:++:d text codecs+splitSlowly :: (B.ByteString -> T.Text)+            -> B.ByteString+            -> (T.Text, Either+            	(Exc.SomeException, B.ByteString)+            	B.ByteString)+splitSlowly dec bytes = valid where+	valid = firstValid (Prelude.map decFirst splits)+	splits = byteSplits bytes+	firstValid = Prelude.head . catMaybes+	tryDec = tryEvaluate . dec+	+	decFirst (a, b) = case tryDec a of+		Left _ -> Nothing+		Right text -> Just (text, case tryDec b of+			Left exc -> Left (exc, b)+			+			-- this case shouldn't occur, since splitSlowly+			-- is only called when parsing failed somewhere+			Right _ -> Right B.empty)+:++\subsection{UTF-8}++:d text codecs+utf8 :: Codec+utf8 = Codec name enc dec where+	name = T.pack "UTF-8"+	enc text = (TE.encodeUtf8 text, Nothing)+	dec bytes = case splitQuickly bytes of+		Just (text, extra) -> (text, Right extra)+		Nothing -> splitSlowly TE.decodeUtf8 bytes+	|utf8 split bytes|+:++:d utf8 split bytes+splitQuickly bytes = loop 0 >>= maybeDecode where+	|utf8 required bytes count|+	maxN = B.length bytes+	+	loop n | n == maxN = Just (TE.decodeUtf8 bytes, B.empty)+	loop n = let+		req = required (B.index bytes n)+		tooLong = first TE.decodeUtf8 (B.splitAt n bytes)+		decodeMore = loop $! n + req+		in if req == 0+			then Nothing+			else if n + req > maxN+				then Just tooLong+				else decodeMore+:++:d utf8 required bytes count+required x0+	| x0 .&. 0x80 == 0x00 = 1+	| x0 .&. 0xE0 == 0xC0 = 2+	| x0 .&. 0xF0 == 0xE0 = 3+	| x0 .&. 0xF8 == 0xF0 = 4+	+	-- Invalid input; let Text figure it out+	| otherwise           = 0+:++\subsection{UTF-16}++:d text codecs+utf16_le :: Codec+utf16_le = Codec name enc dec where+	name = T.pack "UTF-16-LE"+	enc text = (TE.encodeUtf16LE text, Nothing)+	dec bytes = case splitQuickly bytes of+		Just (text, extra) -> (text, Right extra)+		Nothing -> splitSlowly TE.decodeUtf16LE bytes+	|utf16-le split bytes|+:++:d text codecs+utf16_be :: Codec+utf16_be = Codec name enc dec where+	name = T.pack "UTF-16-BE"+	enc text = (TE.encodeUtf16BE text, Nothing)+	dec bytes = case splitQuickly bytes of+		Just (text, extra) -> (text, Right extra)+		Nothing -> splitSlowly TE.decodeUtf16BE bytes+	|utf16-be split bytes|+:++:d utf16-le split bytes+splitQuickly bytes = maybeDecode (loop 0) where+	maxN = B.length bytes+	+	loop n |  n      == maxN = decodeAll+	       | (n + 1) == maxN = decodeTo n+	loop n = let+		req = utf16Required+			(B.index bytes 0)+			(B.index bytes 1)+		decodeMore = loop $! n + req+		in if n + req > maxN+			then decodeTo n+			else decodeMore+	+	decodeTo n = first TE.decodeUtf16LE (B.splitAt n bytes)+	decodeAll = (TE.decodeUtf16LE bytes, B.empty)+:++:d utf16-be split bytes+splitQuickly bytes = maybeDecode (loop 0) where+	maxN = B.length bytes+	+	loop n |  n      == maxN = decodeAll+	       | (n + 1) == maxN = decodeTo n+	loop n = let+		req = utf16Required+			(B.index bytes 1)+			(B.index bytes 0)+		decodeMore = loop $! n + req+		in if n + req > maxN+			then decodeTo n+			else decodeMore+	+	decodeTo n = first TE.decodeUtf16BE (B.splitAt n bytes)+	decodeAll = (TE.decodeUtf16BE bytes, B.empty)+:++:d text codecs+utf16Required :: Word8 -> Word8 -> Int+utf16Required x0 x1 = required where+	required = if x >= 0xD800 && x <= 0xDBFF+		then 4+		else 2+	x :: Word16+	x = (fromIntegral x1 `shiftL` 8) .|. fromIntegral x0+:++\subsection{UTF-32}++:d text codecs+utf32_le :: Codec+utf32_le = Codec name enc dec where+	name = T.pack "UTF-32-LE"+	enc text = (TE.encodeUtf32LE text, Nothing)+	dec bs = case utf32SplitBytes TE.decodeUtf32LE bs of+		Just (text, extra) -> (text, Right extra)+		Nothing -> splitSlowly TE.decodeUtf32LE bs++utf32_be :: Codec+utf32_be = Codec name enc dec where+	name = T.pack "UTF-32-BE"+	enc text = (TE.encodeUtf32BE text, Nothing)+	dec bs = case utf32SplitBytes TE.decodeUtf32BE bs of+		Just (text, extra) -> (text, Right extra)+		Nothing -> splitSlowly TE.decodeUtf32BE bs+:++:d text codecs+utf32SplitBytes :: (B.ByteString -> T.Text)+                -> B.ByteString+                -> Maybe (T.Text, B.ByteString)+utf32SplitBytes dec bytes = split where+	split = maybeDecode (dec toDecode, extra)+	len = B.length bytes+	lenExtra = mod len 4+	+	lenToDecode = len - lenExtra+	(toDecode, extra) = if lenExtra == 0+		then (bytes, B.empty)+		else B.splitAt lenToDecode bytes+:++\subsection{ASCII}++:d text codecs+ascii :: Codec+ascii = Codec name enc dec where+	name = T.pack "ASCII"+	enc text = (bytes, extra) where+		(safe, unsafe) = tSpanBy (\c -> ord c <= 0x7F) text+		bytes = B8.pack (T.unpack safe)+		extra = if T.null unsafe+			then Nothing+			else Just (illegalEnc name (T.head unsafe), unsafe)+	+	dec bytes = (text, extra) where+		(safe, unsafe) = B.span (<= 0x7F) bytes+		text = T.pack (B8.unpack safe)+		extra = if B.null unsafe+			then Right B.empty+			else Left (illegalDec name (B.head unsafe), unsafe)+:++\subsection{ISO 8859-1}++:d text codecs+iso8859_1 :: Codec+iso8859_1 = Codec name enc dec where+	name = T.pack "ISO-8859-1"+	enc text = (bytes, extra) where+		(safe, unsafe) = tSpanBy (\c -> ord c <= 0xFF) text+		bytes = B8.pack (T.unpack safe)+		extra = if T.null unsafe+			then Nothing+			else Just (illegalEnc name (T.head unsafe), unsafe)+	+	dec bytes = (T.pack (B8.unpack bytes), Right B.empty)+:++\subsection*{Encoding Utilities}++:d text codecs+illegalEnc :: T.Text -> Char -> Exc.SomeException+illegalEnc name c = Exc.toException . Exc.ErrorCall $+	concat [ "Codec "+	       , show name+	       , " can't encode character "+	       , reprChar c+	       ]+:++:d text codecs+illegalDec :: T.Text -> Word8 -> Exc.SomeException+illegalDec name w = Exc.toException . Exc.ErrorCall $+	concat [ "Codec "+	       , show name+	       , " can't decode byte "+	       , reprWord w+	       ]+:++:d text codecs+tryEvaluate :: a -> Either Exc.SomeException a+tryEvaluate = unsafePerformIO . Exc.try . Exc.evaluate++maybeDecode:: (a, b) -> Maybe (a, b)+maybeDecode (a, b) = case tryEvaluate a of+	Left _ -> Nothing+	Right _ -> Just (a, b)+:
− src/text.anansi
@@ -1,608 +0,0 @@-\section{Text}--:f Data/Enumerator/Text.hs-|Data.Enumerator.Text module header|-module Data.Enumerator.Text (-	|Data.Enumerator.Text exports|-	) where-import qualified Prelude-import Prelude hiding (head, drop, takeWhile)-import Data.Enumerator hiding (head, drop)-import qualified Data.Text as T-|Data.Enumerator.Text imports|-:--\subsection{IO}--Reading text is similar to reading bytes, but the enumerators have slightly-different behavior -- instead of reading in fixed-size chunks of data, the-text enumerators read in lines. This matches similar text-based {\sc api}s,-such as Python's {\tt xreadlines()}.--:d Data.Enumerator.Text imports-import Data.Enumerator.Util (tryStep)-import qualified Data.Text.IO as TIO--import qualified Control.Exception as Exc-import Control.Monad.IO.Class (MonadIO)-import qualified System.IO as IO-import System.IO.Error (isEOFError)-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.enumHandle|-enumHandle :: MonadIO m => IO.Handle-           -> Enumerator T.Text m b-enumHandle h = loop where-	loop (Continue k) = withText $ \maybeText ->-		case maybeText of-			Nothing -> continue k-			Just text -> k (Chunks [text]) >>== loop-	-	loop step = returnI step-	withText = tryStep $ Exc.catch-		(Just `fmap` TIO.hGetLine h)-		(\err -> if isEOFError err-			then return Nothing-			else Exc.throwIO err)-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.enumFile|-enumFile :: FilePath -> Enumerator T.Text IO b-enumFile path = enum where-	withHandle = tryStep (IO.openFile path IO.ReadMode)-	enum step = withHandle $ \h -> Iteratee $ Exc.finally-		(runIteratee (enumHandle h step))-		(IO.hClose h)-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.iterHandle|-iterHandle :: MonadIO m => IO.Handle-           -> Iteratee T.Text m ()-iterHandle h = continue step where-	step EOF = yield () EOF-	step (Chunks []) = continue step-	step (Chunks chunks) = let-		put = mapM_ (TIO.hPutStr h) chunks-		in tryStep put (\_ -> continue step)-:--:d Data.Enumerator.Text exports-  -- * Text IO-  enumHandle-, enumFile-, iterHandle-:--\subsection{List analogues}--:d Data.Enumerator.Text imports-import qualified Data.Text.Lazy as TL-:--:f Data/Enumerator/Text.hs-toChunks :: TL.Text -> Stream T.Text-toChunks = Chunks . TL.toChunks-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.head|-head :: Monad m => Iteratee T.Text m (Maybe Char)-head = continue loop where-	loop (Chunks xs) = case TL.uncons (TL.fromChunks xs) of-		Just (char, extra) -> yield (Just char) (toChunks extra)-		Nothing -> head-	loop EOF = yield Nothing EOF-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.drop|-drop :: Monad m => Integer -> Iteratee T.Text m ()-drop n | n <= 0 = return ()-drop n = continue (loop n) where-	loop n' (Chunks xs) = iter where-		lazy = TL.fromChunks xs-		len = toInteger (TL.length lazy)-		iter = if len < n'-			then drop (n' - len)-			else yield () (toChunks (TL.drop (fromInteger n') lazy))-	loop _ EOF = yield () EOF-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.dropWhile|-dropWhile :: Monad m => (Char -> Bool) -> Iteratee T.Text m ()-dropWhile p = continue loop where-	loop (Chunks xs) = iter where-		lazy = TL.dropWhile p (TL.fromChunks xs)-		iter = if TL.null lazy-			then continue loop-			else yield () (toChunks lazy)-	loop EOF = yield () EOF-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.take|-take :: Monad m => Integer -> Iteratee T.Text m TL.Text-take n | n <= 0 = return TL.empty-take n = continue (loop id n) where-	loop acc n' (Chunks xs) = iter where-		lazy = TL.fromChunks xs-		len = toInteger (TL.length lazy)-		-		iter = if len < n'-			then continue (loop (acc . (TL.append lazy)) (n' - len))-			else let-				(xs', extra) = TL.splitAt (fromInteger n') lazy-				in yield (acc xs') (toChunks extra)-	loop acc _ EOF = yield (acc TL.empty) EOF-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.takeWhile|-takeWhile :: Monad m => (Char -> Bool) -> Iteratee T.Text m TL.Text-takeWhile p = continue (loop id) where-	loop acc (Chunks []) = continue (loop acc)-	loop acc (Chunks xs) = iter where-		lazy = TL.fromChunks xs-		(xs', extra) = tlSpanBy p lazy-		iter = if TL.null extra-			then continue (loop (acc . (TL.append lazy)))-			else yield (acc xs') (toChunks extra)-	loop acc EOF = yield (acc TL.empty) EOF-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.consume|-consume :: Monad m => Iteratee T.Text m TL.Text-consume = continue (loop id) where-	loop acc (Chunks []) = continue (loop acc)-	loop acc (Chunks xs) = iter where-		lazy = TL.fromChunks xs-		iter = continue (loop (acc . (TL.append lazy)))-	loop acc EOF = yield (acc TL.empty) EOF-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.require|-require :: Monad m => Integer -> Iteratee T.Text m ()-require n | n <= 0 = return ()-require n = continue (loop id n) where-	loop acc n' (Chunks xs) = iter where-		lazy = TL.fromChunks xs-		len = toInteger (TL.length lazy)-		iter = if len < n'-			then continue (loop (acc . (TL.append lazy)) (n' - len))-			else yield () (toChunks (acc lazy))-	loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF")-:--Same caveats as {\tt Data.Enumerator.List.isolate}--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.isolate|-isolate :: Monad m => Integer -> Enumeratee T.Text T.Text m b-isolate n step | n <= 0 = return step-isolate n (Continue k) = continue loop where-	loop (Chunks []) = continue loop-	loop (Chunks xs) = iter where-		lazy = TL.fromChunks xs-		len = toInteger (TL.length lazy)-		-		iter = if len <= n-			then k (Chunks xs) >>== isolate (n - len)-			else let-				(s1, s2) = TL.splitAt (fromInteger n) lazy-				in k (toChunks s1) >>== (\step -> yield step (toChunks s2))-	loop EOF = k EOF >>== (\step -> yield step EOF)-isolate n step = drop n >> return step-:--:d Data.Enumerator.Text exports--- * List analogues-, Data.Enumerator.Text.head-, Data.Enumerator.Text.drop-, Data.Enumerator.Text.dropWhile-, Data.Enumerator.Text.take-, Data.Enumerator.Text.takeWhile-, Data.Enumerator.Text.consume-, require-, isolate-:--\subsection{Codecs}--Many protocols need the non-blocking input behavior of binary \io{}, but-are defined in terms of unicode characters. The {\tt encode} and-{\tt decode} enumeratees allow text-based protocols to be easily parsed-from a binary input source.--Most common codecs ({\sc utf-8}, {\sc iso-8859-1}, {\sc ascii}) are-supported; more complex codecs can be implemented by bindings to libraries-such as libicu.--All of the codecs here are incremental; that is, they try to read as much-data as possible, but no more. This allows iteratees to read partial data-if the input stream contains invalid data.--:d Data.Enumerator.Text imports-import qualified Data.ByteString as B-import Data.Enumerator.Util (tSpanBy, tlSpanBy, reprWord, reprChar)-:--:d Data.Enumerator.Text exports-  -- * Codecs-, Codec-, encode-, decode-|text codec exports|-:--:f Data/Enumerator/Text.hs-data Codec = Codec-	{ codecName :: T.Text-	, codecEncode-		:: T.Text-		-> (B.ByteString, Maybe (Exc.SomeException, T.Text))-	, codecDecode-		:: B.ByteString-		-> (T.Text, Either-			(Exc.SomeException, B.ByteString)-			B.ByteString)-	}--instance Show Codec where-	showsPrec d c = showParen (d > 10) $-		showString "Codec " . shows (codecName c)-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.encode|-encode :: Monad m => Codec-       -> Enumeratee T.Text B.ByteString m b-encode codec = checkDone (continue . step) where-	step k EOF = yield (Continue k) EOF-	step k (Chunks xs) = loop k xs-	-	loop k [] = continue (step k)-	loop k (x:xs) = let-		(bytes, extra) = codecEncode codec x-		extraChunks = Chunks $ case extra of-			Nothing -> xs-			Just (_, text) -> text:xs-		-		checkError k' = case extra of-			Nothing -> loop k' xs-			Just (exc, _) -> throwError exc-		-		in if B.null bytes-			then checkError k-			else k (Chunks [bytes]) >>==-				checkDoneEx extraChunks checkError-:--:f Data/Enumerator/Text.hs-|apidoc Data.Enumerator.Text.decode|-decode :: Monad m => Codec-       -> Enumeratee B.ByteString T.Text m b-decode codec = checkDone (continue . step B.empty) where-	step _   k EOF = yield (Continue k) EOF-	step acc k (Chunks xs) = loop acc k xs-	-	loop acc k [] = continue (step acc k)-	loop acc k (x:xs) = let-		(text, extra) = codecDecode codec (B.append acc x)-		extraChunks = Chunks (either snd id extra : xs)-		-		checkError k' = case extra of-			Left (exc, _) -> throwError exc-			Right bytes -> loop bytes k' xs-		-		in if T.null text-			then checkError k-			else k (Chunks [text]) >>==-				checkDoneEx extraChunks checkError-:--Most of the codecs here need to perform at least basic bitbashing, to-calculate how many input bytes will be needed for the next character.--:d Data.Enumerator.Text imports-import Control.Arrow (first)-import Data.Bits ((.&.), (.|.), shiftL)-import Data.Char (ord)-import Data.Word (Word8, Word16)-import qualified Data.ByteString.Char8 as B8-import qualified Data.Text.Encoding as TE-:--The variable-width decoders all follow the same basic pattern. First,-they examine their input to calculate how many bytes the decoder-function should accept. Next they try to decode it -- if the input-is valid, decoding is finished.--If the input is invalid, trying to decode the full input will throw-an exception. When an exception is caught, decoding is passed off to-{\tt splitSlowly} for a more careful parse. The input is reduced until-the decoder can parse something, and the rest of the bytes are stored-for later. An error will only be thrown if the iteratee requires input,-but there are no valid bytes remaining.--:f Data/Enumerator/Text.hs-byteSplits :: B.ByteString-           -> [(B.ByteString, B.ByteString)]-byteSplits bytes = loop (B.length bytes) where-	loop 0 = [(B.empty, bytes)]-	loop n = B.splitAt n bytes : loop (n - 1)-:--:d Data.Enumerator.Text imports-import Data.Maybe (catMaybes)-:--:f Data/Enumerator/Text.hs-splitSlowly :: (B.ByteString -> T.Text)-            -> B.ByteString-            -> (T.Text, Either-            	(Exc.SomeException, B.ByteString)-            	B.ByteString)-splitSlowly dec bytes = valid where-	valid = firstValid (Prelude.map decFirst splits)-	splits = byteSplits bytes-	firstValid = Prelude.head . catMaybes-	tryDec = tryEvaluate . dec-	-	decFirst (a, b) = case tryDec a of-		Left _ -> Nothing-		Right text -> Just (text, case tryDec b of-			Left exc -> Left (exc, b)-			-			-- this case shouldn't occur, since splitSlowly-			-- is only called when parsing failed somewhere-			Right _ -> Right B.empty)-:--\subsubsection{UTF-8}--:d text codec exports-, utf8-:--:f Data/Enumerator/Text.hs-utf8 :: Codec-utf8 = Codec name enc dec where-	name = T.pack "UTF-8"-	enc text = (TE.encodeUtf8 text, Nothing)-	dec bytes = case splitQuickly bytes of-		Just (text, extra) -> (text, Right extra)-		Nothing -> splitSlowly TE.decodeUtf8 bytes-	|utf8 split bytes|-:--:d utf8 split bytes-splitQuickly bytes = loop 0 >>= maybeDecode where-	|utf8 required bytes count|-	maxN = B.length bytes-	-	loop n | n == maxN = Just (TE.decodeUtf8 bytes, B.empty)-	loop n = let-		req = required (B.index bytes n)-		tooLong = first TE.decodeUtf8 (B.splitAt n bytes)-		decodeMore = loop $! n + req-		in if req == 0-			then Nothing-			else if n + req > maxN-				then Just tooLong-				else decodeMore-:--:d utf8 required bytes count-required x0-	| x0 .&. 0x80 == 0x00 = 1-	| x0 .&. 0xE0 == 0xC0 = 2-	| x0 .&. 0xF0 == 0xE0 = 3-	| x0 .&. 0xF8 == 0xF0 = 4-	-	-- Invalid input; let Text figure it out-	| otherwise           = 0-:--\subsubsection{UTF-16}--:d text codec exports-, utf16_le-, utf16_be-:--:f Data/Enumerator/Text.hs-utf16_le :: Codec-utf16_le = Codec name enc dec where-	name = T.pack "UTF-16-LE"-	enc text = (TE.encodeUtf16LE text, Nothing)-	dec bytes = case splitQuickly bytes of-		Just (text, extra) -> (text, Right extra)-		Nothing -> splitSlowly TE.decodeUtf16LE bytes-	|utf16-le split bytes|-:--:f Data/Enumerator/Text.hs-utf16_be :: Codec-utf16_be = Codec name enc dec where-	name = T.pack "UTF-16-BE"-	enc text = (TE.encodeUtf16BE text, Nothing)-	dec bytes = case splitQuickly bytes of-		Just (text, extra) -> (text, Right extra)-		Nothing -> splitSlowly TE.decodeUtf16BE bytes-	|utf16-be split bytes|-:--:d utf16-le split bytes-splitQuickly bytes = maybeDecode (loop 0) where-	maxN = B.length bytes-	-	loop n |  n      == maxN = decodeAll-	       | (n + 1) == maxN = decodeTo n-	loop n = let-		req = utf16Required-			(B.index bytes 0)-			(B.index bytes 1)-		decodeMore = loop $! n + req-		in if n + req > maxN-			then decodeTo n-			else decodeMore-	-	decodeTo n = first TE.decodeUtf16LE (B.splitAt n bytes)-	decodeAll = (TE.decodeUtf16LE bytes, B.empty)-:--:d utf16-be split bytes-splitQuickly bytes = maybeDecode (loop 0) where-	maxN = B.length bytes-	-	loop n |  n      == maxN = decodeAll-	       | (n + 1) == maxN = decodeTo n-	loop n = let-		req = utf16Required-			(B.index bytes 1)-			(B.index bytes 0)-		decodeMore = loop $! n + req-		in if n + req > maxN-			then decodeTo n-			else decodeMore-	-	decodeTo n = first TE.decodeUtf16BE (B.splitAt n bytes)-	decodeAll = (TE.decodeUtf16BE bytes, B.empty)-:--:f Data/Enumerator/Text.hs-utf16Required :: Word8 -> Word8 -> Int-utf16Required x0 x1 = required where-	required = if x >= 0xD800 && x <= 0xDBFF-		then 4-		else 2-	x :: Word16-	x = (fromIntegral x1 `shiftL` 8) .|. fromIntegral x0-:--\subsubsection{UTF-32}--:d text codec exports-, utf32_le-, utf32_be-:--:f Data/Enumerator/Text.hs-utf32_le :: Codec-utf32_le = Codec name enc dec where-	name = T.pack "UTF-32-LE"-	enc text = (TE.encodeUtf32LE text, Nothing)-	dec bs = case utf32SplitBytes TE.decodeUtf32LE bs of-		Just (text, extra) -> (text, Right extra)-		Nothing -> splitSlowly TE.decodeUtf32LE bs--utf32_be :: Codec-utf32_be = Codec name enc dec where-	name = T.pack "UTF-32-BE"-	enc text = (TE.encodeUtf32BE text, Nothing)-	dec bs = case utf32SplitBytes TE.decodeUtf32BE bs of-		Just (text, extra) -> (text, Right extra)-		Nothing -> splitSlowly TE.decodeUtf32BE bs-:--:f Data/Enumerator/Text.hs-utf32SplitBytes :: (B.ByteString -> T.Text)-                -> B.ByteString-                -> Maybe (T.Text, B.ByteString)-utf32SplitBytes dec bytes = split where-	split = maybeDecode (dec toDecode, extra)-	len = B.length bytes-	lenExtra = mod len 4-	-	lenToDecode = len - lenExtra-	(toDecode, extra) = if lenExtra == 0-		then (bytes, B.empty)-		else B.splitAt lenToDecode bytes-:--\subsubsection{ASCII}--:d text codec exports-, ascii-:--:f Data/Enumerator/Text.hs-ascii :: Codec-ascii = Codec name enc dec where-	name = T.pack "ASCII"-	enc text = (bytes, extra) where-		(safe, unsafe) = tSpanBy (\c -> ord c <= 0x7F) text-		bytes = B8.pack (T.unpack safe)-		extra = if T.null unsafe-			then Nothing-			else Just (illegalEnc name (T.head unsafe), unsafe)-	-	dec bytes = (text, extra) where-		(safe, unsafe) = B.span (<= 0x7F) bytes-		text = T.pack (B8.unpack safe)-		extra = if B.null unsafe-			then Right B.empty-			else Left (illegalDec name (B.head unsafe), unsafe)-:--\subsubsection{ISO 8859-1}--:d text codec exports-, iso8859_1-:--:f Data/Enumerator/Text.hs-iso8859_1 :: Codec-iso8859_1 = Codec name enc dec where-	name = T.pack "ISO-8859-1"-	enc text = (bytes, extra) where-		(safe, unsafe) = tSpanBy (\c -> ord c <= 0xFF) text-		bytes = B8.pack (T.unpack safe)-		extra = if T.null unsafe-			then Nothing-			else Just (illegalEnc name (T.head unsafe), unsafe)-	-	dec bytes = (T.pack (B8.unpack bytes), Right B.empty)-:--\subsection{Encoding Utilities}--:f Data/Enumerator/Text.hs-illegalEnc :: T.Text -> Char -> Exc.SomeException-illegalEnc name c = Exc.toException . Exc.ErrorCall $-	concat [ "Codec "-	       , show name-	       , " can't encode character "-	       , reprChar c-	       ]-:--:f Data/Enumerator/Text.hs-illegalDec :: T.Text -> Word8 -> Exc.SomeException-illegalDec name w = Exc.toException . Exc.ErrorCall $-	concat [ "Codec "-	       , show name-	       , " can't decode byte "-	       , reprWord w-	       ]-:--:d Data.Enumerator.Text imports-import System.IO.Unsafe (unsafePerformIO)-:--:f Data/Enumerator/Text.hs-tryEvaluate :: a -> Either Exc.SomeException a-tryEvaluate = unsafePerformIO . Exc.try . Exc.evaluate--maybeDecode:: (a, b) -> Maybe (a, b)-maybeDecode (a, b) = case tryEvaluate a of-	Left _ -> Nothing-	Right _ -> Just (a, b)-:
src/types.anansi view
@@ -1,35 +1,4 @@-\section{Core types}--Most of this library's types and functions are exported from the-{\tt Data.Enumerator} module.--:f Data/Enumerator.hs-|Data.Enumerator module header|-module Data.Enumerator (-	|Data.Enumerator exports|-	) where-|Data.Enumerator imports|-:--\noindent A few utility functions share names with functions from the Prelude, so-those are removed from the default namespace.--:d Data.Enumerator imports-import qualified Prelude as Prelude-import Prelude hiding (-	|excluded Prelude imports|-	)-:--:d Data.Enumerator exports--- * Core--- ** Types-  Stream (..)-, Iteratee (..)-, Step (..)-, Enumerator-, Enumeratee-:+\section{Types and instances}  \subsection{Input streams} @@ -43,7 +12,7 @@ no data is currently available. Iteratees and enumeratees often special-case empty chunks for performance reasons, though they're not required to. -:f Data/Enumerator.hs+:d types and instances |apidoc Data.Enumerator.Stream| data Stream a 	= Chunks [a]@@ -54,15 +23,6 @@ 	return = Chunks . return 	Chunks xs >>= f = mconcat (fmap f xs) 	EOF >>= _ = EOF--instance Functor Stream where-	fmap f (Chunks xs) = Chunks (fmap f xs)-	fmap _ EOF = EOF---- | Since: 0.4.5-instance A.Applicative Stream where-	pure = return-	(<*>) = CM.ap :  The {\tt Monoid} instance deserves some special attention, because it has@@ -70,11 +30,7 @@ it's reasonable that appending chunks to an {\sc eof} stream should provide a valid stream, such behavior would violate the monoid laws. -:d Data.Enumerator imports-import Data.Monoid (Monoid, mempty, mappend, mconcat)-:--:f Data/Enumerator.hs+:d types and instances instance Monoid (Stream a) where 	mempty = Chunks mempty 	mappend (Chunks xs) (Chunks ys) = Chunks (xs ++ ys)@@ -105,11 +61,7 @@ proceeding further. \end{itemize} -:d Data.Enumerator imports-import qualified Control.Exception as Exc-:--:f Data/Enumerator.hs+:d types and instances data Step a m b 	|apidoc Data.Enumerator.Continue| 	= Continue (Stream a -> Iteratee a m b)@@ -126,10 +78,10 @@ 	} : -Users often need to construct iteratees which only yield or continue,-so we define some helper functions to save typing:+The pattern {\tt Iteratee (return (} \ldots{\tt ))} shows up a lot, so I define a+couple simple wrappers to save typing: -:f Data/Enumerator.hs+:d primitives |apidoc Data.Enumerator.returnI| returnI :: Monad m => Step a m b -> Iteratee a m b returnI step = Iteratee (return step)@@ -139,17 +91,64 @@ yield x extra = returnI (Yield x extra)  |apidoc Data.Enumerator.continue|-continue :: Monad m => (Stream a -> Iteratee a m b)-         -> Iteratee a m b+continue :: Monad m => (Stream a -> Iteratee a m b) -> Iteratee a m b continue k = returnI (Continue k) : -:d Data.Enumerator exports-, returnI-, yield-, continue+\subsection*{Monad instances}++Iteratees are monads; by sequencing iteratees, very complex processing may+be applied to arbitrary input streams. Iteratees are also applicative+functors and monad transformers.++:d types and instances+instance Monad m => Monad (Iteratee a m) where+	return x = yield x (Chunks [])+	|optimized iteratee bind| : +Because iteratees are often used for high-performance software, it is+important that the {\tt (>>=)} method be very efficient. We use a couple+magic-ish features here:++\begin{itemize}+\item First, the whole {\tt (>>=)} is worker-wrapper transformed so {\tt f}+can be cached when working with {\tt Continue}. This prevents a potential+space leak when working with infinite streams.++\item Second, the worker is rendered anonymous with {\tt fix}, so it doesn't+incur any additional time overhead.+\end{itemize}++The end result is a bind implementation with time performance equivalent to+the standard definition, but with significantly reduced memory allocation+rates.++:d optimized iteratee bind+m0 >>= f = ($ m0) $ fix $+	\bind m -> Iteratee $ runIteratee m >>= \r1 ->+		case r1 of+			Continue k -> return (Continue (bind . k))+			Error err -> return (Error err)+			Yield x (Chunks []) -> runIteratee (f x)+			Yield x extra -> runIteratee (f x) >>= \r2 ->+				case r2 of+					Continue k -> runIteratee (k extra)+					Error err -> return (Error err)+					Yield x' _ -> return (Yield x' extra)+:++Most iteratees are used to wrap \io{} operations, so it's sensible to define+instances for typeclasses from {\tt transformers}.++:d types and instances+instance MonadTrans (Iteratee a) where+	lift m = Iteratee (m >>= runIteratee . return)++instance MonadIO m => MonadIO (Iteratee a m) where+	liftIO = lift . liftIO+:+ \subsection{Enumerators}  Enumerators typically read from an external source (parser, handle, random@@ -161,7 +160,7 @@ also be considered step transformers of type {\tt Step a m b -> m (Step a m b)}. -:f Data/Enumerator.hs+:d types and instances |apidoc Data.Enumerator.Enumerator| type Enumerator a m b = Step a m b -> Iteratee a m b :@@ -197,163 +196,7 @@ to an inner iteratee. This model allows a single outer input to generate many inner inputs, and vice-versa. -:f Data/Enumerator.hs+:d types and instances |apidoc Data.Enumerator.Enumeratee|-type Enumeratee ao ai m b = Step ai m b-          -> Iteratee ao m (Step ai m b)-:--\subsection{Operators}--Because {\tt Iteratee a m b} is semantically equivalent to-{\tt m (Step a m b)}, several of the monadic combinators ({\tt (>>=)},-{\tt (>=>)}, etc) are useful to save typing when constructing enumerators-and enumeratees. {\tt (>>==)} corresponds to {\tt (>>=)}, {\tt (>==>)} to-{\tt (>=>)}, and so on.--For compatibility, {\tt (==<<)} is aliased to {\tt (\$\$)}.--:f Data/Enumerator.hs-infixl 1 >>==--|apidoc Data.Enumerator.(>>==)|-(>>==) :: Monad m-       => Iteratee a m b-       -> (Step a m b -> Iteratee a' m b')-       -> Iteratee a' m b'-i >>== f = Iteratee (runIteratee i >>= runIteratee . f)-:--:f Data/Enumerator.hs-infixr 1 ==<<--|apidoc Data.Enumerator.(==<<)|-(==<<) :: Monad m-       => (Step a m b -> Iteratee a' m b')-       -> Iteratee a m b-       -> Iteratee a' m b'-(==<<) = flip (>>==)-:--:f Data/Enumerator.hs-infixr 0 $$--|apidoc Data.Enumerator.($$)|-($$) :: Monad m-     => (Step a m b -> Iteratee a' m b')-     -> Iteratee a m b-     -> Iteratee a' m b'-($$) = (==<<)-:--:f Data/Enumerator.hs-infixr 1 >==>--|apidoc Data.Enumerator.(>==>)|-(>==>) :: Monad m-       => Enumerator a m b-       -> (Step a m b -> Iteratee a' m b')-       -> Step a m b-       -> Iteratee a' m b'-(>==>) e1 e2 s = e1 s >>== e2-:--:f Data/Enumerator.hs-infixr 1 <==<--|apidoc Data.Enumerator.(<==<)|-(<==<) :: Monad m-       => (Step a m b -> Iteratee a' m b')-       -> Enumerator a m b-       -> Step a m b-       -> Iteratee a' m b'-(<==<) = flip (>==>)-:--:d Data.Enumerator exports--- ** Operators-, (>>==)-, (==<<)-, ($$)-, (>==>)-, (<==<)-:--\subsection{Iteratees as Monads}--Iteratees are monads; by sequencing iteratees, very complex processing may-be applied to arbitrary input streams. Iteratees are also applicative-functors and monad transformers.--:d Data.Enumerator imports-import Data.Function (fix)-:--:f Data/Enumerator.hs-instance Monad m => Monad (Iteratee a m) where-	return x = yield x (Chunks [])-	-	m0 >>= f = ($ m0) $ fix $ \bind m -> Iteratee $ runIteratee m >>=-		\r1 -> case r1 of-			Continue k -> return (Continue (bind . k))-			Error err -> return (Error err)-			Yield x (Chunks []) -> runIteratee (f x)-			Yield x extra -> runIteratee (f x) >>=-				\r2 -> case r2 of-					Continue k -> runIteratee (k extra)-					Error err -> return (Error err)-					Yield x' _ -> return (Yield x' extra)-:--Most iteratees are used to wrap \io{} operations, so it's sensible to define-instances for typeclasses from {\tt transformers}.--:d Data.Enumerator imports-import Control.Monad.Trans.Class (MonadTrans, lift)-import Control.Monad.IO.Class (MonadIO, liftIO)-:--:f Data/Enumerator.hs-instance MonadTrans (Iteratee a) where-	lift m = Iteratee (m >>= runIteratee . return)--instance MonadIO m => MonadIO (Iteratee a m) where-	liftIO = lift . liftIO-:--It's probably possible to define {\tt Functor} and {\tt Applicative}-instances for {\tt Iteratee} without a {\tt Monad} constraint, but I haven't-bothered, since every useful operation requires {\tt m} to be a Monad anyway.--:d Data.Enumerator imports-import qualified Control.Applicative as A-import qualified Control.Monad as CM-:--:f Data/Enumerator.hs-instance Monad m => Functor (Iteratee a m) where-	fmap = CM.liftM-:--:f Data/Enumerator.hs-instance Monad m => A.Applicative (Iteratee a m) where-	pure = return-	(<*>) = CM.ap-:--:d Data.Enumerator imports-import Data.Typeable ( Typeable, typeOf-                     , Typeable1, typeOf1-                     , mkTyConApp, mkTyCon)-:--:f Data/Enumerator.hs--- | Since: 0.4.6-instance (Typeable a, Typeable1 m) => Typeable1 (Iteratee a m) where-	typeOf1 i = mkTyConApp tyCon [typeOf a, typeOf1 m] where-		tyCon = mkTyCon "Data.Enumerator.Iteratee"-		(a, m) = peel i-		-		peel :: Iteratee a m b -> (a, m ())-		peel = undefined+type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b) :
− src/util.anansi
@@ -1,250 +0,0 @@-\section{Misc. utilities}--A few special-case utilities that are used by similar libraries, or were-present in previous versions of {\tt enumerator}, or otherwise don't have a-good place to go.--:d Data.Enumerator exports--- * Misc. utilities-:--\subsection{Enumeratees}--Sequencing a fixed set of enumerators is easy, but for more complex-cases, it's useful to have a small utility wrapper.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.concatEnums|-concatEnums :: Monad m => [Enumerator a m b]-            -> Enumerator a m b-concatEnums = Prelude.foldl (>==>) returnI-:--:d Data.Enumerator exports-, concatEnums-:--{\tt joinI} is used to ``flatten'' enumeratees, to transform them into an-{\tt Iteratee}.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.joinI|-joinI :: Monad m => Iteratee a m (Step a' m b)-      -> Iteratee a m b-joinI outer = outer >>= check where-	check (Continue k) = k EOF >>== \s -> case s of-		Continue _ -> error "joinI: divergent iteratee"-		_ -> check s-	check (Yield x _) = return x-	check (Error e) = throwError e-:--{\tt joinE} is similar, except it flattens an enumerator/enumeratee pair-into a single enumerator.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.joinE|-joinE :: Monad m-      => Enumerator ao m (Step ai m b)-      -> Enumeratee ao ai m b-      -> Enumerator ai m b-joinE enum enee s = Iteratee $ do-	step <- runIteratee (enumEOF $$ enum $$ enee s)-	case step of-		Error err -> return (Error err)-		Yield x _ -> return x-		Continue _ -> error "joinE: divergent iteratee"-:--{\tt sequence} repeatedly runs its parameter to transform the stream.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.sequence|-sequence :: Monad m => Iteratee ao m ai-         -> Enumeratee ao ai m b-sequence i = loop where-	loop = checkDone check-	check k = isEOF >>= \f -> if f-		then yield (Continue k) EOF-		else step k-	step k = i >>= \v -> k (Chunks [v]) >>== loop-:--Another small, useful enumerator separates an input list into chunks, and-sends them to the iteratee. This is useful for testing iteratees in pure-code.--:d Data.Enumerator imports-import Data.List (genericSplitAt)-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.enumList|-enumList :: Monad m => Integer -> [a] -> Enumerator a m b-enumList n = loop where-	loop xs (Continue k) | not (null xs) = let-		(s1, s2) = genericSplitAt n xs-		in k (Chunks s1) >>== loop s2-	loop _ step = returnI step-:--:d Data.Enumerator exports-, joinI-, joinE-, Data.Enumerator.sequence-, enumList-:--\subsection{Running iteratees}--To simplify running iteratees, {\tt run} sends {\tt EOF} and then examines-the result. It is not possible for the result to be {\tt Continue}, because-{\tt enumEOF} calls {\tt error} for divergent iteratees.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.run|-run :: Monad m => Iteratee a m b-    -> m (Either Exc.SomeException b)-run i = do-	mStep <- runIteratee $ enumEOF ==<< i-	case mStep of-		Error err -> return $ Left err-		Yield x _ -> return $ Right x-		Continue _ -> error "run: divergent iteratee"-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.enumEOF|-enumEOF :: Monad m => Enumerator a m b-enumEOF (Yield x _) = yield x EOF-enumEOF (Error err) = throwError err-enumEOF (Continue k) = k EOF >>== check where-	check (Continue _) = error "enumEOF: divergent iteratee"-	check s = enumEOF s-:--{\tt run\_} is even more simplified; it's used in simple scripts, where the-user doesn't care about error handling.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.run_|-run_ :: Monad m => Iteratee a m b -> m b-run_ i = run i >>= either Exc.throw return-:--:d Data.Enumerator exports-, enumEOF-, run-, run_-:--\subsection{{\tt checkDone} and {\tt checkDoneEx}}--A common pattern in {\tt Enumeratee} implementations is to check whether-the inner {\tt Iteratee} has finished, and if so, to return its output.-{\tt checkDone} passes its parameter a continuation if the {\tt Iteratee}-can still consume input, or yields otherwise.--Oleg's version of {\tt checkDone} has a problem---when the enumeratee has-some sort of input buffer, but the underlying iteratee enters {\tt Yield},-it will discard the output buffer. {\tt checkDoneEx} corrects this; for-backwards compatibility, {\tt checkDone} remains.--:f Data/Enumerator.hs-|apidoc Data.Enumerator.checkDoneEx|-checkDoneEx :: Monad m =>-	Stream a' ->-	((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->-	Enumeratee a' a m b-checkDoneEx _     f (Continue k) = f k-checkDoneEx extra _ step         = yield step extra--|apidoc Data.Enumerator.checkDone|-checkDone :: Monad m =>-	((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->-	Enumeratee a' a m b-checkDone = checkDoneEx (Chunks [])-:--:d Data.Enumerator exports-, checkDone-, checkDoneEx-:--:f Data/Enumerator.hs-|apidoc Data.Enumerator.isEOF|-isEOF :: Monad m => Iteratee a m Bool-isEOF = continue $ \s -> case s of-	EOF -> yield True s-	_ -> yield False s-:--:d Data.Enumerator exports-, isEOF-:--{\tt Data.Enumerator.Util} is a hidden module for functions used by several-public modules, but not logically part of the {\tt enumerator} API.--:f Data/Enumerator/Util.hs-{-# LANGUAGE CPP #-}-module Data.Enumerator.Util where-import Data.Enumerator--import Data.Char (toUpper, intToDigit, ord)-import Data.Word (Word8)-import qualified Data.Text as T-import qualified Data.Text.Lazy as TL--import Control.Monad.IO.Class (MonadIO, liftIO)-import qualified Control.Exception as Exc-import Numeric (showIntAtBase)-:--:f Data/Enumerator/Util.hs-tryStep :: MonadIO m => IO t -> (t -> Iteratee a m b) -> Iteratee a m b-tryStep get io = do-	tried <- liftIO (Exc.try get)-	case tried of-		Right t -> io t-		Left err -> throwError (err :: Exc.SomeException)-:--:f Data/Enumerator/Util.hs-pad0 :: Int -> String -> String-pad0 size str = padded where-	len = Prelude.length str-	padded = if len >= size-		then str-		else Prelude.replicate (size - len) '0' ++ str-:--:f Data/Enumerator/Util.hs-reprChar :: Char -> String-reprChar c = "U+" ++ (pad0 4 (showIntAtBase 16 (toUpper . intToDigit) (ord c) ""))-:--:f Data/Enumerator/Util.hs-reprWord :: Word8 -> String-reprWord w = "0x" ++ (pad0 2 (showIntAtBase 16 (toUpper . intToDigit) w ""))-:--{\tt text-0.11} changed some function names to appease a few bikeshedding-idiots in -cafe; to support it, a bit of compatibility code is needed.--I had a choice between using the preprocessor, or a separate module plus-some Cabal magic. It turns out that {\tt cabal sdist} doesn't properly-handle multiple source directories selected by flags, so the preprocessor-is used for now.--:f Data/Enumerator/Util.hs-tSpanBy  :: (Char -> Bool) -> T.Text -> (T.Text, T.Text)-tlSpanBy :: (Char -> Bool) -> TL.Text -> (TL.Text, TL.Text)-#if MIN_VERSION_text(0,11,0)-tSpanBy = T.span-tlSpanBy = TL.span-#else-tSpanBy = T.spanBy-tlSpanBy = TL.spanBy-#endif-:
+ src/utilities.anansi view
@@ -0,0 +1,301 @@+\section{Miscellaneous}++A few special-case utilities that are used by similar libraries, or were+present in previous versions of {\tt enumerator}, or otherwise don't have a+good place to go.++Sequencing a fixed set of enumerators is easy, but for more complex+cases, it's useful to have a small utility wrapper.++:d unsorted utilities+|apidoc Data.Enumerator.concatEnums|+concatEnums :: Monad m => [Enumerator a m b]+            -> Enumerator a m b+concatEnums = Prelude.foldl (>==>) returnI+:++{\tt joinI} is used to ``flatten'' enumeratees, to transform them into an+{\tt Iteratee}.++:d unsorted utilities+|apidoc Data.Enumerator.joinI|+joinI :: Monad m => Iteratee a m (Step a' m b)+      -> Iteratee a m b+joinI outer = outer >>= check where+	check (Continue k) = k EOF >>== \s -> case s of+		Continue _ -> error "joinI: divergent iteratee"+		_ -> check s+	check (Yield x _) = return x+	check (Error e) = throwError e+:++{\tt joinE} is similar, except it flattens an enumerator/enumeratee pair+into a single enumerator.++:d unsorted utilities+|apidoc Data.Enumerator.joinE|+joinE :: Monad m+      => Enumerator ao m (Step ai m b)+      -> Enumeratee ao ai m b+      -> Enumerator ai m b+joinE enum enee s = Iteratee $ do+	step <- runIteratee (enumEOF $$ enum $$ enee s)+	case step of+		Error err -> return (Error err)+		Yield x _ -> return x+		Continue _ -> error "joinE: divergent iteratee"+:++{\tt sequence} repeatedly runs its parameter to transform the stream.++:d unsorted utilities+|apidoc Data.Enumerator.sequence|+sequence :: Monad m => Iteratee ao m ai+         -> Enumeratee ao ai m b+sequence i = loop where+	loop = checkDone check+	check k = isEOF >>= \f -> if f+		then yield (Continue k) EOF+		else step k+	step k = i >>= \v -> k (Chunks [v]) >>== loop+:++:d unsorted utilities+|apidoc Data.Enumerator.enumEOF|+enumEOF :: Monad m => Enumerator a m b+enumEOF (Yield x _) = yield x EOF+enumEOF (Error err) = throwError err+enumEOF (Continue k) = k EOF >>== check where+	check (Continue _) = error "enumEOF: divergent iteratee"+	check s = enumEOF s+:++A common pattern in {\tt Enumeratee} implementations is to check whether+the inner {\tt Iteratee} has finished, and if so, to return its output.+{\tt checkDone} passes its parameter a continuation if the {\tt Iteratee}+can still consume input, or yields otherwise.++Oleg's version of {\tt checkDone} has a problem---when the enumeratee has+some sort of input buffer, but the underlying iteratee enters {\tt Yield},+it will discard the output buffer. {\tt checkDoneEx} corrects this; for+backwards compatibility, {\tt checkDone} remains.++:d unsorted utilities+|apidoc Data.Enumerator.checkDoneEx|+checkDoneEx :: Monad m =>+	Stream a' ->+	((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->+	Enumeratee a' a m b+checkDoneEx _     f (Continue k) = f k+checkDoneEx extra _ step         = yield step extra++|apidoc Data.Enumerator.checkDone|+checkDone :: Monad m =>+	((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->+	Enumeratee a' a m b+checkDone = checkDoneEx (Chunks [])+:++:d unsorted utilities+|apidoc Data.Enumerator.isEOF|+isEOF :: Monad m => Iteratee a m Bool+isEOF = continue $ \s -> case s of+	EOF -> yield True s+	_ -> yield False s+:++{\tt Data.Enumerator.Util} is a hidden module for functions used by several+public modules, but not logically part of the {\tt enumerator} API.++:f Data/Enumerator/Util.hs+{-# LANGUAGE CPP #-}+module Data.Enumerator.Util where+import Data.Enumerator++import Data.Char (toUpper, intToDigit, ord)+import Data.Word (Word8)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL++import Control.Monad.IO.Class (MonadIO, liftIO)+import qualified Control.Exception as Exc+import Numeric (showIntAtBase)+:++:f Data/Enumerator/Util.hs+tryIO :: MonadIO m => IO b -> Iteratee a m b+tryIO io = Iteratee $ do+	tried <- liftIO (Exc.try io)+	return $ case tried of+		Right b -> Yield b (Chunks [])+		Left err -> Error err+:++:f Data/Enumerator/Util.hs+pad0 :: Int -> String -> String+pad0 size str = padded where+	len = Prelude.length str+	padded = if len >= size+		then str+		else Prelude.replicate (size - len) '0' ++ str+:++:f Data/Enumerator/Util.hs+reprChar :: Char -> String+reprChar c = "U+" ++ (pad0 4 (showIntAtBase 16 (toUpper . intToDigit) (ord c) ""))+:++:f Data/Enumerator/Util.hs+reprWord :: Word8 -> String+reprWord w = "0x" ++ (pad0 2 (showIntAtBase 16 (toUpper . intToDigit) w ""))+:++{\tt text-0.11} changed some function names to appease a few bikeshedding+idiots in -cafe; to support it, a bit of compatibility code is needed.++I had a choice between using the preprocessor, or a separate module plus+some Cabal magic. It turns out that {\tt cabal sdist} doesn't properly+handle multiple source directories selected by flags, so the preprocessor+is used for now.++:f Data/Enumerator/Util.hs+tSpanBy  :: (Char -> Bool) -> T.Text -> (T.Text, T.Text)+tlSpanBy :: (Char -> Bool) -> TL.Text -> (TL.Text, TL.Text)+#if MIN_VERSION_text(0,11,0)+tSpanBy = T.span+tlSpanBy = TL.span+#else+tSpanBy = T.spanBy+tlSpanBy = TL.spanBy+#endif+:++{\tt text-0.8} added the useful {\tt toStrict} function; this wrapper+lets {\tt enumerator} work with {\tt text-0.7}.++:f Data/Enumerator/Util.hs+textToStrict :: TL.Text -> T.Text+#if MIN_VERSION_text(0,8,0)+textToStrict = TL.toStrict+#else+textToStrict = T.concat . TL.toChunks+#endif+:++\subsection{Supplemental instances}++It can be pretty useful to define {\tt Typeable} instances for iteratees+and streams. For example, they allow iteratee-based libraries to be loaded+dynamically as plugins.++Normally I'd use the {\tt DeriveDataTypeable} language extension, but+many users have said they find {\tt enumerator} useful in large part+because it doesn't rely on extensions. So instead, the instances are+derived manually.++:d Data.Enumerator imports+import Data.Typeable ( Typeable, typeOf+                     , Typeable1, typeOf1+                     , mkTyConApp, mkTyCon)+:++:d supplemental instances+-- | Since: 0.4.8+instance Typeable1 Stream where+	typeOf1 _ = mkTyConApp tyCon [] where+		tyCon = mkTyCon "Data.Enumerator.Stream"+:++:d supplemental instances+-- | Since: 0.4.6+instance (Typeable a, Typeable1 m) =>+	Typeable1 (Iteratee a m) where+		typeOf1 i = let+			tyCon = mkTyCon "Data.Enumerator.Iteratee"+			(a, m) = peel i+			+			peel :: Iteratee a m b -> (a, m ())+			peel = undefined+			+			in mkTyConApp tyCon [typeOf a, typeOf1 m]+:++:d supplemental instances+-- | Since: 0.4.8+instance (Typeable a, Typeable1 m) =>+	Typeable1 (Step a m) where+		typeOf1 s = let+			tyCon = mkTyCon "Data.Enumerator.Step"+			(a, m) = peel s+			+			peel :: Step a m b -> (a, m ())+			peel = undefined+			+			in mkTyConApp tyCon [typeOf a, typeOf1 m]+:++It's probably possible to define {\tt Functor} and {\tt Applicative}+instances for {\tt Iteratee} without a {\tt Monad} constraint, but I haven't+bothered, since every useful operation requires {\tt m} to be a Monad anyway.++:d supplemental instances+instance Monad m => Functor (Iteratee a m) where+	fmap = CM.liftM+:++:d supplemental instances+instance Monad m => A.Applicative (Iteratee a m) where+	pure = return+	(<*>) = CM.ap+:++:d supplemental instances+instance Functor Stream where+	fmap f (Chunks xs) = Chunks (fmap f xs)+	fmap _ EOF = EOF++-- | Since: 0.4.5+instance A.Applicative Stream where+	pure = return+	(<*>) = CM.ap+:++\subsection{Testing and debugging}++Debugging enumerator-based code is mostly a question of what inputs are+being passed around. {\tt printChunks} prints out exactly what chunks are+being sent from an enumerator.++:d utilities for testing and debugging+|apidoc Data.Enumerator.printChunks|+printChunks :: (MonadIO m, Show a)+            => Bool -- ^ Print empty chunks+            -> Iteratee a m ()+printChunks printEmpty = continue loop where+	loop (Chunks xs) = do+		let hide = null xs && not printEmpty+		CM.unless hide (liftIO (print xs))+		continue loop+	+	loop EOF = do+		liftIO (putStrLn "EOF")+		yield () EOF+:++Another small, useful enumerator separates an input list into chunks, and+sends them to the iteratee. This is useful for testing iteratees in pure+code.++:d Data.Enumerator imports+import Data.List (genericSplitAt)+:++:d utilities for testing and debugging+|apidoc Data.Enumerator.enumList|+enumList :: Monad m => Integer -> [a] -> Enumerator a m b+enumList n = loop where+	loop xs (Continue k) | not (null xs) = let+		(s1, s2) = genericSplitAt n xs+		in k (Chunks s1) >>== loop s2+	loop _ step = returnI step+:
+ tests/Benchmarks.hs view
@@ -0,0 +1,98 @@+-- Copyright (C) 2010-2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module Main where++import Criterion.Types+import qualified Criterion.Config as C+import qualified Criterion.Main as C+import qualified Progression.Config as P+import qualified Progression.Main as P++import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import qualified Data.ByteString.Lazy as BL++import qualified Data.Text as T+import qualified Data.Text as TL++import Data.Enumerator hiding (map, replicate)+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.Text as ET++import Control.DeepSeq+import Data.Functor.Identity+import System.Environment+import System.Exit+import System.IO++instance NFData B.ByteString++instance NFData BL.ByteString where+	rnf a = rnf (BL.toChunks a)++bytes_100 :: B.ByteString+bytes_100 = B.replicate 100 0x61++chars_100 :: T.Text+chars_100 = T.replicate 100 (T.singleton 'a')++bench_binary :: Iteratee B.ByteString Identity b -> b+bench_binary iter = runIdentity (run_ (enum $$ iter)) where+	enum = enumList 2 (replicate 1000 bytes_100)++bench_text :: Iteratee T.Text Identity b -> b+bench_text iter = runIdentity (run_ (enum $$ iter)) where+	enum = enumList 2 (replicate 1000 chars_100)++bench_bind :: Iteratee Int Identity b -> b+bench_bind iter = runIdentity (run_ (enum 10000 $$ iter)) where+	enum 0 step = returnI step+	enum n (Continue k) = k (Chunks [n]) >>== enum (n - 1)+	enum _ step = returnI step++bench_enumFile :: Maybe Integer -> Iteratee B.ByteString IO b -> IO b+bench_enumFile limit iter = run_ (EB.enumFileRange "/dev/zero" Nothing limit $$ iter)++iterUnit :: Monad m => Iteratee a m ()+iterUnit = continue loop where+	loop EOF = yield () EOF+	loop (Chunks _) = continue loop++iterUnitTo :: Monad m => Int -> Iteratee a m ()+iterUnitTo n | n <= 0 = yield () EOF+iterUnitTo n = continue check where+	check EOF = yield () EOF+	check (Chunks _) = iterUnitTo (n - 1)++benchmarks :: [Benchmark]+benchmarks =+	[ bgroup "general"+	  [ bench "bind" (nf bench_bind iterUnit)+	  ]+	, bgroup "binary"+	  [ bench "takeWhile" (nf bench_binary (EB.takeWhile (const True)))+	  , bench "consume" (nf bench_binary EB.consume)+	  , bench "enumFile-nolimit" (nfIO (bench_enumFile Nothing (iterUnitTo 10000)))+	  , bench "enumFile-limit" (nfIO (bench_enumFile (Just 1000000000) (iterUnitTo 10000)))+	  ]+	, bgroup "text"+	  [ bench "takeWhile" (nf bench_text (ET.takeWhile (const True)))+	  , bench "consume" (nf bench_text ET.consume)+	  ]+	]++main :: IO ()+main = do+	args <- getArgs+	case args of+		"progression":extra -> withArgs extra $ P.defaultMain (bgroup "all" benchmarks)+		"criterion":extra -> withArgs extra $ let+			config = C.defaultConfig { C.cfgPerformGC = C.ljust True }+			in C.defaultMainWith config (return ()) benchmarks+		_ -> do+			name <- getProgName+			hPutStrLn stderr $ concat ["Usage: ", name, " <progression|criterion>"]+			exitFailure
tests/Properties.hs view
@@ -3,7 +3,17 @@ -- See license.txt for details module Main (tests, main) where -import Data.Enumerator (($$))+import qualified Control.Exception as Exc+import           Data.Bits ((.&.))+import           Data.Char (chr)+import qualified Data.List as L+import qualified Data.List.Split as LS+import           Data.Monoid (mappend, mempty, mconcat)+import           Data.Functor.Identity (Identity, runIdentity)+import           Data.String (IsString, fromString)+import           Data.Word (Word8)++import           Data.Enumerator (($$)) import qualified Data.Enumerator as E import qualified Data.Enumerator.Binary as EB import qualified Data.Enumerator.Text as ET@@ -16,19 +26,10 @@ import qualified Data.Text.Lazy as TL import qualified Data.Text.Encoding as TE -import Test.QuickCheck hiding ((.&.))-import Test.QuickCheck.Poly+import           Test.QuickCheck hiding ((.&.))+import           Test.QuickCheck.Poly (A, B, C) import qualified Test.Framework as F-import Test.Framework.Providers.QuickCheck2 (testProperty)--import Control.Applicative-import Control.Exception-import Control.Monad-import Data.Bits-import Data.Char (chr)-import Data.Monoid-import Data.Functor.Identity-import Data.String+import           Test.Framework.Providers.QuickCheck2 (testProperty)  tests :: [F.Test] tests =@@ -48,7 +49,6 @@ test_StreamInstances = F.testGroup "Stream Instances" 	[ test_StreamMonoid 	, test_StreamFunctor-	, test_StreamApplicative 	, test_StreamMonad 	] @@ -84,30 +84,6 @@ 	prop_law2 :: E.Stream A -> Blind (B -> C) -> Blind (A -> B) -> Bool 	prop_law2 x (Blind f) (Blind g) = fmap (f . g) x == (fmap f . fmap g) x -test_StreamApplicative :: F.Test-test_StreamApplicative = F.testGroup "Applicative Stream" props where-	props = [ testProperty "law 1" prop_law1-	        , testProperty "law 2" prop_law2-	        , testProperty "law 3" prop_law3-	        , testProperty "law 4" prop_law4-	        , testProperty "law 5" prop_law5-	        ]-	-	prop_law1 :: E.Stream A -> Bool-	prop_law1 v = (pure id <*> v) == v-	-	prop_law2 :: Blind (E.Stream (B -> C)) -> Blind (E.Stream (A -> B)) -> E.Stream A -> Bool-	prop_law2 (Blind u) (Blind v) w = (pure (.) <*> u <*> v <*> w) == (u <*> (v <*> w))-	-	prop_law3 :: Blind (A -> B) -> A -> Bool-	prop_law3 (Blind f) x = (pure f <*> pure x) == (pure (f x) `asTypeOf` E.Chunks [B 0])-	-	prop_law4 :: Blind (E.Stream (A -> B)) -> A -> Bool-	prop_law4 (Blind u) y = (u <*> pure y) == (pure ($ y) <*> u)-	-	prop_law5 :: Blind (A -> B) -> E.Stream A -> Bool-	prop_law5 (Blind f) x = (fmap f x) == (pure f <*> x)- test_StreamMonad :: F.Test test_StreamMonad = F.testGroup "Monad Stream" props where 	props = [ testProperty "law 1" prop_law1@@ -149,7 +125,7 @@ 		result = runIdentity (E.run_ iter) 		 		iter = E.enumList n xs $$ do-			a <- enee $$ E.throwError (ErrorCall "")+			_ <- enee $$ E.throwError (Exc.ErrorCall "") 			EL.consume 		 		in result == xs@@ -169,22 +145,22 @@ 	]  test_Map :: F.Test-test_Map = test_Enumeratee "map" (E.map id)+test_Map = test_Enumeratee "map" (EL.map id)  test_ConcatMap :: F.Test-test_ConcatMap = test_Enumeratee "concatMap" (E.concatMap (:[]))+test_ConcatMap = test_Enumeratee "concatMap" (EL.concatMap (:[]))  test_MapM :: F.Test-test_MapM = test_Enumeratee "mapM" (E.mapM return)+test_MapM = test_Enumeratee "mapM" (EL.mapM return)  test_ConcatMapM :: F.Test-test_ConcatMapM = test_Enumeratee "concatMapM" (E.concatMapM (\x -> return [x]))+test_ConcatMapM = test_Enumeratee "concatMapM" (EL.concatMapM (\x -> return [x]))  test_Filter :: F.Test-test_Filter = test_Enumeratee "filter" (E.filter (\_ -> True))+test_Filter = test_Enumeratee "filter" (EL.filter (\_ -> True))  test_FilterM :: F.Test-test_FilterM = test_Enumeratee "filterM" (E.filterM (\_ -> return True))+test_FilterM = test_Enumeratee "filterM" (EL.filterM (\_ -> return True))  -- }}} @@ -452,262 +428,194 @@  test_ListAnalogues :: F.Test test_ListAnalogues = F.testGroup "list analogues"-	[ test_ListConsume-	, test_ListHead-	, test_ListDrop-	, test_ListTake-	-- , test_ListPeek-	, test_ListRequire-	, test_ListIsolate-	-	, test_BinaryConsume-	, test_BinaryHead-	, test_BinaryDrop-	, test_BinaryTake-	, test_BinaryRequire-	, test_BinaryIsolate-	-	, test_TextConsume-	, test_TextHead-	, test_TextDrop-	, test_TextTake-	, test_TextRequire-	, test_TextIsolate+	[ test_Consume+	, test_Head+	, test_Drop+	, test_Take+	, test_Require+	, test_Isolate+	, test_SplitWhen 	] -test_ListConsume :: F.Test-test_ListConsume = testProperty "List.consume" prop where-	prop :: [A] -> Bool-	prop xs = result == xs where-		result = runIdentity (E.run_ iter)-		iter = E.enumList 1 xs $$ EL.consume--test_ListHead :: F.Test-test_ListHead = testProperty "List.head" prop where-	prop :: [A] -> Bool-	prop xs = result == expected where-		result = runIdentity (E.run_ iter)-		expected = case xs of-			[] -> (Nothing, [])-			(x:xs') -> (Just x, xs')-		-		iter = E.enumList 1 xs $$ do-			x <- EL.head-			extra <- EL.consume-			return (x, extra)--test_ListDrop :: F.Test-test_ListDrop = testProperty "List.drop" prop where-	prop :: Positive Integer -> [A] -> Bool-	prop (Positive n) xs = result == expected where-		result = runIdentity (E.run_ iter)-		expected = drop (fromInteger n) xs-		-		iter = E.enumList 1 xs $$ do-			EL.drop n-			EL.consume--test_ListTake :: F.Test-test_ListTake = testProperty "List.take" prop where-	prop :: Positive Integer -> [A] -> Bool-	prop (Positive n) xs = result == expected where-		result = runIdentity (E.run_ iter)-		expected = splitAt (fromInteger n) xs-		-		iter = E.enumList 1 xs $$ do-			xs <- EL.take n-			extra <- EL.consume-			return (xs, extra)--{--test_ListPeek :: F.Test-test_ListPeek = testProperty "List.peek" prop where-	prop :: Positive Integer -> [A] -> Bool-	prop (Positive n) xs = result == expected where-		result = runIdentity (E.run_ iter)-		expected = (take (fromInteger n) xs, xs)-		-		iter = E.enumList 1 xs $$ do-			xs <- EL.peek n-			extra <- EL.consume-			return (xs, extra)--}--test_ListRequire :: F.Test-test_ListRequire = testProperty "List.require" prop where-	prop :: Positive Integer -> [A] -> Bool-	prop (Positive n) xs = result == expected where-		result = case runIdentity (E.run iter) of-			Left exc -> Left (show exc)-			Right x -> Right x-		expected = if n > toInteger (length xs)-			then Left "require: Unexpected EOF"-			else Right xs-		-		iter = E.enumList 1 xs $$ do-			EL.require n-			EL.consume--test_ListIsolate :: F.Test-test_ListIsolate = testProperty "List.isolate" prop where-	prop :: Positive Integer -> [A] -> Bool-	prop (Positive n) xs = result == expected where-		result = runIdentity (E.run_ iter)-		expected = case xs of-			[] -> (Nothing, [])-			(x:[]) -> (Just x, [])-			(x:_:xs') -> (Just x, xs')-		-		iter = E.enumList 1 xs $$ do-			x <- E.joinI (EL.isolate 2 $$ EL.head)-			extra <- EL.consume-			return (x, extra)--test_BinaryConsume :: F.Test-test_BinaryConsume = testProperty "Binary.consume" prop where-	prop ts = result == BL.fromChunks ts where-		result = runIdentity (E.run_ iter)-		iter = E.enumList 1 ts $$ EB.consume--test_BinaryHead :: F.Test-test_BinaryHead = testProperty "Binary.head" prop where-	prop ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = case BL.uncons (BL.fromChunks ts) of-			Nothing -> (Nothing, BL.empty)-			Just (x, extra) -> (Just x, extra)-		-		iter = E.enumList 1 ts $$ do-			x <- EB.head-			extra <- EB.consume-			return (x, extra)+check :: Eq b => E.Iteratee a Identity b -> ([a] -> Either Exc.ErrorCall b) -> [a] -> Bool+check iter plain xs = expected == run iter xs where+	expected = case plain xs of+		Left exc -> Left (Just exc)+		Right x -> Right x+	+	run iter xs = case runIdentity (E.run (E.enumList 1 xs $$ iter)) of+		Left exc -> Left (Exc.fromException exc)+		Right x -> Right x -test_BinaryDrop :: F.Test-test_BinaryDrop = testProperty "Binary.drop" prop where-	prop :: Positive Integer -> [B.ByteString] -> Bool-	prop (Positive n) ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = BL.drop (fromInteger n) (BL.fromChunks ts)-		-		iter = E.enumList 1 ts $$ do-			EB.drop n-			EB.consume+testListAnalogue name iterList plainList iterText plainText iterBytes plainBytes = F.testGroup name tests where+	tests = [ testProperty "list" prop_List+	        , testProperty "text" prop_Text+	        , testProperty "bytes" prop_Bytes+	        ]+	+	prop_List :: [A] -> Bool+	prop_List xs = check iterList plainList xs+	+	prop_Text xs = check iterText (plainText . TL.fromChunks) xs+	prop_Bytes xs = check iterBytes (plainBytes . BL.fromChunks) xs -test_BinaryTake :: F.Test-test_BinaryTake = testProperty "Binary.take" prop where-	prop :: Positive Integer -> [B.ByteString] -> Bool-	prop (Positive n) ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = BL.splitAt (fromInteger n) (BL.fromChunks ts)-		-		iter = E.enumList 1 ts $$ do-			xs <- EB.take n-			extra <- EB.consume-			return (xs, extra)+testListAnalogueN name iterList plainList iterText plainText iterBytes plainBytes = F.testGroup name tests where+	tests = [ testProperty "list" prop_List+	        , testProperty "text" prop_Text+	        , testProperty "bytes" prop_Bytes+	        ]+	+	prop_List :: Positive Integer -> [A] -> Bool+	prop_List (Positive n) xs = check (iterList n) (plainList n) xs+	+	prop_Text (Positive n) xs = check (iterText n) (plainText n . TL.fromChunks) xs+	prop_Bytes (Positive n) xs = check (iterBytes n) (plainBytes n . BL.fromChunks) xs -test_BinaryRequire :: F.Test-test_BinaryRequire = testProperty "Binary.require" prop where-	prop :: Positive Integer -> [B.ByteString] -> Bool-	prop (Positive n) ts = result == expected where-		result = case runIdentity (E.run iter) of-			Left exc -> Left (show exc)-			Right x -> Right x-		lazy = BL.fromChunks ts-		expected = if n > toInteger (BL.length lazy)-			then Left "require: Unexpected EOF"-			else Right lazy-		-		iter = E.enumList 1 ts $$ do-			EB.require n-			EB.consume+testListAnalogueX name iterList plainList iterText plainText iterBytes plainBytes = F.testGroup name tests where+	tests = [ testProperty "list" prop_List+	        , testProperty "text" prop_Text+	        , testProperty "bytes" prop_Bytes+	        ]+	+	prop_List :: A -> [A] -> Bool+	prop_List x xs = check (iterList x) (plainList x) xs+	+	prop_Text x xs = check (iterText x) (plainText x . TL.fromChunks) xs+	prop_Bytes x xs = check (iterBytes x) (plainBytes x . BL.fromChunks) xs -test_BinaryIsolate :: F.Test-test_BinaryIsolate = testProperty "Binary.isolate" prop where-	prop :: Positive Integer -> [B.ByteString] -> Bool-	prop (Positive n) ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = case BL.unpack (BL.fromChunks ts) of-			[] -> (Nothing, BL.empty)-			(x:[]) -> (Just x, BL.empty)-			(x:_:xs') -> (Just x, BL.pack xs')-		-		iter = E.enumList 1 ts $$ do-			x <- E.joinI (EB.isolate 2 $$ EB.head)-			extra <- EB.consume-			return (x, extra)+test_Consume :: F.Test+test_Consume = testListAnalogue "consume"+	EL.consume Right+	ET.consume Right+	EB.consume Right -test_TextConsume :: F.Test-test_TextConsume = testProperty "Text.consume" prop where-	prop ts = result == TL.fromChunks ts where-		result = runIdentity (E.run_ iter)-		iter = E.enumList 1 ts $$ ET.consume+test_Head :: F.Test+test_Head = testListAnalogue "head"+	(do+		x <- EL.head+		extra <- EL.consume+		return (x, extra)+	)+	(\xs -> Right $ case xs of+		[] -> (Nothing, [])+		(x:xs') -> (Just x, xs'))+	(do+		x <- ET.head+		extra <- ET.consume+		return (x, extra)+	)+	(\text -> Right $ case TL.uncons text of+		Nothing -> (Nothing, TL.empty)+		Just (x, extra) -> (Just x, extra))+	(do+		x <- EB.head+		extra <- EB.consume+		return (x, extra)+	)+	(\bytes -> Right $ case BL.uncons bytes of+		Nothing -> (Nothing, BL.empty)+		Just (x, extra) -> (Just x, extra)) -test_TextHead :: F.Test-test_TextHead = testProperty "Text.head" prop where-	prop ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = case TL.uncons (TL.fromChunks ts) of-			Nothing -> (Nothing, TL.empty)-			Just (x, extra) -> (Just x, extra)-		-		iter = E.enumList 1 ts $$ do-			x <- ET.head-			extra <- ET.consume-			return (x, extra)+test_Drop :: F.Test+test_Drop = testListAnalogueN "drop"+	(\n -> EL.drop n >> EL.consume)+	(\n -> Right . L.genericDrop n)+	(\n -> ET.drop n >> ET.consume)+	(\n -> Right . TL.drop (fromInteger n))+	(\n -> EB.drop n >> EB.consume)+	(\n -> Right . BL.drop (fromInteger n)) -test_TextDrop :: F.Test-test_TextDrop = testProperty "Text.drop" prop where-	prop :: Positive Integer -> [T.Text] -> Bool-	prop (Positive n) ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = TL.drop (fromInteger n) (TL.fromChunks ts)-		-		iter = E.enumList 1 ts $$ do-			ET.drop n-			ET.consume+test_Take :: F.Test+test_Take = testListAnalogueN "take"+	(\n -> do+		xs <- EL.take n+		extra <- EL.consume+		return (xs, extra))+	(\n -> Right . L.genericSplitAt n)+	(\n -> do+		xs <- ET.take n+		extra <- ET.consume+		return (xs, extra))+	(\n -> Right . TL.splitAt (fromInteger n))+	(\n -> do+		xs <- EB.take n+		extra <- EB.consume+		return (xs, extra))+	(\n -> Right . BL.splitAt (fromInteger n)) -test_TextTake :: F.Test-test_TextTake = testProperty "Text.take" prop where-	prop :: Positive Integer -> [T.Text] -> Bool-	prop (Positive n) ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = TL.splitAt (fromInteger n) (TL.fromChunks ts)-		-		iter = E.enumList 1 ts $$ do-			xs <- ET.take n-			extra <- ET.consume-			return (xs, extra)+test_Require :: F.Test+test_Require = testListAnalogueN "require"+	(\n -> do+		EL.require n+		EL.consume)+	(\n xs -> if n > toInteger (length xs)+		then Left (Exc.ErrorCall "require: Unexpected EOF")+		else Right xs)+	(\n -> do+		ET.require n+		ET.consume)+	(\n xs -> if n > toInteger (TL.length xs)+		then Left (Exc.ErrorCall "require: Unexpected EOF")+		else Right xs)+	(\n -> do+		EB.require n+		EB.consume)+	(\n xs -> if n > toInteger (BL.length xs)+		then Left (Exc.ErrorCall "require: Unexpected EOF")+		else Right xs) -test_TextRequire :: F.Test-test_TextRequire = testProperty "Text.require" prop where-	prop :: Positive Integer -> [T.Text] -> Bool-	prop (Positive n) ts = result == expected where-		result = case runIdentity (E.run iter) of-			Left exc -> Left (show exc)-			Right x -> Right x-		lazy = TL.fromChunks ts-		expected = if n > toInteger (TL.length lazy)-			then Left "require: Unexpected EOF"-			else Right lazy-		-		iter = E.enumList 1 ts $$ do-			ET.require n-			ET.consume+test_Isolate :: F.Test+test_Isolate = testListAnalogue "isolate"+	(do+		x <- E.joinI (EL.isolate 2 $$ EL.head)+		extra <- EL.consume+		return (x, extra))+	(\xs -> Right $ case xs of+		[] -> (Nothing, [])+		(x:[]) -> (Just x, [])+		(x:_:xs') -> (Just x, xs'))+	(do+		x <- E.joinI (ET.isolate 2 $$ ET.head)+		extra <- ET.consume+		return (x, extra))+	(\text -> Right $ case TL.unpack text of+		[] -> (Nothing, TL.empty)+		(x:[]) -> (Just x, TL.empty)+		(x:_:xs') -> (Just x, TL.pack xs'))+	(do+		x <- E.joinI (EB.isolate 2 $$ EB.head)+		extra <- EB.consume+		return (x, extra))+	(\bytes -> Right $ case BL.unpack bytes of+		[] -> (Nothing, BL.empty)+		(x:[]) -> (Just x, BL.empty)+		(x:_:xs) -> (Just x, BL.pack xs)) -test_TextIsolate :: F.Test-test_TextIsolate = testProperty "Text.isolate" prop where-	prop :: Positive Integer -> [T.Text] -> Bool-	prop (Positive n) ts = result == expected where-		result = runIdentity (E.run_ iter)-		expected = case TL.unpack (TL.fromChunks ts) of-			[] -> (Nothing, TL.empty)-			(x:[]) -> (Just x, TL.empty)-			(x:_:xs') -> (Just x, TL.pack xs')-		-		iter = E.enumList 1 ts $$ do-			x <- E.joinI (ET.isolate 2 $$ ET.head)-			extra <- ET.consume-			return (x, extra)+test_SplitWhen :: F.Test+test_SplitWhen = testListAnalogueX "splitWhen"+	(\x -> do+		xs <- E.joinI (EL.splitWhen (== x) $$ EL.consume)+		extra <- EL.consume+		return (xs, extra))+	(\x xs -> let+		split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt+		in Right (split (== x) xs, []))+	(\c -> do+		xs <- E.joinI (ET.splitWhen (== c) $$ EL.consume)+		extra <- EL.consume+		return (xs, extra))+	(\c text -> let+		split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt+		chars = TL.unpack text+		in Right (map T.pack (split (== c) chars), []))+	(\x -> do+		xs <- E.joinI (EB.splitWhen (== x) $$ EL.consume)+		extra <- EL.consume+		return (xs, extra))+	(\x bytes -> let+		split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt+		words = BL.unpack bytes+		in Right (map B.pack (split (== x) words), []))  -- }}} @@ -735,7 +643,7 @@ 		result = runIdentity (E.run_ iter) 		expected = map (* 10) xs 		-		iter = (E.joinE (E.enumList 1 xs) (E.map (* 10))) $$ EL.consume+		iter = (E.joinE (E.enumList 1 xs) (EL.map (* 10))) $$ EL.consume  -- misc @@ -814,3 +722,6 @@  instance Arbitrary B.ByteString where 	arbitrary = genUnicode++instance Eq Exc.ErrorCall where+	(Exc.ErrorCall s1) == (Exc.ErrorCall s2) = s1 == s2
tests/enumerator-tests.cabal view
@@ -5,6 +5,7 @@  executable enumerator_tests   main-is: Properties.hs+  ghc-options: -Wall -O2    build-depends:       base > 3 && < 5@@ -12,6 +13,21 @@     , bytestring     , text     , enumerator+    , split     , QuickCheck == 2.4.*     , test-framework >= 0.2 && < 0.4     , test-framework-quickcheck2 == 0.2.9++executable enumerator_benchmarks+  main-is: Benchmarks.hs+  ghc-options: -Wall -O2++  build-depends:+      base > 3 && < 5+    , transformers+    , bytestring+    , text+    , enumerator+    , criterion+    , progression+    , deepseq