{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Reflex.Host.Headless where
import Control.Concurrent.Chan (newChan, readChan)
import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
import Control.Monad.Fix (MonadFix, fix)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Primitive (PrimMonad)
import Control.Monad.Ref (MonadRef, Ref, readRef)
import Data.Dependent.Sum (DSum (..), (==>))
import Data.Foldable (for_, asum)
import Data.Functor.Identity (Identity(..))
import Data.IORef (IORef, readIORef)
import Data.Maybe (catMaybes)
import Data.Traversable (for)
import Reflex
import Reflex.Host.Class
type MonadHeadlessApp t m =
( Reflex t
, Adjustable t m
, MonadCatch m
, MonadFix (Performable m)
, MonadFix m
, MonadHold t (Performable m)
, MonadHold t m
, MonadIO (HostFrame t)
, MonadIO (Performable m)
, MonadIO m
, MonadMask m
, MonadRef (HostFrame t)
, MonadSample t (Performable m)
, MonadSample t m
, MonadThrow m
, NotReady t m
, PerformEvent t m
, PostBuild t m
, PrimMonad (HostFrame t)
, Ref (HostFrame t) ~ IORef
, Ref m ~ IORef
, ReflexHost t
, TriggerEvent t m
)
runHeadlessApp
:: forall a
. (forall t m. MonadHeadlessApp t m => m (Event t a))
-> IO a
runHeadlessApp :: forall a.
(forall t (m :: * -> *). MonadHeadlessApp t m => m (Event t a))
-> IO a
runHeadlessApp forall t (m :: * -> *). MonadHeadlessApp t m => m (Event t a)
guest =
(forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO a)
-> IO a
forall r.
(forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO r)
-> IO r
withSpiderTimeline ((forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO a)
-> IO a)
-> (forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO a)
-> IO a
forall a b. (a -> b) -> a -> b
$ SpiderHost x a -> SpiderTimelineEnv x -> IO a
forall x a. SpiderHost x a -> SpiderTimelineEnv x -> IO a
runSpiderHostForTimeline (SpiderHost x a -> SpiderTimelineEnv x -> IO a)
-> SpiderHost x a -> SpiderTimelineEnv x -> IO a
forall a b. (a -> b) -> a -> b
$ do
(postBuild, postBuildTriggerRef) <- SpiderHost
x
(Event (SpiderTimeline x) (),
IORef (Maybe (EventTrigger (SpiderTimeline x) ())))
SpiderHost
x
(Event (SpiderTimeline x) (),
Ref (SpiderHost x) (Maybe (EventTrigger (SpiderTimeline x) ())))
forall t (m :: * -> *) a.
(MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) =>
m (Event t a, Ref m (Maybe (EventTrigger t a)))
newEventWithTriggerRef
events <- liftIO newChan
(result, fc@(FireCommand fire)) <- do
hostPerformEventT $
flip runPostBuildT postBuild $
flip runTriggerEventT events $
guest
mPostBuildTrigger <- readRef postBuildTriggerRef
shutdown <- subscribeEvent result
initialShutdownEventFirings :: Maybe [Maybe a] <- for mPostBuildTrigger $ \EventTrigger (SpiderTimeline x) ()
postBuildTrigger ->
[DSum (EventTrigger (SpiderTimeline x)) Identity]
-> ReadPhase (SpiderHost x) (Maybe a) -> SpiderHost x [Maybe a]
forall a.
[DSum (EventTrigger (SpiderTimeline x)) Identity]
-> ReadPhase (SpiderHost x) a -> SpiderHost x [a]
fire [EventTrigger (SpiderTimeline x) ()
postBuildTrigger EventTrigger (SpiderTimeline x) ()
-> Identity () -> DSum (EventTrigger (SpiderTimeline x)) Identity
forall {k} (tag :: k -> *) (f :: k -> *) (a :: k).
tag a -> f a -> DSum tag f
:=> () -> Identity ()
forall a. a -> Identity a
Identity ()] (ReadPhase (SpiderHost x) (Maybe a) -> SpiderHost x [Maybe a])
-> ReadPhase (SpiderHost x) (Maybe a) -> SpiderHost x [Maybe a]
forall a b. (a -> b) -> a -> b
$ Maybe (ReadPhase x a) -> ReadPhase (SpiderHost x) (Maybe a)
Maybe (ReadPhase x a) -> ReadPhase x (Maybe a)
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => Maybe (m a) -> m (Maybe a)
sequence (Maybe (ReadPhase x a) -> ReadPhase (SpiderHost x) (Maybe a))
-> ReadPhase (SpiderHost x) (Maybe (ReadPhase x a))
-> ReadPhase (SpiderHost x) (Maybe a)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EventHandle (SpiderTimeline x) a
-> ReadPhase x (Maybe (ReadPhase x a))
forall a.
EventHandle (SpiderTimeline x) a
-> ReadPhase x (Maybe (ReadPhase x a))
forall t (m :: * -> *) a.
MonadReadEvent t m =>
EventHandle t a -> m (Maybe (m a))
readEvent EventHandle (SpiderTimeline x) a
shutdown
let shutdownImmediately = case Maybe [Maybe a]
initialShutdownEventFirings of
Maybe [Maybe a]
Nothing -> Maybe a
forall a. Maybe a
Nothing
Just [Maybe a]
firings -> [Maybe a] -> Maybe a
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum [Maybe a]
firings
case shutdownImmediately of
Just a
exitResult -> a -> SpiderHost x a
forall a. a -> SpiderHost x a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
exitResult
Maybe a
Nothing -> (SpiderHost x a -> SpiderHost x a) -> SpiderHost x a
forall a. (a -> a) -> a
fix ((SpiderHost x a -> SpiderHost x a) -> SpiderHost x a)
-> (SpiderHost x a -> SpiderHost x a) -> SpiderHost x a
forall a b. (a -> b) -> a -> b
$ \SpiderHost x a
loop -> do
ers <- IO [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
-> SpiderHost
x [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
forall a. IO a -> SpiderHost x a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
-> SpiderHost
x [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation])
-> IO [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
-> SpiderHost
x [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
forall a b. (a -> b) -> a -> b
$ Chan [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
-> IO [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
forall a. Chan a -> IO a
readChan Chan [DSum (EventTriggerRef (SpiderTimeline x)) TriggerInvocation]
events
shutdownEventFirings :: [Maybe a] <- do
fireEventTriggerRefs fc ers $
sequence =<< readEvent shutdown
let
shutdownNow = [Maybe a] -> Maybe a
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum [Maybe a]
shutdownEventFirings
case shutdownNow of
Just a
exitResult -> a -> SpiderHost x a
forall a. a -> SpiderHost x a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
exitResult
Maybe a
Nothing -> SpiderHost x a
loop
where
fireEventTriggerRefs
:: forall b m t
. MonadIO m
=> FireCommand t m
-> [DSum (EventTriggerRef t) TriggerInvocation]
-> ReadPhase m b
-> m [b]
fireEventTriggerRefs :: forall b (m :: * -> *) t.
MonadIO m =>
FireCommand t m
-> [DSum (EventTriggerRef t) TriggerInvocation]
-> ReadPhase m b
-> m [b]
fireEventTriggerRefs (FireCommand forall a.
[DSum (EventTrigger t) Identity] -> ReadPhase m a -> m [a]
fire) [DSum (EventTriggerRef t) TriggerInvocation]
ers ReadPhase m b
rcb = do
mes <- IO [Maybe (DSum (EventTrigger t) Identity)]
-> m [Maybe (DSum (EventTrigger t) Identity)]
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [Maybe (DSum (EventTrigger t) Identity)]
-> m [Maybe (DSum (EventTrigger t) Identity)])
-> IO [Maybe (DSum (EventTrigger t) Identity)]
-> m [Maybe (DSum (EventTrigger t) Identity)]
forall a b. (a -> b) -> a -> b
$
[DSum (EventTriggerRef t) TriggerInvocation]
-> (DSum (EventTriggerRef t) TriggerInvocation
-> IO (Maybe (DSum (EventTrigger t) Identity)))
-> IO [Maybe (DSum (EventTrigger t) Identity)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [DSum (EventTriggerRef t) TriggerInvocation]
ers ((DSum (EventTriggerRef t) TriggerInvocation
-> IO (Maybe (DSum (EventTrigger t) Identity)))
-> IO [Maybe (DSum (EventTrigger t) Identity)])
-> (DSum (EventTriggerRef t) TriggerInvocation
-> IO (Maybe (DSum (EventTrigger t) Identity)))
-> IO [Maybe (DSum (EventTrigger t) Identity)]
forall a b. (a -> b) -> a -> b
$ \(EventTriggerRef IORef (Maybe (EventTrigger t a))
er :=> TriggerInvocation a
a IO ()
_) -> do
me <- IORef (Maybe (EventTrigger t a)) -> IO (Maybe (EventTrigger t a))
forall a. IORef a -> IO a
readIORef IORef (Maybe (EventTrigger t a))
er
pure $ fmap (==> a) me
a <- fire (catMaybes mes) rcb
liftIO $ for_ ers $ \(EventTriggerRef t a
_ :=> TriggerInvocation a
_ IO ()
cb) -> IO ()
cb
pure a