module Data.Enumerator.IO
( enumHandle
, enumFile
, iterFile
, iterHandle
) where
import Data.Enumerator
import Control.Monad.IO.Class (liftIO)
import qualified Control.Exception as E
import qualified Data.ByteString as B
import qualified Foreign as F
import qualified System.IO as IO
enumHandle :: Integer
-> IO.Handle
-> Enumerator E.SomeException B.ByteString IO b
enumHandle bufferSize h = Iteratee . F.allocaBytes size' . loop where
size' = fromInteger bufferSize
loop (Continue k) = read' k
loop step = const $ return step
read' k p = do
eitherN <- E.try $ IO.hGetBuf h p size'
case eitherN of
Left err -> return $ Error err
Right 0 -> return $ Continue k
Right n -> do
bytes <- B.packCStringLen (p, n)
step <- runIteratee (k (Chunks [bytes]))
loop step p
enumFile :: FilePath -> Enumerator E.SomeException B.ByteString IO b
enumFile path s = Iteratee $ do
eitherH <- E.try $ IO.openBinaryFile path IO.ReadMode
case eitherH of
Left err -> return $ Error err
Right h -> E.finally
(runIteratee (enumHandle 4096 h s))
(IO.hClose h)
iterHandle :: IO.Handle -> Iteratee E.SomeException B.ByteString IO ()
iterHandle h = continue step where
step EOF = yield () EOF
step (Chunks bytes) = do
eitherErr <- liftIO . E.try $ mapM_ (B.hPut h) bytes
case eitherErr of
Left err -> throwError err
_ -> continue step
iterFile :: FilePath -> Iteratee E.SomeException B.ByteString IO ()
iterFile path = Iteratee $ do
eitherH <- E.try $ IO.openBinaryFile path IO.WriteMode
case eitherH of
Left err -> return $ Error err
Right h -> E.finally
(runIteratee (iterHandle h))
(IO.hClose h)