module Data.Iteratee.Base (
Stream (..)
,StreamStatus (..)
,module Data.Iteratee.Exception
,Iteratee (..)
,run
,tryRun
,mapIteratee
,ilift
,idone
,icont
,liftI
,idoneM
,icontM
,setEOF
,module Data.NullPoint
,module Data.Nullable
,module Data.Iteratee.Base.LooseMap
)
where
import Prelude hiding (null, catch)
import Data.Iteratee.Base.LooseMap
import Data.Iteratee.Exception
import Data.Nullable
import Data.NullPoint
import Data.Monoid
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.CatchIO (MonadCatchIO (..), Exception (..),
catch, block, toException, fromException)
import Control.Applicative hiding (empty)
import Control.Exception (SomeException)
import qualified Control.Exception as E
import Data.Data
data Stream c =
EOF (Maybe SomeException)
| Chunk c
deriving (Show, Typeable)
instance (Eq c) => Eq (Stream c) where
(Chunk c1) == (Chunk c2) = c1 == c2
(EOF Nothing) == (EOF Nothing) = True
(EOF (Just e1)) == (EOF (Just e2)) = typeOf e1 == typeOf e2
_ == _ = False
instance Monoid c => Monoid (Stream c) where
mempty = Chunk mempty
mappend (EOF mErr) _ = EOF mErr
mappend _ (EOF mErr) = EOF mErr
mappend (Chunk s1) (Chunk s2) = Chunk (s1 `mappend` s2)
instance Functor Stream where
fmap f (Chunk xs) = Chunk $ f xs
fmap _ (EOF mErr) = EOF mErr
data StreamStatus =
DataRemaining
| EofNoError
| EofError SomeException
deriving (Show, Typeable)
setEOF :: Stream c -> SomeException
setEOF (EOF (Just e)) = e
setEOF _ = toException EofException
newtype Iteratee s m a = Iteratee{ runIter :: forall r.
(a -> Stream s -> m r) ->
((Stream s -> Iteratee s m a) -> Maybe SomeException -> m r) ->
m r}
idone :: Monad m => a -> Stream s -> Iteratee s m a
idone a s = Iteratee $ \onDone _ -> onDone a s
icont :: (Stream s -> Iteratee s m a) -> Maybe SomeException -> Iteratee s m a
icont k e = Iteratee $ \_ onCont -> onCont k e
liftI :: Monad m => (Stream s -> Iteratee s m a) -> Iteratee s m a
liftI k = Iteratee $ \_ onCont -> onCont k Nothing
idoneM :: Monad m => a -> Stream s -> m (Iteratee s m a)
idoneM x str = return $ Iteratee $ \onDone _ -> onDone x str
icontM
:: Monad m =>
(Stream s -> Iteratee s m a)
-> Maybe SomeException
-> m (Iteratee s m a)
icontM k e = return $ Iteratee $ \_ onCont -> onCont k e
instance (Functor m, Monad m) => Functor (Iteratee s m) where
fmap f m = Iteratee $ \onDone onCont ->
let od = onDone . f
oc = onCont . (fmap f .)
in runIter m od oc
instance (Functor m, Monad m, Nullable s) => Applicative (Iteratee s m) where
pure x = idone x (Chunk empty)
m <*> a = m >>= flip fmap a
instance (Monad m, Nullable s) => Monad (Iteratee s m) where
return x = Iteratee $ \onDone _ -> onDone x (Chunk empty)
(>>=) = bindIteratee
bindIteratee :: (Monad m, Nullable s)
=> Iteratee s m a
-> (a -> Iteratee s m b)
-> Iteratee s m b
bindIteratee = self
where
self m f = Iteratee $ \onDone onCont ->
let m_done a (Chunk s)
| nullC s = runIter (f a) onDone onCont
m_done a stream = runIter (f a) (const . flip onDone stream) f_cont
where f_cont k Nothing = runIter (k stream) onDone onCont
f_cont k e = onCont k e
in runIter m m_done (onCont . (flip self f .))
instance NullPoint s => MonadTrans (Iteratee s) where
lift m = Iteratee $ \onDone _ -> m >>= flip onDone (Chunk empty)
instance (MonadIO m, Nullable s, NullPoint s) => MonadIO (Iteratee s m) where
liftIO = lift . liftIO
instance (MonadCatchIO m, Nullable s, NullPoint s) =>
MonadCatchIO (Iteratee s m) where
m `catch` f = Iteratee $ \od oc -> runIter m od oc `catch` (\e -> runIter (f e) od oc)
block = ilift block
unblock = ilift unblock
run :: Monad m => Iteratee s m a -> m a
run iter = runIter iter onDone onCont
where
onDone x _ = return x
onCont k Nothing = runIter (k (EOF Nothing)) onDone onCont'
onCont _ (Just e) = E.throw e
onCont' _ Nothing = E.throw EofException
onCont' _ (Just e) = E.throw e
tryRun :: (Exception e, Monad m) => Iteratee s m a -> m (Either e a)
tryRun iter = runIter iter onDone onCont
where
onDone x _ = return $ Right x
onCont k Nothing = runIter (k (EOF Nothing)) onDone onCont'
onCont _ (Just e) = return $ maybeExc e
onCont' _ Nothing = return $ maybeExc (toException EofException)
onCont' _ (Just e) = return $ maybeExc e
maybeExc e = maybe (Left (E.throw e)) Left (fromException e)
mapIteratee :: (NullPoint s, Monad n, Monad m) =>
(m a -> n b)
-> Iteratee s m a
-> Iteratee s n b
mapIteratee f = lift . f . run
ilift ::
(Monad m, Monad n)
=> (forall r. m r -> n r)
-> Iteratee s m a
-> Iteratee s n a
ilift f i = Iteratee $ \od oc ->
let onDone a str = return $ Left (a,str)
onCont k mErr = return $ Right (ilift f . k, mErr)
in f (runIter i onDone onCont) >>= either (uncurry od) (uncurry oc)