iteratee 0.3.5 → 0.3.6
raw patch · 8 files changed
+148/−10 lines, 8 filesdep −haskell98dep ~test-frameworkPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies removed: haskell98
Dependency ranges changed: test-framework
API changes (from Hackage documentation)
- Data.Iteratee.Base: instance (Eq (c el)) => Eq (StreamG c el)
- Data.Iteratee.Base: instance (Functor c) => Functor (StreamG c)
- Data.Iteratee.Base: instance (Monad m) => Monad (IterateeG s el m)
- Data.Iteratee.Base: instance (MonadIO m) => MonadIO (IterateeG s el m)
- Data.Iteratee.Base: instance (Monoid (c el)) => Monoid (StreamG c el)
- Data.Iteratee.Base: instance (Show (c el)) => Show (StreamG c el)
+ Data.Iteratee.Base: convStateStream :: MonadIO m => (t -> s el -> IterateeG s el m (Maybe (t, s el, s' el'))) -> t -> s el -> EnumeratorN s el s' el' m b
+ Data.Iteratee.Base: instance Eq (c el) => Eq (StreamG c el)
+ Data.Iteratee.Base: instance Functor c => Functor (StreamG c)
+ Data.Iteratee.Base: instance Monad m => Monad (IterateeG s el m)
+ Data.Iteratee.Base: instance MonadIO m => MonadIO (IterateeG s el m)
+ Data.Iteratee.Base: instance Monoid (c el) => Monoid (StreamG c el)
+ Data.Iteratee.Base: instance Show (c el) => Show (StreamG c el)
+ Data.Iteratee.Base: last :: (StreamChunk s el, Monad m) => IterateeG s el m el
+ Data.Iteratee.Base: mapM_ :: (ListLike (s el) el, MonadIO m) => (el -> m ()) -> IterateeG s el m ()
+ Data.Iteratee.IO.Fd: enumFdFollow :: ReadableChunk s el => Fd -> EnumeratorGM s el IO a
+ Data.Iteratee.IO.Fd: fileDriverFollowFd :: ReadableChunk s el => IterateeG s el IO a -> (a -> IterateeG s el IO b) -> FilePath -> IO b
+ Data.Iteratee.IO.Interact: ioIter :: (StreamChunk s el, MonadIO m) => (a -> IO (Either b (IterateeG s el m a))) -> a -> IterateeG s el m b
- Data.Iteratee.Base: convStream :: (Monad m) => IterateeG s el m (Maybe (s' el')) -> EnumeratorN s el s' el' m a
+ Data.Iteratee.Base: convStream :: Monad m => IterateeG s el m (Maybe (s' el')) -> EnumeratorN s el s' el' m a
- Data.Iteratee.Base: enumEof :: (Monad m) => EnumeratorGM s el m a
+ Data.Iteratee.Base: enumEof :: Monad m => EnumeratorGM s el m a
- Data.Iteratee.Base: identity :: (Monad m) => IterateeG s el m ()
+ Data.Iteratee.Base: identity :: Monad m => IterateeG s el m ()
- Data.Iteratee.Base: joinIM :: (Monad m) => m (IterateeG s el m a) -> IterateeG s el m a
+ Data.Iteratee.Base: joinIM :: Monad m => m (IterateeG s el m a) -> IterateeG s el m a
- Data.Iteratee.Base: seek :: (Monad m) => FileOffset -> IterateeG s el m ()
+ Data.Iteratee.Base: seek :: Monad m => FileOffset -> IterateeG s el m ()
- Data.Iteratee.Base: skipToEof :: (Monad m) => IterateeG s el m ()
+ Data.Iteratee.Base: skipToEof :: Monad m => IterateeG s el m ()
- Data.Iteratee.Base: throwErr :: (Monad m) => ErrMsg -> IterateeG s el m a
+ Data.Iteratee.Base: throwErr :: Monad m => ErrMsg -> IterateeG s el m a
- Data.Iteratee.Base.LooseMap: looseMap :: (LooseMap c el el') => (el -> el') -> c el -> c el'
+ Data.Iteratee.Base.LooseMap: looseMap :: LooseMap c el el' => (el -> el') -> c el -> c el'
- Data.Iteratee.Base.StreamChunk: class (ListLike (c el) el) => StreamChunk c el
+ Data.Iteratee.Base.StreamChunk: class ListLike (c el) el => StreamChunk c el
- Data.Iteratee.Base.StreamChunk: cons :: (StreamChunk c el) => el -> c el -> c el
+ Data.Iteratee.Base.StreamChunk: cons :: StreamChunk c el => el -> c el -> c el
- Data.Iteratee.Base.StreamChunk: dropWhile :: (StreamChunk c el) => (el -> Bool) -> c el -> c el
+ Data.Iteratee.Base.StreamChunk: dropWhile :: StreamChunk c el => (el -> Bool) -> c el -> c el
- Data.Iteratee.Base.StreamChunk: findIndex :: (StreamChunk c el) => (el -> Bool) -> c el -> Maybe Int
+ Data.Iteratee.Base.StreamChunk: findIndex :: StreamChunk c el => (el -> Bool) -> c el -> Maybe Int
- Data.Iteratee.Base.StreamChunk: fromList :: (StreamChunk c el) => [el] -> c el
+ Data.Iteratee.Base.StreamChunk: fromList :: StreamChunk c el => [el] -> c el
- Data.Iteratee.Base.StreamChunk: head :: (StreamChunk c el) => c el -> el
+ Data.Iteratee.Base.StreamChunk: head :: StreamChunk c el => c el -> el
- Data.Iteratee.Base.StreamChunk: length :: (StreamChunk c el) => c el -> Int
+ Data.Iteratee.Base.StreamChunk: length :: StreamChunk c el => c el -> Int
- Data.Iteratee.Base.StreamChunk: null :: (StreamChunk c el) => c el -> Bool
+ Data.Iteratee.Base.StreamChunk: null :: StreamChunk c el => c el -> Bool
- Data.Iteratee.Base.StreamChunk: readFromPtr :: (ReadableChunk s el) => Ptr (el) -> Int -> IO (s el)
+ Data.Iteratee.Base.StreamChunk: readFromPtr :: ReadableChunk s el => Ptr (el) -> Int -> IO (s el)
- Data.Iteratee.Base.StreamChunk: splitAt :: (StreamChunk c el) => Int -> c el -> (c el, c el)
+ Data.Iteratee.Base.StreamChunk: splitAt :: StreamChunk c el => Int -> c el -> (c el, c el)
- Data.Iteratee.Base.StreamChunk: tail :: (StreamChunk c el) => c el -> c el
+ Data.Iteratee.Base.StreamChunk: tail :: StreamChunk c el => c el -> c el
- Data.Iteratee.Base.StreamChunk: toList :: (StreamChunk c el) => c el -> [el]
+ Data.Iteratee.Base.StreamChunk: toList :: StreamChunk c el => c el -> [el]
- Data.Iteratee.Char: line :: (Monad m) => IterateeG [] Char m (Either Line Line)
+ Data.Iteratee.Char: line :: Monad m => IterateeG [] Char m (Either Line Line)
- Data.Iteratee.Char: readLines :: (Monad m) => IterateeG [] Char m (Either [Line] [Line])
+ Data.Iteratee.Char: readLines :: Monad m => IterateeG [] Char m (Either [Line] [Line])
Files
- CONTRIBUTORS +2/−0
- iteratee.cabal +4/−4
- src/Data/Iteratee/Base.hs +61/−3
- src/Data/Iteratee/Char.hs +1/−1
- src/Data/Iteratee/IO/Fd.hs +47/−0
- src/Data/Iteratee/IO/Interact.hs +31/−0
- tests/QCUtils.hs +1/−1
- tests/testIteratee.hs +1/−1
CONTRIBUTORS view
@@ -1,9 +1,11 @@ Thanks to the following individuals for contributing to this project. +Brian Buecking Oleg Kiselyov Brian Lewis John Lato Echo Nolan+Conrad Parker Paulo Tanimoto Magnus Therning Johan Tibell
iteratee.cabal view
@@ -1,5 +1,5 @@ name: iteratee-version: 0.3.5+version: 0.3.6 synopsis: Iteratee-based I/O description: The IterateeGM monad provides strict, safe, and functional I/O. In addition@@ -10,7 +10,7 @@ license: BSD3 license-file: LICENSE homepage: http://inmachina.net/~jwlato/haskell/iteratee-tested-with: GHC == 6.10.4+tested-with: GHC == 6.12.1 stability: experimental cabal-version: >= 1.6@@ -62,7 +62,6 @@ bytestring >= 0.9 && < 0.10, containers >= 0.2 && < 0.4, extensible-exceptions >= 0.1 && < 0.2,- haskell98 >= 1 && < 2, transformers >= 0.2.0.0 && < 0.3 exposed-modules:@@ -74,6 +73,7 @@ Data.Iteratee.Char Data.Iteratee.IO Data.Iteratee.IO.Handle+ Data.Iteratee.IO.Interact Data.Iteratee.WrappedByteString if flag(includeCodecs)@@ -101,7 +101,7 @@ if flag(buildTests) build-depends: QuickCheck >= 2 && < 3,- test-framework >= 0.2 && < 0.3,+ test-framework >= 0.3 && < 0.4, test-framework-quickcheck2 >= 0.2 && < 0.3 else executable: False
src/Data/Iteratee/Base.hs view
@@ -35,6 +35,7 @@ head, heads, peek,+ last, skipToEof, length, -- ** Nested iteratee combinators@@ -44,6 +45,7 @@ rigidMapStream, looseMapStream, convStream,+ convStateStream, filter, -- ** Folds foldl,@@ -52,6 +54,8 @@ -- ** Special Folds sum, product,+ -- ** Monadic variants of iteratees+ mapM_, -- * Enumerators -- ** Basic enumerators enumEof,@@ -69,7 +73,7 @@ ) where -import Prelude hiding (head, drop, dropWhile, take, break, foldl, foldl1, length, filter, sum, product)+import Prelude hiding (head, last, drop, dropWhile, take, break, foldl, foldl1, length, filter, sum, product, mapM_) import qualified Prelude as P import qualified Data.Iteratee.Base.StreamChunk as SC@@ -77,7 +81,7 @@ import qualified Data.ListLike.FoldableLL as FLL import Data.Iteratee.Base.LooseMap import Data.Iteratee.IO.Base-import Control.Monad+import Control.Monad hiding (mapM_) import Control.Applicative import Control.Monad.Trans.Class import Control.Monad.IO.Class@@ -86,7 +90,7 @@ -- |A stream is a (continuing) sequence of elements bundled in Chunks.--- The first two variants indicate termination of the stream.+-- The first variant indicates termination of the stream. -- Chunk a gives the currently available part of the stream. -- The stream is not terminated yet. -- The case (null Chunk) signifies a stream with no currently available@@ -397,6 +401,13 @@ | otherwise = return $ Done (Just $ SC.head vec) s step stream = return $ Done Nothing stream +-- | Attempt to skip to the last element of the stream and return it+last :: (SC.StreamChunk s el, Monad m) => IterateeG s el m el+last = do x <- head+ next <- peek+ case next of+ Just _ -> last+ Nothing -> return x -- |Skip the rest of the stream skipToEof :: (Monad m) => IterateeG s el m ()@@ -573,6 +584,38 @@ {-# INLINE convStream #-} +-- |Convert one stream into another while continually updating an internal+-- state. The state of type 't' is updated by the supplied function, which+-- maybe returns a tuple consisting of the updated state, the remaining+-- unprocessed portion of the input stream, and the output stream.+-- In order to produce elements of the output stream from data that spans+-- stream chunks, the remaining portion of the input stream is passed to the+-- following iteration of the supplied function, which should prepend it to+-- its input stream chunk.+-- The supplied function should return Nothing on EOF.+convStateStream :: MonadIO m =>+ (t -> s el -> IterateeG s el m (Maybe (t, s el, s' el'))) ->+ t -> s el ->+ EnumeratorN s el s' el' m b+convStateStream outer state pre inner = outer state pre >>= convStateCheck outer inner++{-# INLINE convStateStream #-}++convStateCheck :: (MonadIO m) =>+ (t -> s el -> IterateeG s el m (Maybe (t, s el, s' el')))+ -> IterateeG s' el' m b+ -> Maybe (t, s el, s' el')+ -> IterateeG s el m (IterateeG s' el' m b)+convStateCheck outer inner (Just (state', remainder, result)) =+ lift (runIter inner (Chunk result)) >>= docase+ where+ docase (Done a _) = return . return $ a+ docase (Cont k Nothing) = convStateStream outer state' remainder k+ docase (Cont _ (Just e)) = return $ throwErr e+convStateCheck _ iter (Nothing) = return iter++{-# INLINE convStateCheck #-}+ -- |Creates an enumerator with only elements from the stream that -- satisfy the predicate function. filter :: (LL.ListLike (s el) el, Monad m) =>@@ -751,3 +794,18 @@ -- |A variant of join for Iteratees in a monad. joinIM :: (Monad m) => m (IterateeG s el m a) -> IterateeG s el m a joinIM m = IterateeG (\str -> m >>= flip runIter str)++-- ------------------------------------------------------------------------+-- Monadic variants of iteratees++-- | Map a monadic function over all elements of a stream, and ignore the result+mapM_ :: (LL.ListLike (s el) el, MonadIO m)+ => (el -> m ()) -> IterateeG s el m ()+mapM_ f = IterateeG step+ where+ step (Chunk xs) | LL.null xs = return $ Cont (IterateeG step) Nothing+ step (Chunk xs) = do LL.mapM_ f xs+ return $ Cont (IterateeG step) Nothing+ step stream = return $ Done () stream++{-# INLINE mapM_ #-}
src/Data/Iteratee/Char.hs view
@@ -31,7 +31,7 @@ where import qualified Data.Iteratee.Base as Iter-import Data.Iteratee.Base hiding (break)+import Data.Iteratee.Base hiding (break, last) import Data.Char import Control.Monad.IO.Class import qualified Data.ListLike as LL
src/Data/Iteratee/IO/Fd.hs view
@@ -9,9 +9,11 @@ -- * File enumerators -- ** FileDescriptor based enumerators enumFd+ ,enumFdFollow ,enumFdRandom -- * Iteratee drivers ,fileDriverFd+ ,fileDriverFollowFd ,fileDriverRandomFd #endif )@@ -65,6 +67,34 @@ check p (Cont i Nothing) = loop i p check _p (Cont _ (Just e)) = return $ throwErr e +-- |The enumerator of a POSIX File Descriptor: a variation of enumFd+-- that follows the tail of growing input.+enumFdFollow :: forall s el a.(ReadableChunk s el) =>+ Fd ->+ EnumeratorGM s el IO a+enumFdFollow fd iter' =+ liftIO (mallocForeignPtrBytes (fromIntegral buffer_size)) >>= loop iter'+ where+ buffer_size = fromIntegral $ 4096 - mod 4096 (sizeOf (undefined :: el))+ loop iter fp = do+ s <- readFollow iter fp+ checkres fp iter s+ readFollow iter fp = do+ liftIO . withForeignPtr fp $ \p -> do+ liftIO $ GHC.Conc.threadWaitRead fd+ n <- myfdRead fd (castPtr p) buffer_size+ case n of+ Left _errno -> return $ Left "IO error"+ Right 0 -> do liftIO $ threadDelay (250 * 1000)+ readFollow iter fp+ Right n' -> liftM (Right . Just) $ readFromPtr p (fromIntegral n')+ checkres fp iter = either (flip enumErr iter)+ (maybe (return iter)+ (check fp <=< runIter iter . Chunk))+ check _p (Done x _) = return . return $ x+ check p (Cont i Nothing) = loop i p+ check _p (Cont _ (Just e)) = return $ throwErr e+ -- |The enumerator of a POSIX File Descriptor: a variation of enumFd that -- supports RandomIO (seek requests) enumFdRandom :: forall s el m a.(ReadableChunk s el, MonadIO m) =>@@ -127,6 +157,23 @@ fileDriverFd iter filepath = do fd <- liftIO $ openFd filepath ReadOnly Nothing defaultFileFlags result <- enumFd fd iter >>= run+ liftIO $ closeFd fd+ return result++-- |Process a file using the given IterateeGM. This function wraps+-- enumFdFollow as a convenience.+-- The first iteratee is used to scan through to the end of the file, using+-- enumFd. The second iteratee is used from then onwards on the growing tail+-- of the file, using enumFdFollow.+fileDriverFollowFd :: (ReadableChunk s el) =>+ IterateeG s el IO a ->+ (a -> IterateeG s el IO b) ->+ FilePath ->+ IO b+fileDriverFollowFd scanIter followIter filepath = do+ fd <- liftIO $ openFd filepath ReadOnly Nothing defaultFileFlags+ state <- enumFd fd scanIter >>= run+ result <- enumFdFollow fd (followIter state) >>= run liftIO $ closeFd fd return result
+ src/Data/Iteratee/IO/Interact.hs view
@@ -0,0 +1,31 @@+module Data.Iteratee.IO.Interact (+ ioIter+) where++import Control.Monad.IO.Class (MonadIO, liftIO)++import Data.Iteratee+import qualified Data.Iteratee.Base.StreamChunk as SC++-- | Use an IO function to choose what iteratee to run.+-- Typically this function handles user interaction and+-- returns with a simple iteratee such as 'head' or 'seek'.+-- +-- The IO function takes a value of type 'a' as input, and+-- should return 'Right a' to continue, or 'Left b'+-- to terminate. Upon termination, ioIter will return 'Done b'.+--+-- The second argument to 'ioIter' is used as the initial input+-- to the IO function, and on each successive iteration the+-- previously returned value is used as input. Put another way,+-- the value of type 'a' is used like a fold accumulator.+-- The value of type 'b' is typically some form of control code+-- that the application uses to signal the reason for termination.+ioIter :: (SC.StreamChunk s el, MonadIO m)+ => (a -> IO (Either b (IterateeG s el m a))) -> a -> IterateeG s el m b+ioIter f a = do i'e <- liftIO $ f a+ case i'e of+ Left e -> return e+ Right i -> do a' <- i+ ioIter f a'+
tests/QCUtils.hs view
@@ -9,7 +9,7 @@ import Data.Iteratee import qualified Data.Iteratee as I import Data.Iteratee.Base.StreamChunk (StreamChunk)-import Control.Monad.Identity+import Data.Functor.Identity -- Show instance instance (Show a, StreamChunk s el) => Show (IterateeG s el Identity a) where
tests/testIteratee.hs view
@@ -14,7 +14,7 @@ import qualified Data.Iteratee.Char as IC import qualified Data.Iteratee as Iter import qualified Data.Iteratee.Base.StreamChunk as SC-import Control.Monad.Identity+import Data.Functor.Identity import Data.Monoid import qualified Data.ListLike as LL