-------------------------------------------------------------------- -- | -- Module : Data.MessagePack.Iteratee -- Copyright : (c) Hideyuki Tanaka, 2009-2010 -- License : BSD3 -- -- Maintainer: tanaka.hideyuki@gmail.com -- Stability : experimental -- Portability: portable -- -- MessagePack Deserializer interface to @Data.Iteratee@ -- -------------------------------------------------------------------- module Data.MessagePack.Iteratee( -- * Iteratee version of deserializer getI, -- * Non Blocking Enumerator enumHandleNonBlocking, -- * Convert Parser to Iteratee parserToIteratee, ) where import Control.Exception import Control.Monad.IO.Class import qualified Data.Attoparsec as A import qualified Data.ByteString as B import qualified Data.Iteratee as I import System.IO import Data.MessagePack.Unpack -- | Deserialize a value getI :: (Monad m, Unpackable a) => I.Iteratee B.ByteString m a getI = parserToIteratee get -- | Enumerator enumHandleNonBlocking :: MonadIO m => Int -> Handle -> I.Enumerator B.ByteString m a enumHandleNonBlocking bufSize h = I.enumFromCallback $ readSome bufSize h readSome :: MonadIO m => Int -> Handle -> m (Either SomeException (Bool, B.ByteString)) readSome bufSize h = liftIO $ do ebs <- try $ hGetSome bufSize h case ebs of Left exc -> return $ Left (exc :: SomeException) Right bs | B.null bs -> return $ Right (False, B.empty) Right bs -> return $ Right (True, bs) hGetSome :: Int -> Handle -> IO B.ByteString hGetSome bufSize h = do bs <- B.hGetNonBlocking h bufSize if B.null bs then do hd <- B.hGet h 1 if B.null hd then do return B.empty else do rest <- B.hGetNonBlocking h (bufSize - 1) return $ B.cons (B.head hd) rest else do return bs -- | Convert Parser to Iteratee parserToIteratee :: Monad m => A.Parser a -> I.Iteratee B.ByteString m a parserToIteratee p = I.icont (itr (A.parse p)) Nothing where itr pcont s = case s of I.EOF _ -> I.throwErr (I.setEOF s) I.Chunk bs -> case pcont bs of A.Fail _ _ msg -> I.throwErr (I.iterStrExc msg) A.Partial cont -> I.icont (itr cont) Nothing A.Done remain ret -> I.idone ret (I.Chunk remain)