1{-# LANGUAGE ConstraintKinds #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE StandaloneDeriving #-}
10{-# LANGUAGE UndecidableInstances #-}
11module Reflex.Plan.Reflex
32import Reflex.Host.Class
35import Control.Applicative
37import Control.Monad.Identity
38import Control.Monad.State.Strict
40import Control.Monad.Ref
41import Data.Dependent.Sum (DSum (..))
42import qualified Data.IntMap.Strict as IntMap
45import Data.Traversable (sequenceA, traverse)
48import Control.Exception
49import Data.IntMap.Strict (IntMap)
53-- Note: this import must come last to silence warnings from AMP
56type MonadIORef m = (MonadIO m, MonadRef m, Ref m ~ Ref IO)
59 Firing :: IORef (Maybe (EventTrigger t a)) -> a -> Firing t
62type Schedule t = IntMap [Firing t]
64-- Implementation of a TestPlan in terms of ReflexHost
65newtype Plan t a = Plan (StateT (Schedule t) (HostFrame t) a)
67deriving instance ReflexHost t => Functor (Plan t)
68deriving instance ReflexHost t => Applicative (Plan t)
69deriving instance ReflexHost t => Monad (Plan t)
71deriving instance ReflexHost t => MonadSample t (Plan t)
72deriving instance ReflexHost t => MonadHold t (Plan t)
73deriving instance ReflexHost t => MonadFix (Plan t)
76instance (ReflexHost t, MonadRef (HostFrame t), Ref (HostFrame t) ~ Ref IO) => TestPlan t (Plan t) where
77 plan occurrences = Plan $ do
78 (e, ref) <- newEventWithTriggerRef
79 modify (IntMap.unionWith mappend (firings ref))
83 firings ref = IntMap.fromList (makeFiring ref <$> occurrences)
84 makeFiring ref (t, a) = (fromIntegral t, [Firing ref a])
87firingTrigger :: (MonadReflexHost t m, MonadIORef m) => Firing t -> m (Maybe (DSum (EventTrigger t) Identity))
88firingTrigger (Firing ref a) = fmap (:=> Identity a) <$> readRef ref
90runPlan :: (MonadReflexHost t m) => Plan t a -> m (a, Schedule t)
91runPlan (Plan p) = runHostFrame $ runStateT p mempty
94makeDense :: Schedule t -> Schedule t
95makeDense s = fromMaybe (emptyRange 0) $ do
96 (end, _) <- fst <$> IntMap.maxViewWithKey s
97 return $ IntMap.union s (emptyRange end)
99 emptyRange end = IntMap.fromList (zip [0..end + 1] (repeat []))
102-- For the purposes of testing, we add in a zero frame and extend one frame (to observe changes to behaviors
103-- after the last event)
104-- performGC is called at each frame to test for GC issues
105testSchedule :: (MonadReflexHost t m, MonadIORef m, NFData a) => Schedule t -> ReadPhase m a -> m (IntMap a)
106testSchedule schedule readResult = IntMap.traverseWithKey (\t occs -> liftIO performGC *> triggerFrame readResult t occs) (makeDense schedule)
108readSchedule :: (MonadReflexHost t m, MonadIORef m, NFData a) => Schedule t -> ReadPhase m a -> m (IntMap a)
109readSchedule schedule readResult = IntMap.traverseWithKey (triggerFrame readResult) schedule
111readSchedule_ :: (MonadReflexHost t m, MonadIORef m, NFData a) => Schedule t -> ReadPhase m a -> m ()
112readSchedule_ schedule readResult = mapM_ (uncurry $ triggerFrame readResult) $ IntMap.toList schedule
114triggerFrame :: (MonadReflexHost t m, MonadIORef m, NFData a) => ReadPhase m a -> Int -> [Firing t] -> m a
115triggerFrame readResult _ occs = do
116 triggers <- catMaybes <$> traverse firingTrigger occs
117 liftIO . evaluate . force =<< fireEventsAndRead triggers readResult
119readEvent' :: MonadReadEvent t m => EventHandle t a -> m (Maybe a)
120readEvent' = readEvent >=> sequenceA
123-- Convenience functions for running tests producing Events/Behaviors
124runTestB :: (MonadReflexHost t m, MonadIORef m, NFData a) => Plan t (Behavior t a) -> m (IntMap a)
127 testSchedule s $ sample b
129runTestE :: (MonadReflexHost t m, MonadIORef m, NFData a) => Plan t (Event t a) -> m (IntMap (Maybe a))
132 h <- subscribeEvent e
133 testSchedule s (readEvent' h)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list