@@ -1,8 +1,6 @@
1−{-# LANGUAGE CPP, ExistentialQuantification, GADTs, ScopedTypeVariables, TypeFamilies, FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, RankNTypes, BangPatterns, UndecidableInstances, EmptyDataDecls, RecursiveDo, RoleAnnotations, LambdaCase #-}
1+{-# LANGUAGE CPP, ExistentialQuantification, GADTs, ScopedTypeVariables, TypeFamilies, FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, RankNTypes, BangPatterns, UndecidableInstances, EmptyDataDecls, RecursiveDo, RoleAnnotations, LambdaCase, TypeOperators #-}
22module Reflex.Spider.Internal where
33
4−import Prelude hiding (mapM, mapM_, any, sequence, concat)
5−
64import qualified Reflex.Class as R
75import qualified Reflex.Host.Class as R
86
@@ -13,9 +11,7 @@ import Data.Traversable
1311import Control.Monad hiding (mapM, mapM_, forM_, forM, sequence)
1412import Control.Monad.Reader hiding (mapM, mapM_, forM_, forM, sequence)
1513import GHC.Exts
16−#if !MIN_VERSION_base(4,8,0)
17−import Control.Applicative
18−#endif
14+import Control.Applicative -- Unconditionally import, because otherwise it breaks on GHC 7.10.1RC2
1915import Data.Dependent.Map (DMap, DSum (..))
2016import qualified Data.Dependent.Map as DMap
2117import Data.GADT.Compare
@@ -24,12 +20,16 @@ import Data.Maybe
2420import Data.IntMap (IntMap)
2521import qualified Data.IntMap as IntMap
2622import Control.Monad.Ref
23+import Control.Monad.Exception
2724import Data.Monoid ((<>))
2825
2926import System.IO.Unsafe
3027import Unsafe.Coerce
3128import Control.Monad.Primitive
3229
30+-- Note: must come last to silence warnings due to AMP on GHC < 7.10
31+import Prelude hiding (mapM, mapM_, any, sequence, concat)
32+
3333debugPropagate :: Bool
3434
3535debugInvalidateHeight :: Bool
@@ -109,6 +109,7 @@ data EventEnv
109109 = EventEnv { eventEnvAssignments :: !(IORef [SomeAssignment])
110110 , eventEnvHoldInits :: !(IORef [SomeHoldInit])
111111 , eventEnvClears :: !(IORef [SomeMaybeIORef])
112+ , eventEnvRootClears :: !(IORef [SomeDMapIORef])
112113 , eventEnvCurrentHeight :: !(IORef Int)
113114 , eventEnvCoincidenceInfos :: !(IORef [SomeCoincidenceInfo])
114115 , eventEnvDelayedMerges :: !(IORef (IntMap [DelayedMerge]))
@@ -138,6 +139,11 @@ scheduleClear r = EventM $ do
138139 clears <- asks eventEnvClears
139140 liftIO $ modifyIORef' clears (SomeMaybeIORef r :)
140141
142+scheduleRootClear :: IORef (DMap k) -> EventM ()
143+scheduleRootClear r = EventM $ do
144+ clears <- asks eventEnvRootClears
145+ liftIO $ modifyIORef' clears (SomeDMapIORef r :)
146+
141147scheduleMerge :: Int -> MergeSubscribed a -> EventM ()
142148scheduleMerge height subscribed = EventM $ do
143149 delayedRef <- asks eventEnvDelayedMerges
@@ -213,19 +219,19 @@ data Invalidator
213219
214220data RootSubscribed a
215221 = RootSubscribed { rootSubscribedSubscribers :: !(IORef [WeakSubscriber a])
216− , rootSubscribedOccurrence :: !(IORef (Maybe a)) -- Alias to rootOccurrence
222+ , rootSubscribedOccurrence :: !(IO (Maybe a)) -- Lookup from rootOccurrence
217223 }
218224
219−data Root a
220− = Root { rootOccurrence :: !(IORef (Maybe a)) -- The currently-firing occurrence of this event
221− , rootSubscribed :: !(IORef (Maybe (RootSubscribed a)))
222− , rootInit :: !(RootTrigger a -> IO (IO ()))
225+data Root (k :: * -> *)
226+ = Root { rootOccurrence :: !(IORef (DMap k)) -- The currently-firing occurrence of this event
227+ , rootSubscribed :: !(IORef (DMap (WrapArg RootSubscribed k)))
228+ , rootInit :: !(forall a. k a -> RootTrigger a -> IO (IO ()))
223229 }
224230
225231data SomeHoldInit = forall a. SomeHoldInit (Event a) (Hold a)
226232
227233-- EventM can do everything BehaviorM can, plus create holds
228−newtype EventM a = EventM { unEventM :: ReaderT EventEnv IO a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO) -- The environment should be Nothing if we are not in a frame, and Just if we are - in which case it is a list of assignments to be done after the frame is over
234+newtype EventM a = EventM { unEventM :: ReaderT EventEnv IO a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException) -- The environment should be Nothing if we are not in a frame, and Just if we are - in which case it is a list of assignments to be done after the frame is over
229235
230236data PushSubscribed a b
231237 = PushSubscribed { pushSubscribedOccurrence :: !(IORef (Maybe b)) -- If the current height is less than our height, this should always be Nothing; during our height, this will get filled in at some point, always before our children are notified; after our height, this will be filled in with the correct value (Nothing if we are not firing, Just if we are)
@@ -365,7 +371,7 @@ showSubscriberType = \case
365371 SubscriberCoincidenceInner _ -> "SubscriberCoincidenceInner"
366372
367373data Event a
368− = EventRoot !(Root a)
374+ = forall k. GCompare k => EventRoot !(k a) !(Root k)
369375 | EventNever
370376 | forall b. EventPush !(Push b a)
371377 | forall k. (GCompare k, a ~ DMap k) => EventMerge !(Merge k)
@@ -375,7 +381,7 @@ data Event a
375381
376382showEventType :: Event a -> String
377383showEventType = \case
378− EventRoot _ -> "EventRoot"
384+ EventRoot _ _ -> "EventRoot"
379385 EventNever -> "EventNever"
380386 EventPush _ -> "EventPush"
381387 EventMerge _ -> "EventMerge"
@@ -402,7 +408,7 @@ data EventSubscribed a
402408-- the weak pointer to it in some cases.
403409
404410{-# NOINLINE newRootSubscribed #-}
405−newRootSubscribed :: IORef (Maybe a) -> IORef [WeakSubscriber a] -> IO (RootSubscribed a)
411+newRootSubscribed :: IO (Maybe a) -> IORef [WeakSubscriber a] -> IO (RootSubscribed a)
406412newRootSubscribed occ subs =
407413 return $! RootSubscribed
408414 { rootSubscribedOccurrence = occ
@@ -495,14 +501,14 @@ coincidence a = EventCoincidence $ Coincidence
495501 , coincidenceSubscribed = unsafeNewIORef a Nothing
496502 }
497503
498−newRoot :: IO (Root a)
504+newRoot :: IO (Root k)
499505newRoot = do
500− occRef <- newIORef Nothing
501− subscribedRef <- newIORef Nothing
506+ occRef <- newIORef DMap.empty
507+ subscribedRef <- newIORef DMap.empty
502508 return $ Root
503509 { rootOccurrence = occRef
504510 , rootSubscribed = subscribedRef
505− , rootInit = const $ return $ return ()
511+ , rootInit = \_ _ -> return $ return ()
506512 }
507513
508514propagateAndUpdateSubscribersRef :: IORef [WeakSubscriber a] -> a -> EventM ()
@@ -517,10 +523,16 @@ run :: [DSum RootTrigger] -> ResultM b -> IO b
517523run roots after = do
518524 when debugPropagate $ putStrLn "Running an event frame"
519525 result <- runFrame $ do
520− forM_ roots $ \(RootTrigger (_, occRef) :=> a) -> do
521− liftIO $ writeIORef occRef $ Just a
522− scheduleClear occRef
523− forM_ roots $ \(RootTrigger (subscribersRef, _) :=> a) -> do
526+ rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
527+ occBefore <- liftIO $ do
528+ occBefore <- readIORef occRef
529+ writeIORef occRef $ DMap.insert k a occBefore
530+ return occBefore
531+ if DMap.null occBefore
532+ then do scheduleRootClear occRef
533+ return $ Just r
534+ else return Nothing
535+ forM_ (catMaybes rootsToPropagate) $ \(RootTrigger (subscribersRef, _, _) :=> a) -> do
524536 propagateAndUpdateSubscribersRef subscribersRef a
525537 delayedRef <- EventM $ asks eventEnvDelayedMerges
526538 let go = do
@@ -553,6 +565,8 @@ run roots after = do
553565
554566data SomeMaybeIORef = forall a. SomeMaybeIORef (IORef (Maybe a))
555567
568+data SomeDMapIORef = forall k. SomeDMapIORef (IORef (DMap k))
569+
556570data SomeAssignment = forall a. SomeAssignment (Hold a) a
557571
558572data DelayedMerge = forall k. DelayedMerge (MergeSubscribed k)
@@ -717,7 +731,7 @@ readBehaviorTracked b = case b of
717731
718732readEvent :: Event a -> ResultM (Maybe a)
719733readEvent e = case e of
720− EventRoot r -> liftIO $ readIORef $ rootOccurrence r
734+ EventRoot k r -> liftIO $ liftM (DMap.lookup k) $ readIORef $ rootOccurrence r
721735 EventNever -> return Nothing
722736 EventPush p -> do
723737 subscribed <- getPushSubscribed p
@@ -756,7 +770,7 @@ zeroRef = unsafePerformIO $ newIORef 0
756770
757771getEventSubscribed :: Event a -> EventM (EventSubscribed a)
758772getEventSubscribed e = case e of
759− EventRoot r -> liftM EventSubscribedRoot $ getRootSubscribed r
773+ EventRoot k r -> liftM EventSubscribedRoot $ getRootSubscribed k r
760774 EventNever -> return EventSubscribedNever
761775 EventPush p -> liftM EventSubscribedPush $ getPushSubscribed p
762776 EventFan k f -> liftM (EventSubscribedFan k) $ getFanSubscribed f
@@ -793,7 +807,7 @@ subscribeEventSubscribed es ws = case es of
793807
794808getEventSubscribedOcc :: EventSubscribed a -> IO (Maybe a)
795809getEventSubscribedOcc es = case es of
796− EventSubscribedRoot r -> readIORef $ rootSubscribedOccurrence r
810+ EventSubscribedRoot r -> rootSubscribedOccurrence r
797811 EventSubscribedNever -> return Nothing
798812 EventSubscribedPush subscribed -> readIORef $ pushSubscribedOccurrence subscribed
799813 EventSubscribedFan k subscribed -> do
@@ -824,21 +838,21 @@ noinlineFalse :: Bool
824838noinlineFalse = False
825839{-# NOINLINE noinlineFalse #-}
826840
827−getRootSubscribed :: Root a -> EventM (RootSubscribed a)
828−getRootSubscribed r = do
841+getRootSubscribed :: GCompare k => k a -> Root k -> EventM (RootSubscribed a)
842+getRootSubscribed k r = do
829843 mSubscribed <- liftIO $ readIORef $ rootSubscribed r
830− case mSubscribed of
844+ case DMap.lookup (WrapArg k) mSubscribed of
831845 Just subscribed -> return subscribed
832846 Nothing -> liftIO $ do
833847 subscribersRef <- newIORef []
834− subscribed <- newRootSubscribed (rootOccurrence r) subscribersRef
848+ subscribed <- newRootSubscribed (liftM (DMap.lookup k) $ readIORef $ rootOccurrence r) subscribersRef
835849 -- Strangely, init needs the same stuff as a RootSubscribed has, but it must not be the same as the one that everyone's subscribing to, or it'll leak memory
836− uninit <- rootInit r $ RootTrigger (subscribersRef, rootOccurrence r)
850+ uninit <- rootInit r k $ RootTrigger (subscribersRef, rootOccurrence r, k)
837851 addFinalizer subscribed $ do
838852 when noinlineFalse $ putStr "" -- For some reason, without this line, the finalizer will run earlier than it should
839853-- putStrLn "Uninit root"
840854 uninit
841− liftIO $ writeIORef (rootSubscribed r) $ Just subscribed
855+ liftIO $ modifyIORef' (rootSubscribed r) $ DMap.insert (WrapArg k) subscribed
842856 return subscribed
843857
844858-- When getPushSubscribed returns, the PushSubscribed returned will have a fully filled-in
@@ -1057,9 +1071,10 @@ runFrame a = do
10571071 holdInitRef <- newIORef []
10581072 heightRef <- newIORef 0
10591073 toClearRef <- newIORef []
1074+ toClearRootRef <- newIORef []
10601075 coincidenceInfosRef <- newIORef []
10611076 delayedRef <- liftIO $ newIORef IntMap.empty
1062− result <- flip runEventM (EventEnv toAssignRef holdInitRef toClearRef heightRef coincidenceInfosRef delayedRef) $ do
1077+ result <- flip runEventM (EventEnv toAssignRef holdInitRef toClearRef toClearRootRef heightRef coincidenceInfosRef delayedRef) $ do
10631078 result <- a
10641079 let runHoldInits = do
10651080 holdInits <- liftIO $ readIORef holdInitRef
@@ -1071,6 +1086,8 @@ runFrame a = do
10711086 return result
10721087 toClear <- readIORef toClearRef
10731088 forM_ toClear $ \(SomeMaybeIORef ref) -> writeIORef ref Nothing
1089+ toClearRoot <- readIORef toClearRootRef
1090+ forM_ toClearRoot $ \(SomeDMapIORef ref) -> writeIORef ref DMap.empty
10741091 toAssign <- readIORef toAssignRef
10751092 toReconnectRef <- newIORef []
10761093 forM_ toAssign $ \(SomeAssignment h v) -> do
@@ -1323,16 +1340,22 @@ instance R.MonadHold Spider EventM where
13231340 {-# INLINE hold #-}
13241341 hold v0 e = SpiderBehavior <$> hold v0 (unSpiderEvent e)
13251342
1326−newtype RootTrigger a = RootTrigger (IORef [WeakSubscriber a], IORef (Maybe a))
1343+data RootTrigger a = forall k. GCompare k => RootTrigger (IORef [WeakSubscriber a], IORef (DMap k), k a)
1344+newtype SpiderEventHandle a = SpiderEventHandle { unEventHandle :: Event a }
1345+
1346+instance R.MonadSubscribeEvent Spider SpiderHostFrame where
1347+ subscribeEvent e = SpiderHostFrame $ do
1348+ _ <- getEventSubscribed $ unSpiderEvent e --TODO: The result of this should actually be used
1349+ return $ SpiderEventHandle (unSpiderEvent e)
13271350
13281351instance R.ReflexHost Spider where
13291352 type EventTrigger Spider = RootTrigger
1330− type EventHandle Spider = R.Event Spider
1353+ type EventHandle Spider = SpiderEventHandle
13311354 type HostFrame Spider = SpiderHostFrame
13321355
1333−instance R.MonadReadEvent Spider ResultM where
1356+instance R.MonadReadEvent Spider ReadPhase where
13341357 {-# INLINE readEvent #-}
1335− readEvent = liftM (fmap return) . readEvent . unSpiderEvent
1358+ readEvent = ReadPhase . liftM (fmap return) . readEvent . unEventHandle
13361359
13371360instance MonadRef EventM where
13381361 type Ref EventM = Ref IO
@@ -1347,9 +1370,9 @@ instance MonadAtomicRef EventM where
13471370 {-# INLINE atomicModifyRef #-}
13481371 atomicModifyRef r f = liftIO $ atomicModifyRef r f
13491372
1350−newtype SpiderHost a = SpiderHost { runSpiderHost :: IO a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO)
1373+newtype SpiderHost a = SpiderHost { runSpiderHost :: IO a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
13511374
1352−newtype SpiderHostFrame a = SpiderHostFrame { runSpiderHostFrame :: EventM a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO)
1375+newtype SpiderHostFrame a = SpiderHostFrame { runSpiderHostFrame :: EventM a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
13531376
13541377instance R.MonadSample Spider SpiderHostFrame where
13551378 sample = SpiderHostFrame . R.sample --TODO: This can cause problems with laziness, so we should get rid of it if we can
@@ -1358,29 +1381,44 @@ instance R.MonadHold Spider SpiderHostFrame where
13581381 {-# INLINE hold #-}
13591382 hold v0 e = SpiderHostFrame $ R.hold v0 e
13601383
1361−newEventWithTriggerIO :: (RootTrigger a -> IO (IO ())) -> IO (R.Event Spider a)
1384+newEventWithTriggerIO :: forall a. (RootTrigger a -> IO (IO ())) -> IO (Event a)
13621385newEventWithTriggerIO f = do
1363− occRef <- newIORef Nothing
1364− subscribedRef <- newIORef Nothing
1386+ es <- newFanEventWithTriggerIO $ \Refl -> f
1387+ return $ select es Refl
1388+
1389+newFanEventWithTriggerIO :: GCompare k => (forall a. k a -> RootTrigger a -> IO (IO ())) -> IO (EventSelector k)
1390+newFanEventWithTriggerIO f = do
1391+ occRef <- newIORef DMap.empty
1392+ subscribedRef <- newIORef DMap.empty
13651393 let !r = Root
13661394 { rootOccurrence = occRef
13671395 , rootSubscribed = subscribedRef
13681396 , rootInit = f
13691397 }
1370− return $ SpiderEvent $ EventRoot r
1398+ return $ EventSelector $ \k -> EventRoot k r
13711399
13721400instance R.MonadReflexCreateTrigger Spider SpiderHost where
1373− newEventWithTrigger = SpiderHost . newEventWithTriggerIO
1401+ newEventWithTrigger = SpiderHost . liftM SpiderEvent . newEventWithTriggerIO
1402+ newFanEventWithTrigger f = SpiderHost $ do
1403+ es <- newFanEventWithTriggerIO f
1404+ return $ R.EventSelector $ SpiderEvent . select es
13741405
13751406instance R.MonadReflexCreateTrigger Spider SpiderHostFrame where
1376− newEventWithTrigger = SpiderHostFrame . EventM . liftIO . newEventWithTriggerIO
1407+ newEventWithTrigger = SpiderHostFrame . EventM . liftIO . liftM SpiderEvent . newEventWithTriggerIO
1408+ newFanEventWithTrigger f = SpiderHostFrame $ EventM $ liftIO $ do
1409+ es <- newFanEventWithTriggerIO f
1410+ return $ R.EventSelector $ SpiderEvent . select es
13771411
1378−instance R.MonadReflexHost Spider SpiderHost where
1379− fireEventsAndRead es a = SpiderHost $ run es a
1412+instance R.MonadSubscribeEvent Spider SpiderHost where
13801413 subscribeEvent e = SpiderHost $ do
13811414 _ <- runFrame $ getEventSubscribed $ unSpiderEvent e --TODO: The result of this should actually be used
1382− return e
1383− runFrame = SpiderHost . runFrame
1415+ return $ SpiderEventHandle (unSpiderEvent e)
1416+
1417+newtype ReadPhase a = ReadPhase { runReadPhase :: ResultM a } deriving (Functor, Applicative, Monad, MonadFix, R.MonadSample Spider, R.MonadHold Spider)
1418+
1419+instance R.MonadReflexHost Spider SpiderHost where
1420+ type ReadPhase SpiderHost = ReadPhase
1421+ fireEventsAndRead es (ReadPhase a) = SpiderHost $ run es a
13841422 runHostFrame = SpiderHost . runFrame . runSpiderHostFrame
13851423
13861424instance MonadRef SpiderHost where