{-# LANGUAGE DeriveDataTypeable #-}
module Data.Serialize.Get.Enumerator
    ( ParseError(..)
    , iterGet
    ) where

import Control.Exception
import Data.Monoid
import Data.Typeable

import Data.Serialize.Get
import Data.Enumerator
import Data.ByteString

data ParseError = ParseError String
                | EOFError
                deriving (Show, Typeable)

instance Exception ParseError

-- | Convert a 'Get' to an 'Iteratee'. A 'ParseError' is emitted on failure.
iterGet :: Monad m => Get a -> Iteratee ByteString m a
iterGet = continue . step . runGetPartial
    step p (Chunks xs) = loop p xs
    step p EOF = case p mempty of
        Done r _  -> yield r EOF
        Partial{} -> throwError EOFError
        Fail s    -> throwError (ParseError s)

    loop p [] = continue (step p)
    loop p (x:xs) = case p x of
        Done r bs -> yield r $ Chunks (bs:xs)
        Partial c -> loop c xs
        Fail s    -> throwError (ParseError s)