@@ -17,6 +17,7 @@
17{-# LANGUAGE TypeFamilies #-}
17{-# LANGUAGE TypeFamilies #-}
18{-# LANGUAGE TypeOperators #-}
18{-# LANGUAGE TypeOperators #-}
19{-# LANGUAGE UndecidableInstances #-}
19{-# LANGUAGE UndecidableInstances #-}
20+{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
20-- | This module is the implementation of the 'Spider' 'Reflex' engine. It uses
21-- | This module is the implementation of the 'Spider' 'Reflex' engine. It uses
21-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
22-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
22module Reflex.Spider.Internal where
23module Reflex.Spider.Internal where
@@ -180,12 +181,23 @@ unsafeNodeId a = unsafePerformIO $ do
181--------------------------------------------------------------------------------
182--------------------------------------------------------------------------------
184+newtype Event x a = Event { unEvent :: Subscriber x a -> EventM x (EventSubscription x, Maybe a) }
186+{-# INLINE subscribeAndRead #-}
183−newtype Event x a = Event { subscribeAndRead :: Subscriber x a -> EventM x (EventSubscription x, Maybe a) }
187+subscribeAndRead :: Event x a -> Subscriber x a -> EventM x (EventSubscription x, Maybe a)
188+subscribeAndRead = unEvent
190+{-# RULES "pushCheap/cacheEvent" forall f e. pushCheap f (cacheEvent e) = pushCheap f e #-}
191+{-# RULES "hold/cacheEvent" forall f e. hold f (cacheEvent e) = hold f e #-}
193+ "subscribeAndRead/cacheEvent" forall e. subscribeAndRead (cacheEvent e) = subscribeAndRead e
185-- | Construct an 'Event' equivalent to that constructed by 'push', but with no
196-- | Construct an 'Event' equivalent to that constructed by 'push', but with no
186-- caching; if the computation function is very cheap, this is (much) more
197-- caching; if the computation function is very cheap, this is (much) more
187-- efficient than 'push'
198-- efficient than 'push'
188−{-# INLINABLE pushCheap #-}
199+{- INLINABLE pushCheap #-}
200+{-# INLINE [1] pushCheap #-}
189pushCheap :: HasSpiderTimeline x => (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
201pushCheap :: HasSpiderTimeline x => (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
190pushCheap f e = Event $ \sub -> do
202pushCheap f e = Event $ \sub -> do
191 (subscription, occ) <- subscribeAndRead e $ sub
203 (subscription, occ) <- subscribeAndRead e $ sub
@@ -210,7 +222,7 @@ data CacheSubscribed x a
210--TODO: Try a caching strategy where we subscribe directly to the parent when
222--TODO: Try a caching strategy where we subscribe directly to the parent when
211--there's only one subscriber, and then build our own WeakBag only when a second
223--there's only one subscriber, and then build our own WeakBag only when a second
212--subscriber joins
224--subscriber joins
213−{-# INLINABLE cacheEvent #-}
225+{-# NOINLINE [1] cacheEvent #-}
214cacheEvent :: HasSpiderTimeline x => Event x a -> Event x a
226cacheEvent :: HasSpiderTimeline x => Event x a -> Event x a
215cacheEvent e = Event $ \sub -> {-# SCC "cacheEvent" #-} do
227cacheEvent e = Event $ \sub -> {-# SCC "cacheEvent" #-} do
216 let !mSubscribedRef = unsafeNewIORef e Nothing
228 let !mSubscribedRef = unsafeNewIORef e Nothing
@@ -588,7 +600,7 @@ behaviorPull !p = Behavior $ do
588 askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (BehaviorSubscribedPull subscribed) :))
600 askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (BehaviorSubscribedPull subscribed) :))
591−behaviorDyn :: (HasSpiderTimeline x, R.Patch p) => Dyn x p -> Behavior x (R.PatchTarget p)
603+behaviorDyn :: R.Patch p => Dyn x p -> Behavior x (R.PatchTarget p)
592behaviorDyn !d = Behavior $ readHoldTracked =<< getDynHold d
604behaviorDyn !d = Behavior $ readHoldTracked =<< getDynHold d
594{-# INLINE readHoldTracked #-}
606{-# INLINE readHoldTracked #-}
@@ -599,7 +611,7 @@ readHoldTracked h = do
599 askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (BehaviorSubscribedHold h) :))
611 askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (BehaviorSubscribedHold h) :))
600 return result
612 return result
602−{-# SPECIALIZE readBehaviorUntracked :: HasSpiderTimeline x => Behavior x a -> BehaviorM x a #-}
614+{-# SPECIALIZE readBehaviorUntracked :: Behavior x a -> BehaviorM x a #-}
603{-# SPECIALIZE readBehaviorUntracked :: HasSpiderTimeline x => Behavior x a -> EventM x a #-}
615{-# SPECIALIZE readBehaviorUntracked :: HasSpiderTimeline x => Behavior x a -> EventM x a #-}
604readBehaviorUntracked :: Defer (SomeHoldInit x) m => Behavior x a -> m a
616readBehaviorUntracked :: Defer (SomeHoldInit x) m => Behavior x a -> m a
605readBehaviorUntracked b = do
617readBehaviorUntracked b = do
@@ -693,7 +705,7 @@ instance HasSpiderTimeline x => Defer (SomeHoldInit x) (EventM x) where
693 {-# INLINE getDeferralQueue #-}
705 {-# INLINE getDeferralQueue #-}
694 getDeferralQueue = asksEventEnv eventEnvHoldInits
706 getDeferralQueue = asksEventEnv eventEnvHoldInits
696−instance HasSpiderTimeline x => Defer (SomeHoldInit x) (BehaviorM x) where
708+instance Defer (SomeHoldInit x) (BehaviorM x) where
697 {-# INLINE getDeferralQueue #-}
709 {-# INLINE getDeferralQueue #-}
698 getDeferralQueue = BehaviorM $ asks snd
710 getDeferralQueue = BehaviorM $ asks snd
@@ -752,8 +764,8 @@ instance HasSpiderTimeline x => Defer (SomeResetCoincidence x) (EventM x) where
752 getDeferralQueue = asksEventEnv eventEnvResetCoincidences
764 getDeferralQueue = asksEventEnv eventEnvResetCoincidences
754-- Note: hold cannot examine its event until after the phase is over
766-- Note: hold cannot examine its event until after the phase is over
755−{-# SPECIALIZE hold :: (HasSpiderTimeline x, R.Patch p) => R.PatchTarget p -> Event x p -> EventM x (Hold x p) #-}
767+{- SPECIALIZE hold :: (HasSpiderTimeline x, R.Patch p) => R.PatchTarget p -> Event x p -> EventM x (Hold x p) #-}
756−{- SPECIALIZE hold :: (HasSpiderTimeline x, R.Patch p) => R.PatchTarget p -> Event x p -> ComputeM x (Hold x p) #-}
768+{-# INLINE [1] hold #-}
757hold :: (R.Patch p, Defer (SomeHoldInit x) m) => R.PatchTarget p -> Event x p -> m (Hold x p)
769hold :: (R.Patch p, Defer (SomeHoldInit x) m) => R.PatchTarget p -> Event x p -> m (Hold x p)
758hold v0 e = do
770hold v0 e = do
759 valRef <- liftIO $ newIORef v0
771 valRef <- liftIO $ newIORef v0
@@ -1050,17 +1062,9 @@ instance HasSpiderTimeline x => Functor (Event x) where
1050instance Functor (Behavior x) where
1062instance Functor (Behavior x) where
1051 fmap f = pull . fmap f . readBehaviorTracked
1063 fmap f = pull . fmap f . readBehaviorTracked
1053−{-# INLINABLE push #-} --TODO: If this is helpful, we can get rid of the unsafeNewIORef and use unsafePerformIO directly
1065+{-# INLINE push #-}
1054push :: HasSpiderTimeline x => (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
1066push :: HasSpiderTimeline x => (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
1055push f e = cacheEvent (pushCheap f e)
1067push f e = cacheEvent (pushCheap f e)
1057−push f e = eventPush $ Push
1060− , pushSubscribed = unsafeNewIORef (f, e) Nothing --TODO: Does the use of the tuple here create unnecessary overhead?
1062−-- DISABLED: {- RULES "push/push" forall f g e. push f (push g e) = push (maybe (return Nothing) f <=< g) e #-}
1065{-# INLINABLE pull #-}
1069{-# INLINABLE pull #-}
1066pull :: BehaviorM x a -> Behavior x a
1070pull :: BehaviorM x a -> Behavior x a
@@ -1089,8 +1093,8 @@ coincidence a = eventCoincidence $ Coincidence
1089run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1093run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1090run roots after = do
1094run roots after = do
1091 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1095 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1092− spiderTimeline <- SpiderHost ask
1096+ t <- SpiderHost ask
1093− result <- SpiderHost $ lift $ withMVar (_spiderTimeline_lock spiderTimeline) $ \_ -> flip runReaderT spiderTimeline $ unSpiderHost $ runFrame $ do
1097+ result <- SpiderHost $ lift $ withMVar (_spiderTimeline_lock t) $ \_ -> flip runReaderT t $ unSpiderHost $ runFrame $ do
1094 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1098 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1095 occBefore <- liftIO $ do
1099 occBefore <- liftIO $ do
1096 occBefore <- readIORef occRef
1100 occBefore <- readIORef occRef
@@ -1485,7 +1489,11 @@ subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceS
1486{-# INLINE merge #-}
1490{-# INLINE merge #-}
1487merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (R.PatchDMap k (Event x)) -> Event x (DMap k Identity)
1491merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (R.PatchDMap k (Event x)) -> Event x (DMap k Identity)
1488−merge d = cacheEvent $ Event $ \sub -> do
1492+merge d = cacheEvent (mergeCheap d)
1494+{-# INLINE [1] mergeCheap #-}
1495+mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (R.PatchDMap k (Event x)) -> Event x (DMap k Identity)
1496+mergeCheap d = Event $ \sub -> do
1489 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1497 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1490 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1498 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1491 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
1499 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
@@ -1660,7 +1668,7 @@ clearEventEnv (EventEnv toAssignRef holdInitRef mergeUpdateRef mergeInitRef toCl
1661-- | Run an event action outside of a frame
1669-- | Run an event action outside of a frame
1662runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
1670runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
1663−runFrame a = SpiderHost $ ask >>= \spiderTimeline -> lift $ do
1671+runFrame a = SpiderHost $ ask >>= \_ -> lift $ do
1664 let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimeline x)
1672 let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimeline x)
1665 let go = do
1673 let go = do
1666 result <- a
1674 result <- a
@@ -1822,7 +1830,7 @@ data Global
1823{-# NOINLINE globalSpiderTimeline #-}
1831{-# NOINLINE globalSpiderTimeline #-}
1824globalSpiderTimeline :: SpiderTimeline Global
1832globalSpiderTimeline :: SpiderTimeline Global
1825−globalSpiderTimeline = unsafePerformIO unsafeNewSpiderTimeline
1833+!globalSpiderTimeline = unsafePerformIO unsafeNewSpiderTimeline
1827-- | Stores all global data relevant to a particular Spider timeline; only one
1835-- | Stores all global data relevant to a particular Spider timeline; only one
1828-- value should exist for each type @x@
1836-- value should exist for each type @x@
@@ -1887,6 +1895,7 @@ instance HasSpiderTimeline x => Monad (R.Dynamic (SpiderTimeline x)) where
1887 fail _ = error "Dynamic does not support 'fail'"
1895 fail _ = error "Dynamic does not support 'fail'"
1889instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
1897instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
1898+ {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
1890 newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
1899 newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
1891 newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
1900 newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
1892 newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: Dynamic x (Identity a) } -- deriving (Functor, Applicative, Monad)
1901 newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: Dynamic x (Identity a) } -- deriving (Functor, Applicative, Monad)
@@ -1897,7 +1906,7 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
1897 never = SpiderEvent eventNever
1906 never = SpiderEvent eventNever
1898 {-# INLINABLE constant #-}
1907 {-# INLINABLE constant #-}
1899 constant = SpiderBehavior . behaviorConst
1908 constant = SpiderBehavior . behaviorConst
1900− {-# INLINABLE push #-}
1909+ {-# INLINE push #-}
1901 push f = SpiderEvent . push (coerce f) . unSpiderEvent
1910 push f = SpiderEvent . push (coerce f) . unSpiderEvent
1902 {-# INLINABLE pull #-}
1911 {-# INLINABLE pull #-}
1903 pull = SpiderBehavior . pull . coerce
1912 pull = SpiderBehavior . pull . coerce
@@ -1964,11 +1973,11 @@ instance HasSpiderTimeline x => R.MonadSample (SpiderTimeline x) (SpiderHost x)
1964 {-# INLINABLE sample #-}
1973 {-# INLINABLE sample #-}
1965 sample = runFrame . readBehaviorUntracked . unSpiderBehavior
1974 sample = runFrame . readBehaviorUntracked . unSpiderBehavior
1967−instance HasSpiderTimeline x => R.MonadSample (SpiderTimeline x) (SpiderPullM x) where
1976+instance R.MonadSample (SpiderTimeline x) (SpiderPullM x) where
1968 {-# INLINABLE sample #-}
1977 {-# INLINABLE sample #-}
1969 sample = coerce . readBehaviorTracked . unSpiderBehavior
1978 sample = coerce . readBehaviorTracked . unSpiderBehavior
1971−instance HasSpiderTimeline x => R.MonadSample (SpiderTimeline x) (SpiderPushM x) where
1980+instance R.MonadSample (SpiderTimeline x) (SpiderPushM x) where
1972 {-# INLINABLE sample #-}
1981 {-# INLINABLE sample #-}
1973 sample (SpiderBehavior b) = SpiderPushM $ readBehaviorUntracked b
1982 sample (SpiderBehavior b) = SpiderPushM $ readBehaviorUntracked b