enumerator-0.4.5: src/binary.anansi
\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
: