iteratee 0.8.0.3 → 0.8.1.0
raw patch · 9 files changed
+126/−15 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Iteratee.Char: printLinesUnterminated :: (Eq el, Nullable s, StringLike s, ListLike s el) => Iteratee s IO ()
+ Data.Iteratee.Iteratee: mapChunksM_ :: (Monad m, Nullable s) => (s -> m b) -> Iteratee s m ()
+ Data.Iteratee.ListLike: breakE :: (Monad m, ListLike s el, NullPoint s) => (el -> Bool) -> Enumeratee s s m a
Files
- iteratee.cabal +4/−4
- src/Data/Iteratee/Base/ReadableChunk.hs +5/−0
- src/Data/Iteratee/Char.hs +32/−3
- src/Data/Iteratee/Iteratee.hs +19/−2
- src/Data/Iteratee/ListLike.hs +29/−5
- src/Data/NullPoint.hs +3/−0
- src/Data/Nullable.hs +4/−0
- tests/foo.hs +20/−0
- tests/testIteratee.hs +10/−1
iteratee.cabal view
@@ -1,5 +1,5 @@ name: iteratee-version: 0.8.0.3+version: 0.8.1.0 synopsis: Iteratee-based I/O description: The Iteratee monad provides strict, safe, and functional I/O. In addition@@ -9,8 +9,8 @@ maintainer: John W. Lato <jwlato@gmail.com> license: BSD3 license-file: LICENSE-homepage: http://inmachina.net/~jwlato/haskell/iteratee-tested-with: GHC == 6.12.3+homepage: http://www.tiresiaspress.us/haskell/iteratee+tested-with: GHC == 7.0.1, GHC == 6.12.3 stability: experimental cabal-version: >= 1.6@@ -111,4 +111,4 @@ source-repository head type: darcs- location: http://inmachina.net/~jwlato/haskell/iteratee+ location: http://www.tiresiaspress.us/haskell/iteratee
src/Data/Iteratee/Base/ReadableChunk.hs view
@@ -13,6 +13,7 @@ import Prelude hiding (head, tail, dropWhile, length, splitAt ) import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L import Data.Word import Control.Monad.IO.Class import Foreign.C@@ -45,3 +46,7 @@ instance ReadableChunk B.ByteString Word8 where readFromPtr buf l = liftIO $ B.packCStringLen (castPtr buf, l)++instance ReadableChunk L.ByteString Word8 where+ readFromPtr buf l = liftIO $+ return . L.fromChunks . (:[]) =<< readFromPtr buf l
src/Data/Iteratee/Char.hs view
@@ -1,10 +1,11 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-} -- | Utilities for Char-based iteratee processing. module Data.Iteratee.Char ( -- * Word and Line processors printLines+ ,printLinesUnterminated ,enumLines ,enumLinesBS ,enumWords@@ -26,14 +27,42 @@ -- |Print lines as they are received. This is the first `impure' iteratee -- with non-trivial actions during chunk processing+--+-- Only lines ending with a newline are printed,+-- data terminated with EOF is not printed. printLines :: Iteratee String IO () printLines = lines'- where+ where lines' = I.break (`elem` "\r\n") >>= \l -> terminators >>= check l check _ 0 = return () check "" _ = return () check l _ = liftIO (putStrLn l) >> lines'- terminators = heads "\r\n" >>= \l -> if l == 0 then heads "\n" else return l++-- |Print lines as they are received.+--+-- All lines are printed, including a line with a terminating EOF.+-- If the final line is terminated by EOF without a newline,+-- no newline is printed.+-- this function should be used in preference to printLines when possible,+-- as it is more efficient with long lines.+printLinesUnterminated :: forall s el.+ (Eq el, Nullable s, LL.StringLike s, LL.ListLike s el)+ => Iteratee s IO ()+printLinesUnterminated = lines'+ where+ lines' = do+ joinI $ I.breakE (`LL.elem` t1) (I.mapChunksM_ (putStr . LL.toString))+ terminators >>= check+ check 0 = return ()+ check _ = liftIO (putStrLn "") >> lines'+ t1 :: s+ t1 = LL.fromString "\r\n"++terminators :: (Eq el, Nullable s, LL.StringLike s, LL.ListLike s el)+ => Iteratee s IO Int+terminators = do+ l <- heads (LL.fromString "\r\n")+ if l == 0 then heads (LL.fromString "\n") else return l -- |Convert the stream of characters to the stream of lines, and
src/Data/Iteratee/Iteratee.hs view
@@ -13,6 +13,8 @@ ,identity ,skipToEof ,isStreamFinished+ -- ** Chunkwise Iteratees+ ,mapChunksM_ -- ** Nested iteratee combinators ,convStream ,unfoldConvStream@@ -46,6 +48,7 @@ import Data.Iteratee.Base import Control.Exception+import Control.Monad.Trans.Class import Data.Maybe import Data.Typeable @@ -117,7 +120,21 @@ seek :: (Monad m, NullPoint s) => FileOffset -> Iteratee s m () seek o = throwRecoverableErr (toException $ SeekException o) (const identity) +-- | Map a monadic function over the chunks of the stream and ignore the+-- result. Useful for creating efficient monadic iteratee consumers, e.g.+--+-- logger = mapChunksM_ (liftIO . putStrLn)+--+-- these can be efficiently run in parallel with other iteratees via+-- enumPair.+mapChunksM_ :: (Monad m, Nullable s) => (s -> m b) -> Iteratee s m ()+mapChunksM_ f = liftI step+ where+ step (Chunk xs) = lift (f xs) >> liftI step+ step s@(EOF _) = idone () s+{-# INLINE mapChunksM_ #-} + -- --------------------------------------------------- -- The converters show a different way of composing two iteratees: -- `vertical' rather than `horizontal'@@ -146,7 +163,7 @@ -- general: it may take several elements of the outer stream to produce -- one element of the inner stream, or the other way around. -- The transformation from one stream to the other is specified as--- Iteratee s el s'.+-- Iteratee s m s'. convStream :: (Monad m, Nullable s) => Iteratee s m s'@@ -154,7 +171,7 @@ convStream fi = eneeCheckIfDone check where check k = isStreamFinished >>= maybe (step k) (idone (liftI k) . EOF . Just)- step k = fi >>= convStream fi . k . Chunk+ step k = fi >>= eneeCheckIfDone check . k . Chunk -- |The most general stream converter. Given a function to produce iteratee -- transformers and an initial state, convert the stream using iteratees
src/Data/Iteratee/ListLike.hs view
@@ -24,6 +24,7 @@ ,roll ,length -- ** Nested iteratee combinators+ ,breakE ,take ,takeUpTo ,mapStream@@ -112,6 +113,10 @@ -- If the stream is not terminated, the first character of the remaining stream -- satisfies the predicate. --+-- N.B. @breakE@ should be used in preference to @break@.+-- @break@ will retain all data until the predicate is met, which may+-- result in a space leak.+-- -- The analogue of @List.break@ break :: (Monad m, LL.ListLike s el) => (el -> Bool) -> Iteratee s m s@@ -166,7 +171,7 @@ where loop cnt xs | nullC xs = return cnt- | True = liftI (step cnt xs)+ | True = liftI (step cnt xs) step cnt str (Chunk xs) | nullC xs = liftI (step cnt str) step cnt str stream | nullC str = idone cnt stream step cnt str s@(Chunk xs) =@@ -248,8 +253,8 @@ length :: (Monad m, Num a, LL.ListLike s el) => Iteratee s m a length = liftI (step 0) where- step !i (Chunk xs) = liftI (step $ i + LL.length xs)- step !i stream = idone (fromIntegral i) stream+ step !i (Chunk xs) = liftI (step $! i + fromIntegral (LL.length xs))+ step !i stream = idone i stream {-# INLINE length #-} @@ -257,6 +262,25 @@ -- The converters show a different way of composing two iteratees: -- `vertical' rather than `horizontal' +-- |Takes an element predicate and an iteratee, running the iteratee+-- on all elements of the stream until the predicate is met.+--+-- the following rule relates @break@ to @breakE@+-- @break@ pred >> iter === @joinI@ (@breakE@ pred iter)+--+-- @breakE@ should be used in preference to @break@ whenever possible.+breakE :: (Monad m, LL.ListLike s el, NullPoint s) => (el -> Bool) -> Enumeratee s s m a+breakE cpred = eneeCheckIfDone (liftI . step)+ where+ step k (Chunk s)+ | LL.null s = liftI (step k)+ | otherwise = case LL.break cpred s of+ (str', tail')+ | LL.null tail' -> eneeCheckIfDone (liftI . step) . k $ Chunk str'+ | otherwise -> idone (k $ Chunk str') (Chunk tail')+ step k stream = idone (k stream) stream+{-# INLINE breakE #-}+ -- |Read n elements from a stream and apply the given iteratee to the -- stream of the read elements. Unless the stream is terminated early, we -- read exactly n elements, even if the iteratee has accepted fewer.@@ -577,8 +601,8 @@ -> Iteratee s m () mapM_ f = liftI step where- step (Chunk xs) | LL.null xs = mapM_ f- step (Chunk xs) = lift (LL.mapM_ f xs) >> mapM_ f+ step (Chunk xs) | LL.null xs = liftI step+ step (Chunk xs) = lift (LL.mapM_ f xs) >> liftI step step s@(EOF _) = idone () s {-# INLINE mapM_ #-}
src/Data/NullPoint.hs view
@@ -9,6 +9,7 @@ where import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L -- ---------------------------------------------- -- |NullPoint class. Containers that have a null representation, corresponding@@ -22,3 +23,5 @@ instance NullPoint B.ByteString where empty = B.empty +instance NullPoint L.ByteString where+ empty = L.empty
src/Data/Nullable.hs view
@@ -9,6 +9,7 @@ import Data.NullPoint import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L -- ----------------------------------------------@@ -22,3 +23,6 @@ instance Nullable B.ByteString where nullC = B.null++instance Nullable L.ByteString where+ nullC = L.null
+ tests/foo.hs view
@@ -0,0 +1,20 @@+import Data.ByteString (ByteString)+import Data.Iteratee as I+import Data.Iteratee.Char+import System++main = do+ args <- getArgs+ let fname = args !! 0+ let blockSize = read $ args !! 1++ fileDriver (leak blockSize) fname >>= print++leak :: Int -> Iteratee ByteString IO ()+leak blockSize = chunkedRead+ where+ consChunk :: Iteratee ByteString IO String+ consChunk = (joinI $ I.take blockSize I.length) >>= return . show++ chunkedRead :: Iteratee ByteString IO ()+ chunkedRead = joinI $ convStream consChunk printLinesUnterminated
tests/testIteratee.hs view
@@ -91,6 +91,13 @@ prop_break2 f xs = runner1 (enumPure1Chunk xs (Iter.break f >> stream2list)) == snd (break f xs) where types = xs :: [Int] +prop_breakE f xs = runner1 (enumPure1Chunk xs (joinI $ Iter.breakE f stream2stream)) == fst (break f xs)+ where types = xs :: [Int]++prop_breakE2 f xs = runner1 (enumPure1Chunk xs (joinI (Iter.breakE f stream2stream) >> stream2list)) == snd (break f xs)+ where types = xs :: [Int]++ prop_head xs = P.length xs > 0 ==> runner1 (enumPure1Chunk xs Iter.head) == head xs where types = xs :: [Int] @@ -260,7 +267,7 @@ ] ,testGroup "Simple Iteratees" [ testProperty "break" prop_break- ,testProperty "break remaineder" prop_break2+ ,testProperty "break remainder" prop_break2 ,testProperty "head" prop_head ,testProperty "head remainder" prop_head2 ,testProperty "heads" prop_heads@@ -289,6 +296,8 @@ testProperty "mapStream identity" prop_mapStream ,testProperty "mapStream identity 2" prop_mapStream2 ,testProperty "mapStream identity joinI" prop_mapjoin+ ,testProperty "breakE" prop_breakE+ ,testProperty "breakE remainder" prop_breakE2 ,testProperty "take" prop_take ,testProperty "take (finished iteratee)" prop_take2 ,testProperty "takeUpTo" prop_takeUpTo