{-# LANGUAGE GADTs, FlexibleInstances, ScopedTypeVariables #-} ---------------------------- -- | IO event driverzo -- ---------------------------- module Control.Monad.Trans.Crtn.Driver where -- import Control.Monad.Error import Control.Monad.Reader import Control.Monad.Trans.Either import Data.Foldable -- import Control.Monad.Trans.Crtn import Control.Monad.Trans.Crtn.Event import Control.Monad.Trans.Crtn.Logger import Control.Monad.Trans.Crtn.Object import Control.Monad.Trans.Crtn.World -- -- | signature of IO event driver data DrvOp e i o where Dispatch :: DrvOp e e (Maybe (ActionOrder e)) -- | driver type Driver e m = SObjT (DrvOp e) m -- | driver client type DrvClient e m r = CObjT (DrvOp e) m r -- | dispatch :: (Monad m) => e -> DrvClient e m (Maybe (ActionOrder e)) dispatch ev = do Res Dispatch r <- request (Arg Dispatch ev) return r -- | basic driver driver :: forall m e. (Monad m, MonadLog m, MonadIO m) => LogServer (SObjBT (DrvOp e) m) () -> SObjT (WorldOp e (SObjBT (DrvOp e) m)) (SObjBT (DrvOp e) m) () -> Driver e m () driver logger world = ReaderT (driverW logger world) where driverW :: LogServer (SObjBT (DrvOp e) m) () -> SObjT (WorldOp e (SObjBT (DrvOp e) m)) (SObjBT (DrvOp e) m) () -> Arg (DrvOp e) -> SObjBT (DrvOp e) m () driverW logobj worldobj (Arg Dispatch ev) = do (logobj',worldobj') <- multiDispatchTillEnd (logobj,worldobj) [Right ev] req <- request (Res Dispatch Nothing) driverW logobj' worldobj' req -- | single event dispatch singleDispatch :: (Monad m) => Either (ActionOrder e) e -> ( LogServer (SObjBT (DrvOp e) m) () , World e (SObjBT (DrvOp e) m) () , [EvOrAct e]) -> SObjBT (DrvOp e) m ( LogServer (SObjBT (DrvOp e) m) () , World e (SObjBT (DrvOp e) m) () , [EvOrAct e]) singleDispatch (Right ev) (logobj,worldobj,evacc) = do -- Right (logobj',worldobj',events) <- r <- runEitherT $ do (worldobj1,_) <- EitherT (worldobj <==| giveEvent ev) (worldobj2,logobj1) <- EitherT (worldobj1 <==| flushLog logobj) (worldobj3,events) <- EitherT (worldobj2 <==| flushQueue) return (logobj1,worldobj3,events) case r of Left _ -> -- resuming original (this must be refined. resume point must be defined ) return (logobj,worldobj,evacc) Right (logobj',worldobj',events) -> return (logobj',worldobj',evacc++events) singleDispatch (Left act) (logobj,worldobj,evacc) = do Arg Dispatch ev <- request (Res Dispatch (Just act)) return (logobj,worldobj,evacc++[Right ev]) -- | a single feedback step of multiple event dispatch multiDispatch :: (Monad m) => ( LogServer (SObjBT (DrvOp e) m) () , World e (SObjBT (DrvOp e) m) ()) -> [EvOrAct e] -> SObjBT (DrvOp e) m ( LogServer (SObjBT (DrvOp e) m) () , World e (SObjBT (DrvOp e) m) () , [EvOrAct e] ) multiDispatch (logobj,worldobj) events = do foldrM singleDispatch (logobj,worldobj,[]) events -- | full multiple event dispatch with feedback multiDispatchTillEnd :: (Monad m) => ( LogServer (SObjBT (DrvOp e) m) () , World e (SObjBT (DrvOp e) m) ()) -> [EvOrAct e] -> SObjBT (DrvOp e) m (LogServer (SObjBT (DrvOp e) m) () , World e (SObjBT (DrvOp e) m) ()) multiDispatchTillEnd (logobj,worldobj) events = go (logobj,worldobj,events) where go (l,w,evs) = do (l',w',evs') <- multiDispatch (l,w) evs if (not.null) evs' then go (l',w',evs') else return (l',w') -- | convenience routine for driver fire :: (Monad m, MonadLog m) => e -> EStT (Driver e m ()) m (Maybe (ActionOrder e)) fire = query . dispatch