{-# LANGUAGE CPP #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
#ifdef USE_REFLEX_OPTIMIZER
{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
#endif
module Reflex.PerformEvent.Base
( PerformEventT (..)
, FireCommand (..)
, hostPerformEventT
) where
import Reflex.Class
import Reflex.Adjustable.Class
import Reflex.Host.Class
import Reflex.PerformEvent.Class
import Reflex.Requester.Base
import Reflex.Requester.Class
import Control.Lens
import Control.Monad.Exception
import Control.Monad.Identity
import Control.Monad.Primitive
import Control.Monad.Reader
import Control.Monad.Ref
import Data.Coerce
import Data.Dependent.Map (DMap)
import qualified Data.Dependent.Map as DMap
import Data.Dependent.Sum
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IntMap
import qualified Data.Semigroup as S
newtype FireCommand t m = FireCommand { runFireCommand :: forall a. [DSum (EventTrigger t) Identity] -> ReadPhase m a -> m [a] }
newtype PerformEventT t m a = PerformEventT { unPerformEventT :: RequesterT t (HostFrame t) Identity (HostFrame t) a }
deriving instance ReflexHost t => Functor (PerformEventT t m)
deriving instance ReflexHost t => Applicative (PerformEventT t m)
deriving instance ReflexHost t => Monad (PerformEventT t m)
deriving instance ReflexHost t => MonadFix (PerformEventT t m)
deriving instance (ReflexHost t, MonadIO (HostFrame t)) => MonadIO (PerformEventT t m)
deriving instance (ReflexHost t, MonadException (HostFrame t)) => MonadException (PerformEventT t m)
deriving instance (ReflexHost t, Monoid a) => Monoid (PerformEventT t m a)
deriving instance (ReflexHost t, S.Semigroup a) => S.Semigroup (PerformEventT t m a)
instance (PrimMonad (HostFrame t), ReflexHost t) => PrimMonad (PerformEventT t m) where
type PrimState (PerformEventT t m) = PrimState (HostFrame t)
primitive = PerformEventT . lift . primitive
instance (ReflexHost t, Ref m ~ Ref IO) => PerformEvent t (PerformEventT t m) where
type Performable (PerformEventT t m) = HostFrame t
{-# INLINABLE performEvent_ #-}
performEvent_ = PerformEventT . requesting_
{-# INLINABLE performEvent #-}
performEvent = PerformEventT . requestingIdentity
instance (ReflexHost t, PrimMonad (HostFrame t)) => Adjustable t (PerformEventT t m) where
runWithReplace outerA0 outerA' = PerformEventT $ runWithReplaceRequesterTWith f (coerce outerA0) (coerceEvent outerA')
where f :: HostFrame t a -> Event t (HostFrame t b) -> RequesterT t (HostFrame t) Identity (HostFrame t) (a, Event t b)
f a0 a' = do
result0 <- lift a0
result' <- requestingIdentity a'
return (result0, result')
traverseIntMapWithKeyWithAdjust f outerDm0 outerDm' = PerformEventT $ traverseIntMapWithKeyWithAdjustRequesterTWith (defaultAdjustIntBase traverseIntMapPatchWithKey) patchIntMapNewElementsMap mergeIntIncremental (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
traverseDMapWithKeyWithAdjust f outerDm0 outerDm' = PerformEventT $ traverseDMapWithKeyWithAdjustRequesterTWith (defaultAdjustBase traversePatchDMapWithKey) mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
traverseDMapWithKeyWithAdjustWithMove f outerDm0 outerDm' = PerformEventT $ traverseDMapWithKeyWithAdjustRequesterTWith (defaultAdjustBase traversePatchDMapWithMoveWithKey) mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
defaultAdjustBase :: forall t v v2 k' p. (Monad (HostFrame t), PrimMonad (HostFrame t), Reflex t)
=> ((forall a. k' a -> v a -> HostFrame t (v2 a)) -> p k' v -> HostFrame t (p k' v2))
-> (forall a. k' a -> v a -> HostFrame t (v2 a))
-> DMap k' v
-> Event t (p k' v)
-> RequesterT t (HostFrame t) Identity (HostFrame t) (DMap k' v2, Event t (p k' v2))
defaultAdjustBase traversePatchWithKey f' dm0 dm' = do
result0 <- lift $ DMap.traverseWithKey f' dm0
result' <- requestingIdentity $ ffor dm' $ traversePatchWithKey f'
return (result0, result')
defaultAdjustIntBase :: forall t v v2 p. (Monad (HostFrame t), PrimMonad (HostFrame t), Reflex t)
=> ((IntMap.Key -> v -> HostFrame t v2) -> p v -> HostFrame t (p v2))
-> (IntMap.Key -> v -> HostFrame t v2)
-> IntMap v
-> Event t (p v)
-> RequesterT t (HostFrame t) Identity (HostFrame t) (IntMap v2, Event t (p v2))
defaultAdjustIntBase traversePatchWithKey f' dm0 dm' = do
result0 <- lift $ IntMap.traverseWithKey f' dm0
result' <- requestingIdentity $ ffor dm' $ traversePatchWithKey f'
return (result0, result')
instance ReflexHost t => MonadReflexCreateTrigger t (PerformEventT t m) where
{-# INLINABLE newEventWithTrigger #-}
newEventWithTrigger = PerformEventT . lift . newEventWithTrigger
{-# INLINABLE newFanEventWithTrigger #-}
newFanEventWithTrigger f = PerformEventT $ lift $ newFanEventWithTrigger f
{-# INLINABLE hostPerformEventT #-}
hostPerformEventT :: forall t m a.
( Monad m
, MonadSubscribeEvent t m
, MonadReflexHost t m
, MonadRef m
, Ref m ~ Ref IO
)
=> PerformEventT t m a
-> m (a, FireCommand t m)
hostPerformEventT a = do
(response, responseTrigger) <- newEventWithTriggerRef
(result, eventToPerform) <- runHostFrame $ runRequesterT (unPerformEventT a) response
eventToPerformHandle <- subscribeEvent eventToPerform
return $ (,) result $ FireCommand $ \triggers (readPhase :: ReadPhase m a') -> do
let go :: [DSum (EventTrigger t) Identity] -> m [a']
go ts = do
(result', mToPerform) <- fireEventsAndRead ts $ do
mToPerform <- sequence =<< readEvent eventToPerformHandle
result' <- readPhase
return (result', mToPerform)
case mToPerform of
Nothing -> return [result']
Just toPerform -> do
responses <- runHostFrame $ traverseRequesterData (Identity <$>) toPerform
mrt <- readRef responseTrigger
let followupEventTriggers = case mrt of
Just rt -> [rt :=> Identity responses]
Nothing -> []
(result':) <$> go followupEventTriggers
go triggers
instance ReflexHost t => MonadSample t (PerformEventT t m) where
{-# INLINABLE sample #-}
sample = PerformEventT . lift . sample
instance (ReflexHost t, MonadHold t m) => MonadHold t (PerformEventT t m) where
{-# INLINABLE hold #-}
hold v0 v' = PerformEventT $ lift $ hold v0 v'
{-# INLINABLE holdDyn #-}
holdDyn v0 v' = PerformEventT $ lift $ holdDyn v0 v'
{-# INLINABLE holdIncremental #-}
holdIncremental v0 v' = PerformEventT $ lift $ holdIncremental v0 v'
{-# INLINABLE buildDynamic #-}
buildDynamic getV0 v' = PerformEventT $ lift $ buildDynamic getV0 v'
{-# INLINABLE headE #-}
headE = PerformEventT . lift . headE
instance (MonadRef (HostFrame t), ReflexHost t) => MonadRef (PerformEventT t m) where
type Ref (PerformEventT t m) = Ref (HostFrame t)
{-# INLINABLE newRef #-}
newRef = PerformEventT . lift . newRef
{-# INLINABLE readRef #-}
readRef = PerformEventT . lift . readRef
{-# INLINABLE writeRef #-}
writeRef r = PerformEventT . lift . writeRef r
instance (MonadAtomicRef (HostFrame t), ReflexHost t) => MonadAtomicRef (PerformEventT t m) where
{-# INLINABLE atomicModifyRef #-}
atomicModifyRef r = PerformEventT . lift . atomicModifyRef r