MissingH API ManualContentsIndex
MissingH.IO.BlockIO
Portability Haskell 2-pre
Stability provisional
Maintainer simons@cryp.to
Contents
I/O Buffer
BlockIO Monad
Primitives
Handler and I/O Driver
Handler Combinators
Lines
Error Handling
Internal Helper Functions
Description

All you need from this module is the runLoop function and the Handler type definition. It's no breath-takingly inventive concept, actually: runLoop will read blocks of Word8 from a Handle into a static buffer on the heap, and every time new input has arrived, it will call a handler with a Ptr into the buffer, so that the handler can do stuff with the data. Then, the handler returns either: I need more data before I can do anything (Nothing), or I have consumed n bytes, please flush them (Just (a,Int)).

Basically, runLoop drives the handler with the data read from the input stream until hIsEOF ensues. Everything else has to be done by the handler -- the BlockIO monad just does the I/O. But it does it fast.

Synopsis
data Buffer = Buf !Int !(Ptr Word8) !Int
withBuffer :: Int -> (Buffer -> IO a) -> IO a
flushBuffer :: Int -> Buffer -> IO Buffer
readBuffer :: Handle -> Buffer -> IO (Maybe Buffer)
data BIOState st = BIO !Handle !Buffer !st
type BlockIO st a = StateT (BIOState st) IO a
runBlockIO :: Handle -> Int -> BlockIO st a -> st -> IO (a, st)
slurp :: Timeout -> BlockIO st Bool
flush :: Int -> BlockIO st ()
type Handler st a = (Ptr Word8, Int) -> StateT st IO (Maybe (a, Int))
type LoopHandler st = Handler st ()
consume :: Timeout -> Handler st a -> BlockIO st (Maybe a)
loop :: (st -> Timeout) -> LoopHandler st -> BlockIO st ()
runLoopNB :: (st -> Timeout) -> Handle -> Int -> LoopHandler st -> st -> IO st
runLoop :: Handle -> Int -> LoopHandler st -> st -> IO st
type LineHandler st a = Handler (Int, st) [a]
handleLines :: (String -> StateT st IO a) -> LineHandler st a
isBufferOverflow :: IOError -> Bool
isTimeout :: IOError -> Bool
handleEOF :: IO a -> IO (Maybe a)
splitBy :: (a -> Bool) -> [a] -> ([[a]], [a])
I/O Buffer
data Buffer
Capacity, pointer into the heap, and length of contents; all sizes are in bytes, naturally.
Constructors
Buf !Int !(Ptr Word8) !Int
Instances
Show Buffer
withBuffer :: Int -> (Buffer -> IO a) -> IO a
Initialize a Buffer of capacity n > 0 and run the given IO computation with it. The buffer will be destroyed when the computation returns.
flushBuffer :: Int -> Buffer -> IO Buffer
Drop the first 0 <= n <= size octets from the buffer.
readBuffer :: Handle -> Buffer -> IO (Maybe Buffer)
If there is space in the Buffer, read and append more octets, then return the modified buffer. In case of EOF, Nothing is returned. If the buffer is full already, raise an IOError. Use the isBufferOverflow predicate to test an exception you caught for this condition.
BlockIO Monad
data BIOState st
The internal state of a block-I/O execution thread.
Constructors
BIO !Handle !Buffer !st
Instances
Show st => Show (BIOState st)
type BlockIO st a = StateT (BIOState st) IO a
A block-I/O execution thread.
runBlockIO
:: Handle
-> Intbuffer capacity
-> BlockIO st acomputation to run
-> stinitial state
-> IO (a, st)
Run a BlockIO computation in the IO monad. The contents of the I/O buffer is lost when runBlockIO returns. If you need more control, use withBuffer to construct your own BIOState and run the monad with runStateT.
Primitives
slurp :: Timeout -> BlockIO st Bool
Read some more input data into the I/O buffer. Returns True if there is more, False when EOF occurs. May raise an isBufferOverflow or isTimeout exception.
flush :: Int -> BlockIO st ()
Drop the first 0 <= n <= size octets from the I/O buffer.
Handler and I/O Driver
type Handler st a = (Ptr Word8, Int) -> StateT st IO (Maybe (a, Int))
A handler is a stateful IO computation which the I/O driver consume calls every time new input has arrived. If the buffer contains enough data to do something useful with it, it should do it, and signal how many octets have been consumed with the returned Int. These will be flushed from the beginning of buffer when the handler is called the next time. The handler itself should not modify the buffer.
type LoopHandler st = Handler st ()
A handler which can be run in an I/O loop without ever needing to return values to the main program, for instance with runLoop.
consume :: Timeout -> Handler st a -> BlockIO st (Maybe a)
Use the given handler to consume a token from the I/O buffer. Returns Nothing in case of EOF. May raise an isBufferOverflow or isTimeout exception.
loop :: (st -> Timeout) -> LoopHandler st -> BlockIO st ()
Repeated consume until EOF. The handler may only return () to prevent space leaks. Use st instead. :-)
runLoopNB
:: (st -> Timeout)user state provides timeout
-> Handleread from here
-> Intbuffer size to allocate
-> LoopHandler stcall-back to handle the data
-> stinitial handler state
-> IO stthe state at time of EOF
Iterate a handle until EOF and use the given Handler to do stuff with the data we've read. The (st -> Timeout) function will be used to to determine the read timeout from the current handler state.
runLoop :: Handle -> Int -> LoopHandler st -> st -> IO st
runLoop = runLoopNB (const (-1))
Handler Combinators
Lines
type LineHandler st a = Handler (Int, st) [a]
Wrap an integer signifying the front gap of the buffer into the user state. Initialize it to 0.
handleLines :: (String -> StateT st IO a) -> LineHandler st a
Split the input buffer into lines using '\n' as end-of-line marker. The '\n' is not stripped. Then call the given IO computation line-by-line until all lines have been consumed.
Error Handling
isBufferOverflow :: IOError -> Bool
Predicate to determine whether a caught IOError was caused by a buffer overflow.
isTimeout :: IOError -> Bool
Determine whether a given exception is a read timeout error raised by the BlockIO code.
Internal Helper Functions
handleEOF :: IO a -> IO (Maybe a)
Return Nothing if the given computation throws an isEOFError exception. Used by readBuffer.
splitBy :: (a -> Bool) -> [a] -> ([[a]], [a])
Produced by Haddock version 0.6