module Data.Machine.Concurrent.AsyncStep where
import Control.Concurrent.Async.Lifted (Async, async, wait)
import Control.Monad.Trans.Control (MonadBaseControl, StM)
import Data.Machine
type MachineStep m k o = Step k o (MachineT m k o)
type AsyncStep m k o = Async (StM m (MachineStep m k o))
awaitStep :: (a -> d) -> k' a -> d -> (d -> r) -> Step k' b r
awaitStep f sel ff k = Await (k . f) sel (k ff)
asyncRun :: MonadBaseControl IO m => MachineT m k o -> m (AsyncStep m k o)
asyncRun = async . runMachineT
stepAsync :: forall m k k' a' d b.
MonadBaseControl IO m
=> (forall c. k c -> k' c)
-> AsyncStep m k a'
-> (a' -> d)
-> d
-> d
-> (AsyncStep m k a' -> d -> MachineT m k' b)
-> MachineT m k' b
stepAsync sel src f def prev go = MachineT $ wait src >>= \u -> case u of
Stop -> go' stopped def
Yield a k -> go' k (f a)
Await g kg fg -> return $ awaitStep g (sel kg) fg (MachineT . flip go' prev)
where go' :: MachineT m k a' -> d -> m (MachineStep m k' b)
go' k d = asyncRun k >>= runMachineT . flip go d
asyncEncased :: MonadBaseControl IO m
=> (AsyncStep m k1 o1 -> MachineT m k o)
-> MachineT m k1 o1
-> MachineT m k o
asyncEncased f x = MachineT $ asyncRun x >>= runMachineT . f
asyncAwait :: MonadBaseControl IO m
=> (a -> MachineT m k o)
-> k' a
-> MachineT m k o
-> (AsyncStep m k o -> MachineT m k1 o1)
-> m (Step k' b (MachineT m k1 o1))
asyncAwait f sel ff = return . awaitStep f sel ff . asyncEncased