{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module Reflex.TriggerEvent.Base
( TriggerEventT (..)
, runTriggerEventT
, askEvents
, TriggerInvocation (..)
, EventTriggerRef (..)
) where
import Control.Applicative (liftA2)
import Control.Concurrent
import Control.Monad.Exception
import Control.Monad.Primitive
import Control.Monad.Reader
import Control.Monad.Ref
import Data.Coerce
import Data.Dependent.Sum
import Data.IORef
import Data.Monoid ((<>))
import qualified Data.Semigroup as S
import Reflex.Class
import Reflex.Adjustable.Class
import Reflex.Host.Class
import Reflex.PerformEvent.Class
import Reflex.PostBuild.Class
import Reflex.TriggerEvent.Class
data TriggerInvocation a = TriggerInvocation a (IO ())
newtype EventTriggerRef t a = EventTriggerRef { unEventTriggerRef :: IORef (Maybe (EventTrigger t a)) }
newtype TriggerEventT t m a = TriggerEventT { unTriggerEventT :: ReaderT (Chan [DSum (EventTriggerRef t) TriggerInvocation]) m a }
deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
runTriggerEventT :: TriggerEventT t m a -> Chan [DSum (EventTriggerRef t) TriggerInvocation] -> m a
runTriggerEventT = runReaderT . unTriggerEventT
instance MonadTrans (TriggerEventT t) where
{-# INLINABLE lift #-}
lift = TriggerEventT . lift
instance PrimMonad m => PrimMonad (TriggerEventT t m) where
type PrimState (TriggerEventT t m) = PrimState m
{-# INLINABLE primitive #-}
primitive = lift . primitive
instance PerformEvent t m => PerformEvent t (TriggerEventT t m) where
type Performable (TriggerEventT t m) = Performable m
{-# INLINABLE performEvent_ #-}
performEvent_ e = lift $ performEvent_ e
{-# INLINABLE performEvent #-}
performEvent e = lift $ performEvent e
instance PostBuild t m => PostBuild t (TriggerEventT t m) where
{-# INLINABLE getPostBuild #-}
getPostBuild = lift getPostBuild
instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (TriggerEventT t m) where
{-# INLINABLE newEventWithTrigger #-}
newEventWithTrigger = lift . newEventWithTrigger
{-# INLINABLE newFanEventWithTrigger #-}
newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
instance (Monad m, MonadRef m, Ref m ~ Ref IO, MonadReflexCreateTrigger t m) => TriggerEvent t (TriggerEventT t m) where
{-# INLINABLE newTriggerEvent #-}
newTriggerEvent = do
(e, t) <- newTriggerEventWithOnComplete
return (e, \a -> t a $ return ())
{-# INLINABLE newTriggerEventWithOnComplete #-}
newTriggerEventWithOnComplete = do
events <- askEvents
(eResult, reResultTrigger) <- lift newEventWithTriggerRef
return . (,) eResult $ \a cb ->
writeChan events [EventTriggerRef reResultTrigger :=> TriggerInvocation a cb]
{-# INLINABLE newEventWithLazyTriggerWithOnComplete #-}
newEventWithLazyTriggerWithOnComplete f = do
events <- askEvents
lift . newEventWithTrigger $ \t ->
f $ \a cb -> do
reResultTrigger <- newRef $ Just t
writeChan events [EventTriggerRef reResultTrigger :=> TriggerInvocation a cb]
instance MonadRef m => MonadRef (TriggerEventT t m) where
type Ref (TriggerEventT t m) = Ref m
{-# INLINABLE newRef #-}
newRef = lift . newRef
{-# INLINABLE readRef #-}
readRef = lift . readRef
{-# INLINABLE writeRef #-}
writeRef r = lift . writeRef r
instance MonadAtomicRef m => MonadAtomicRef (TriggerEventT t m) where
{-# INLINABLE atomicModifyRef #-}
atomicModifyRef r = lift . atomicModifyRef r
instance MonadSample t m => MonadSample t (TriggerEventT t m) where
{-# INLINABLE sample #-}
sample = lift . sample
instance MonadHold t m => MonadHold t (TriggerEventT t m) where
{-# INLINABLE hold #-}
hold v0 v' = lift $ hold v0 v'
{-# INLINABLE holdDyn #-}
holdDyn v0 v' = lift $ holdDyn v0 v'
{-# INLINABLE holdIncremental #-}
holdIncremental v0 v' = lift $ holdIncremental v0 v'
{-# INLINABLE buildDynamic #-}
buildDynamic a0 = lift . buildDynamic a0
{-# INLINABLE headE #-}
headE = lift . headE
instance Adjustable t m => Adjustable t (TriggerEventT t m) where
{-# INLINABLE runWithReplace #-}
runWithReplace (TriggerEventT a0) a' = TriggerEventT $ runWithReplace a0 (coerceEvent a')
{-# INLINABLE traverseIntMapWithKeyWithAdjust #-}
traverseIntMapWithKeyWithAdjust f dm0 dm' = TriggerEventT $ traverseIntMapWithKeyWithAdjust (coerce . f) dm0 dm'
{-# INLINABLE traverseDMapWithKeyWithAdjust #-}
traverseDMapWithKeyWithAdjust f dm0 dm' = TriggerEventT $ traverseDMapWithKeyWithAdjust (coerce . f) dm0 dm'
{-# INLINABLE traverseDMapWithKeyWithAdjustWithMove #-}
traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = TriggerEventT $ traverseDMapWithKeyWithAdjustWithMove (coerce . f) dm0 dm'
instance (Monoid a, Applicative m) => Monoid (TriggerEventT t m a) where
mempty = pure mempty
mappend = (<>)
instance (S.Semigroup a, Applicative m) => S.Semigroup (TriggerEventT t m a) where
(<>) = liftA2 (S.<>)
askEvents :: Monad m => TriggerEventT t m (Chan [DSum (EventTriggerRef t) TriggerInvocation])
askEvents = TriggerEventT ask