@@ -38,11 +38,12 @@ import Control.Monad hiding (forM, forM_, mapM, mapM_)
38import Control.Monad.Exception
38import Control.Monad.Exception
39import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
39import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
40import Control.Monad.Primitive
40import Control.Monad.Primitive
41−--import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_)
42import Control.Monad.Reader.Class
41import Control.Monad.Reader.Class
43import Control.Monad.IO.Class
42import Control.Monad.IO.Class
44import Control.Monad.ReaderIO
43import Control.Monad.ReaderIO
45import Control.Monad.Ref
44import Control.Monad.Ref
45+import Control.Monad.Fail (MonadFail)
46+import qualified Control.Monad.Fail as MonadFail
46import Data.Align
47import Data.Align
47import Data.Coerce
48import Data.Coerce
48import Data.Dependent.Map (DMap, DSum (..))
49import Data.Dependent.Map (DMap, DSum (..))
@@ -59,12 +60,13 @@ import qualified Data.IntMap.Strict as IntMap
59import Data.IORef
60import Data.IORef
60import Data.Kind (Type)
61import Data.Kind (Type)
61import Data.Maybe hiding (mapMaybe)
62import Data.Maybe hiding (mapMaybe)
62−import Data.Monoid ((<>))
63+import Data.Monoid (mempty, (<>))
63import Data.Proxy
64import Data.Proxy
64import Data.These
65import Data.These
65import Data.Traversable
66import Data.Traversable
67+import Data.Type.Equality ((:~:)(Refl))
66import Data.Witherable (Filterable, mapMaybe)
68import Data.Witherable (Filterable, mapMaybe)
67−import GHC.Exts
69+import GHC.Exts hiding (toList)
68import GHC.IORef (IORef (..))
70import GHC.IORef (IORef (..))
69import GHC.Stack
71import GHC.Stack
70import Reflex.FastWeak
72import Reflex.FastWeak
@@ -83,14 +85,16 @@ import Data.Zip (Zip (..))
84#ifdef DEBUG_CYCLES
86#ifdef DEBUG_CYCLES
85import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
87import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
86import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
90import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
87import qualified Data.List.NonEmpty as NonEmpty
91import qualified Data.List.NonEmpty as NonEmpty
88−import Data.Monoid (mempty)
89import Data.Tree (Forest, Tree (..), drawForest)
92import Data.Tree (Forest, Tree (..), drawForest)
90−#endif
93+import Data.List (isPrefixOf)
92−import Data.FastWeakBag (FastWeakBag)
95+import Data.FastWeakBag (FastWeakBag, FastWeakBagTicket)
93import qualified Data.FastWeakBag as FastWeakBag
96import qualified Data.FastWeakBag as FastWeakBag
94import Data.Reflection
98import Data.Reflection
95import Data.Some (Some(Some))
99import Data.Some (Some(Some))
96import Data.Type.Coercion
100import Data.Type.Coercion
@@ -101,20 +105,26 @@ import qualified Reflex.Class
101import qualified Reflex.Class as R
105import qualified Reflex.Class as R
102import qualified Reflex.Host.Class
106import qualified Reflex.Host.Class
103import Reflex.NotReady.Class
107import Reflex.NotReady.Class
104−import Reflex.Patch
108+import Data.Patch
105−import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
109+import qualified Data.Patch.DMapWithMove as PatchDMapWithMove
110+import Reflex.PerformEvent.Base (PerformEventT)
107#ifdef DEBUG_TRACE_EVENTS
112#ifdef DEBUG_TRACE_EVENTS
108import qualified Data.ByteString.Char8 as BS8
113import qualified Data.ByteString.Char8 as BS8
109import System.IO (stderr)
114import System.IO (stderr)
115+import Data.List (isPrefixOf)
112−#ifdef DEBUG_TRACE_EVENTS
118+-- TODO stdout might not be the best channel for debug output
119+debugStrLn :: String -> IO ()
120+debugStrLn = putStrLn
122+#ifdef DEBUG_TRACE_EVENTS
114withStackOneLine :: (BS8.ByteString -> a) -> a
123withStackOneLine :: (BS8.ByteString -> a) -> a
115withStackOneLine expr = unsafePerformIO $ do
124withStackOneLine expr = unsafePerformIO $ do
116 stack <- currentCallStack
125 stack <- currentCallStack
117− return (expr (BS8.pack (unwords (reverse stack))))
126+ return (expr . BS8.pack . unwords . dropInternal . reverse $ stack)
127+ where dropInternal = filterStack "Reflex.Spider.Internal"
@@ -125,28 +135,42 @@ debugInvalidateHeight :: Bool
125debugInvalidate :: Bool
135debugInvalidate :: Bool
127#ifdef DEBUG
137#ifdef DEBUG
129#define DEBUG_NODEIDS
138#define DEBUG_NODEIDS
140+#ifdef DEBUG_TRACE_PROPAGATION
131debugPropagate = True
141debugPropagate = True
143+debugPropagate = False
146+#ifdef DEBUG_TRACE_HEIGHT
147+debugInvalidateHeight = True
133debugInvalidateHeight = False
149debugInvalidateHeight = False
152+#ifdef DEBUG_TRACE_INVALIDATION
135debugInvalidate = True
153debugInvalidate = True
155+debugInvalidate = False
137class HasNodeId a where
158class HasNodeId a where
138 getNodeId :: a -> Int
159 getNodeId :: a -> Int
140−instance HasNodeId (Hold x p a) where
161+instance HasNodeId (CacheSubscribed x a) where
141− getNodeId = holdNodeId
162+ getNodeId = _cacheSubscribed_nodeId
143−instance HasNodeId (PushSubscribed x a b) where
164+instance HasNodeId (FanInt x a) where
144− getNodeId = pushSubscribedNodeId
165+ getNodeId = _fanInt_nodeId
167+instance HasNodeId (Hold x p) where
168+ getNodeId = holdNodeId
146instance HasNodeId (SwitchSubscribed x a) where
170instance HasNodeId (SwitchSubscribed x a) where
147 getNodeId = switchSubscribedNodeId
171 getNodeId = switchSubscribedNodeId
149−instance HasNodeId (FanSubscribed x a) where
173+instance HasNodeId (FanSubscribed x v a) where
150 getNodeId = fanSubscribedNodeId
174 getNodeId = fanSubscribedNodeId
152instance HasNodeId (CoincidenceSubscribed x a) where
176instance HasNodeId (CoincidenceSubscribed x a) where
@@ -160,41 +184,16 @@ instance HasNodeId (Pull x a) where
161{-# INLINE showNodeId #-}
185{-# INLINE showNodeId #-}
162showNodeId :: HasNodeId a => a -> String
186showNodeId :: HasNodeId a => a -> String
163−showNodeId = ("#"<>) . show . getNodeId
187+showNodeId = showNodeId' . getNodeId
165−showSubscriberType :: Subscriber x a -> String
189+showNodeId' :: Int -> String
166−showSubscriberType = \case
190+showNodeId' = ("#"<>) . show
167− SubscriberPush _ _ -> "SubscriberPush"
191+
168− SubscriberMerge _ _ -> "SubscriberMerge"
169− SubscriberFan _ -> "SubscriberFan"
170− SubscriberMergeChange _ -> "SubscriberMergeChange"
171− SubscriberHold _ -> "SubscriberHold"
172− SubscriberHoldIdentity _ -> "SubscriberHoldIdentity"
173− SubscriberSwitch _ -> "SubscriberSwitch"
174− SubscriberCoincidenceOuter _ -> "SubscriberCoincidenceOuter"
175− SubscriberCoincidenceInner _ -> "SubscriberCoincidenceInner"
176− SubscriberHandle -> "SubscriberHandle"
178−showEventType :: Event x a -> String
179−showEventType = \case
180− EventRoot _ _ -> "EventRoot"
181− EventNever -> "EventNever"
182− EventPush _ -> "EventPush"
183− EventMerge _ -> "EventMerge"
184− EventFan _ _ -> "EventFan"
185− EventSwitch _ -> "EventSwitch"
186− EventCoincidence _ -> "EventCoincidence"
187− EventHold _ -> "EventHold"
188− EventDyn _ -> "EventDyn"
189− EventHoldIdentity _ -> "EventHoldIdentity"
190− EventDynIdentity _ -> "EventDynIdentity"
194debugPropagate = False
195debugPropagate = False
196debugInvalidateHeight = False
196debugInvalidateHeight = False
198debugInvalidate = False
197debugInvalidate = False
200-- This must be inline, or error messages will cause memory leaks due to retaining the node in question
199-- This must be inline, or error messages will cause memory leaks due to retaining the node in question
@@ -202,6 +201,10 @@ debugInvalidate = False
202showNodeId :: a -> String
201showNodeId :: a -> String
203showNodeId _ = ""
202showNodeId _ = ""
204+{-# INLINE showNodeId' #-}
205+showNodeId' :: Int -> String
207#ifdef DEBUG_NODEIDS
210#ifdef DEBUG_NODEIDS
@@ -247,9 +250,9 @@ subscribeAndRead = unEvent
247-- caching; if the computation function is very cheap, this is (much) more
250-- caching; if the computation function is very cheap, this is (much) more
248-- efficient than 'push'
251-- efficient than 'push'
249{-# INLINE [1] pushCheap #-}
252{-# INLINE [1] pushCheap #-}
250−pushCheap :: (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
253+pushCheap :: HasSpiderTimeline x => (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
251pushCheap !f e = Event $ \sub -> do
254pushCheap !f e = Event $ \sub -> do
252− (subscription, occ) <- subscribeAndRead e $ sub
255+ (subscription, occ) <- subscribeAndRead e $ debugSubscriber' "push" $ sub
253 { subscriberPropagate = \a -> do
256 { subscriberPropagate = \a -> do
254 mb <- f a
257 mb <- f a
255 mapM_ (subscriberPropagate sub) mb
258 mapM_ (subscriberPropagate sub) mb
@@ -268,10 +271,10 @@ terminalSubscriber p = Subscriber
269-- | Subscribe to an Event only for the duration of one occurrence
272-- | Subscribe to an Event only for the duration of one occurrence
270{-# INLINE subscribeAndReadHead #-}
273{-# INLINE subscribeAndReadHead #-}
271−subscribeAndReadHead :: Event x a -> Subscriber x a -> EventM x (EventSubscription x, Maybe a)
274+subscribeAndReadHead :: HasSpiderTimeline x => Event x a -> Subscriber x a -> EventM x (EventSubscription x, Maybe a)
272subscribeAndReadHead e sub = do
275subscribeAndReadHead e sub = do
273 subscriptionRef <- liftIO $ newIORef $ error "subscribeAndReadHead: not initialized"
276 subscriptionRef <- liftIO $ newIORef $ error "subscribeAndReadHead: not initialized"
274− (subscription, occ) <- subscribeAndRead e $ sub
277+ (subscription, occ) <- subscribeAndRead e $ debugSubscriber' "head" $ sub
275 { subscriberPropagate = \a -> do
278 { subscriberPropagate = \a -> do
276 liftIO $ unsubscribe =<< readIORef subscriptionRef
279 liftIO $ unsubscribe =<< readIORef subscriptionRef
277 subscriberPropagate sub a
280 subscriberPropagate sub a
@@ -282,24 +285,29 @@ subscribeAndReadHead e sub = do
282 return (subscription, occ)
285 return (subscription, occ)
284--TODO: Make this lazy in its input event
287--TODO: Make this lazy in its input event
285−headE :: (MonadIO m, Defer (SomeMergeInit x) m) => Event x a -> m (Event x a)
288+headE :: (MonadIO m, Defer (SomeMergeInit x) m, HasSpiderTimeline x) => Event x a -> m (Event x a)
286headE originalE = do
289headE originalE = do
287 parent <- liftIO $ newIORef $ Just originalE
290 parent <- liftIO $ newIORef $ Just originalE
288 defer $ SomeMergeInit $ do --TODO: Rename SomeMergeInit appropriately
291 defer $ SomeMergeInit $ do --TODO: Rename SomeMergeInit appropriately
289 let clearParent = liftIO $ writeIORef parent Nothing
292 let clearParent = liftIO $ writeIORef parent Nothing
290− (_, occ) <- subscribeAndReadHead originalE $ terminalSubscriber $ \_ -> clearParent
293+ (_, occ) <- subscribeAndReadHead originalE $ terminalSubscriber $ const clearParent
291 when (isJust occ) clearParent
294 when (isJust occ) clearParent
292− return $ Event $ \sub -> do
295+ return $ Event $ \sub ->
293 liftIO (readIORef parent) >>= \case
296 liftIO (readIORef parent) >>= \case
294− Nothing -> return (EventSubscription (return ()) $ EventSubscribed zeroRef $ toAny (), Nothing)
297+ Nothing -> subscribeAndReadNever
295 Just e -> subscribeAndReadHead e sub
298 Just e -> subscribeAndReadHead e sub
297data CacheSubscribed x a
300data CacheSubscribed x a
298 = CacheSubscribed { _cacheSubscribed_subscribers :: {-# UNPACK #-} !(FastWeakBag (Subscriber x a))
301 = CacheSubscribed { _cacheSubscribed_subscribers :: {-# UNPACK #-} !(FastWeakBag (Subscriber x a))
299 , _cacheSubscribed_parent :: {-# UNPACK #-} !(EventSubscription x)
302 , _cacheSubscribed_parent :: {-# UNPACK #-} !(EventSubscription x)
300 , _cacheSubscribed_occurrence :: {-# UNPACK #-} !(IORef (Maybe a))
303 , _cacheSubscribed_occurrence :: {-# UNPACK #-} !(IORef (Maybe a))
305+ , _cacheSubscribed_nodeId :: {-# UNPACK #-} !Int
303-- | Construct an 'Event' whose value is guaranteed not to be recomputed
311-- | Construct an 'Event' whose value is guaranteed not to be recomputed
304-- repeatedly
312-- repeatedly
@@ -324,18 +332,23 @@ cacheEvent e =
324 subscribedTicket <- liftIO (readIORef mSubscribedRef >>= getFastWeakTicket) >>= \case
332 subscribedTicket <- liftIO (readIORef mSubscribedRef >>= getFastWeakTicket) >>= \case
325 Just subscribedTicket -> return subscribedTicket
333 Just subscribedTicket -> return subscribedTicket
326 Nothing -> do
334 Nothing -> do
336+ nodeId <- liftIO newNodeId
327 subscribers <- liftIO FastWeakBag.empty
338 subscribers <- liftIO FastWeakBag.empty
328 occRef <- liftIO $ newIORef Nothing -- This should never be read prior to being set below
339 occRef <- liftIO $ newIORef Nothing -- This should never be read prior to being set below
341+ (parentSub, occ) <- subscribeAndRead e $ debugSubscriber' ("cacheEvent" <> showNodeId' nodeId) $ Subscriber
329 (parentSub, occ) <- subscribeAndRead e $ Subscriber
343 (parentSub, occ) <- subscribeAndRead e $ Subscriber
330− { subscriberPropagate = \a -> do
345+ { subscriberPropagate = \a -> do
331− liftIO $ writeIORef occRef $ Just a
346+ liftIO $ writeIORef occRef (Just a)
332− scheduleClear occRef
347+ scheduleClear occRef
333− propagateFast a subscribers
348+ propagateFast a subscribers
334− , subscriberInvalidateHeight = \old -> do
335− FastWeakBag.traverse subscribers $ invalidateSubscriberHeight old
349+ , subscriberInvalidateHeight = FastWeakBag.traverse_ subscribers . invalidateSubscriberHeight
336− , subscriberRecalculateHeight = \new -> do
337− FastWeakBag.traverse subscribers $ recalculateSubscriberHeight new
350+ , subscriberRecalculateHeight = FastWeakBag.traverse_ subscribers . recalculateSubscriberHeight
339 when (isJust occ) $ do
352 when (isJust occ) $ do
340 liftIO $ writeIORef occRef occ -- Set the initial value of occRef; we don't need to do this if occ is Nothing
353 liftIO $ writeIORef occRef occ -- Set the initial value of occRef; we don't need to do this if occ is Nothing
341 scheduleClear occRef
354 scheduleClear occRef
@@ -343,29 +356,45 @@ cacheEvent e =
343 { _cacheSubscribed_subscribers = subscribers
356 { _cacheSubscribed_subscribers = subscribers
344 , _cacheSubscribed_parent = parentSub
357 , _cacheSubscribed_parent = parentSub
345 , _cacheSubscribed_occurrence = occRef
358 , _cacheSubscribed_occurrence = occRef
360+ , _cacheSubscribed_nodeId = nodeId
347 subscribedTicket <- liftIO $ mkFastWeakTicket subscribed
363 subscribedTicket <- liftIO $ mkFastWeakTicket subscribed
348 liftIO $ writeIORef mSubscribedRef =<< getFastWeakTicketWeak subscribedTicket
364 liftIO $ writeIORef mSubscribedRef =<< getFastWeakTicketWeak subscribedTicket
349 return subscribedTicket
365 return subscribedTicket
350− liftIO $ do
366+ liftIO $ cacheSubscription sub mSubscribedRef subscribedTicket
368+cacheSubscription :: Subscriber x a -> IORef (FastWeak (CacheSubscribed x a))
369+ -> FastWeakTicket (CacheSubscribed x a) -> IO (EventSubscription x, Maybe a)
370+cacheSubscription sub mSubscribedRef subscribedTicket = do
351− subscribed <- getFastWeakTicketValue subscribedTicket
371+ subscribed <- getFastWeakTicketValue subscribedTicket
352− ticket <- FastWeakBag.insert sub $ _cacheSubscribed_subscribers subscribed
372+ ticket <- FastWeakBag.insert sub $ _cacheSubscribed_subscribers subscribed
353− occ <- readIORef $ _cacheSubscribed_occurrence subscribed
373+ occ <- readIORef $ _cacheSubscribed_occurrence subscribed
375+ let parentSub = _cacheSubscribed_parent subscribed
354− let es = EventSubscription
376+ es = EventSubscription
355− { _eventSubscription_unsubscribe = do
377+ { _eventSubscription_unsubscribe = do
356− FastWeakBag.remove ticket
378+ FastWeakBag.remove ticket
357− isEmpty <- FastWeakBag.isEmpty $ _cacheSubscribed_subscribers subscribed
380+ isEmpty <- FastWeakBag.isEmpty $ _cacheSubscribed_subscribers subscribed
358− when isEmpty $ do
381+ when isEmpty $ do
359− writeIORef mSubscribedRef emptyFastWeak
382+ writeIORef mSubscribedRef emptyFastWeak
360− unsubscribe $ _cacheSubscribed_parent subscribed
383+ unsubscribe parentSub
361− touch ticket
384+ touch ticket
362− touch subscribedTicket
385+ touch subscribedTicket
363− , _eventSubscription_subscribed = EventSubscribed
386+ , _eventSubscription_subscribed = EventSubscribed
364− { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ _cacheSubscribed_parent subscribed
387+ { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed parentSub
365− , eventSubscribedRetained = toAny subscribedTicket
388+ , eventSubscribedRetained = toAny subscribedTicket
390+ , eventSubscribedGetParents = return [_eventSubscription_subscribed parentSub]
391+ , eventSubscribedHasOwnHeightRef = False
392+ , eventSubscribedWhoCreated = whoCreatedIORef mSubscribedRef
368− return (es, occ)
396+ return (es, occ)
370subscribe :: Event x a -> Subscriber x a -> EventM x (EventSubscription x)
399subscribe :: Event x a -> Subscriber x a -> EventM x (EventSubscription x)
371subscribe e s = fst <$> subscribeAndRead e s
400subscribe e s = fst <$> subscribeAndRead e s
@@ -377,11 +406,14 @@ wrap tag getSpecificSubscribed sub = do
377 let es = tag subd
406 let es = tag subd
378 return (EventSubscription (WeakBag.remove sln >> touch sln) es, occ)
407 return (EventSubscription (WeakBag.remove sln >> touch sln) es, occ)
380−eventRoot :: GCompare k => k a -> Root x k -> Event x a
409+eventRoot :: (GCompare k, HasSpiderTimeline x) => k a -> Root x k -> Event x a
381eventRoot !k !r = Event $ wrap eventSubscribedRoot $ liftIO . getRootSubscribed k r
410eventRoot !k !r = Event $ wrap eventSubscribedRoot $ liftIO . getRootSubscribed k r
412+subscribeAndReadNever :: EventM x (EventSubscription x, Maybe a)
413+subscribeAndReadNever = return (EventSubscription (return ()) eventSubscribedNever, Nothing)
383eventNever :: Event x a
415eventNever :: Event x a
384−eventNever = Event $ \_ -> return (EventSubscription (return ()) eventSubscribedNever, Nothing)
416+eventNever = Event $ const subscribeAndReadNever
386eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k v -> Event x (v a)
418eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k v -> Event x (v a)
387eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
419eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
@@ -436,10 +468,10 @@ newSubscriberHold h = return $ Subscriber
438newSubscriberFan :: forall x k v. (HasSpiderTimeline x, GCompare k) => FanSubscribed x k v -> IO (Subscriber x (DMap k v))
470newSubscriberFan :: forall x k v. (HasSpiderTimeline x, GCompare k) => FanSubscribed x k v -> IO (Subscriber x (DMap k v))
439−newSubscriberFan subscribed = return $ Subscriber
471+newSubscriberFan subscribed = debugSubscriber ("SubscriberFan " <> showNodeId subscribed) $ Subscriber
440 { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
472 { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
441 subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
473 subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
442− tracePropagate (Proxy :: Proxy x) $ "SubscriberFan" <> showNodeId subscribed <> ": " ++ show (DMap.size subs) ++ " keys subscribed, " ++ show (DMap.size a) ++ " keys firing"
474+ tracePropagate (Proxy :: Proxy x) $ show (DMap.size subs) <> " keys subscribed, " <> show (DMap.size a) <> " keys firing"
443 liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
475 liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
444 scheduleClear $ fanSubscribedOccurrence subscribed
476 scheduleClear $ fanSubscribedOccurrence subscribed
445 let f _ (Pair v subsubs) = do
477 let f _ (Pair v subsubs) = do
@@ -448,72 +480,55 @@ newSubscriberFan subscribed = return $ Subscriber
448 _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
480 _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
449 return ()
481 return ()
450 , subscriberInvalidateHeight = \old -> do
482 , subscriberInvalidateHeight = \old -> do
451− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
452 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
483 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
453− forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse (_fanSubscribedChildren_list v) $ invalidateSubscriberHeight old
484+ forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse_ (_fanSubscribedChildren_list v) $ invalidateSubscriberHeight old
454− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
455 , subscriberRecalculateHeight = \new -> do
485 , subscriberRecalculateHeight = \new -> do
456− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
457 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
486 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
458− forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse (_fanSubscribedChildren_list v) $ recalculateSubscriberHeight new
487+ forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse_ (_fanSubscribedChildren_list v) $ recalculateSubscriberHeight new
459− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
462newSubscriberSwitch :: forall x a. HasSpiderTimeline x => SwitchSubscribed x a -> IO (Subscriber x a)
490newSubscriberSwitch :: forall x a. HasSpiderTimeline x => SwitchSubscribed x a -> IO (Subscriber x a)
463−newSubscriberSwitch subscribed = return $ Subscriber
491+newSubscriberSwitch subscribed = debugSubscriber ("SubscriberCoincidenceOuter" <> showNodeId subscribed) $ Subscriber
464 { subscriberPropagate = \a -> {-# SCC "traverseSwitch" #-} do
492 { subscriberPropagate = \a -> {-# SCC "traverseSwitch" #-} do
465− tracePropagate (Proxy :: Proxy x) $ "SubscriberSwitch" <> showNodeId subscribed
466 liftIO $ writeIORef (switchSubscribedOccurrence subscribed) $ Just a
493 liftIO $ writeIORef (switchSubscribedOccurrence subscribed) $ Just a
467 scheduleClear $ switchSubscribedOccurrence subscribed
494 scheduleClear $ switchSubscribedOccurrence subscribed
468 propagate a $ switchSubscribedSubscribers subscribed
495 propagate a $ switchSubscribedSubscribers subscribed
469 , subscriberInvalidateHeight = \_ -> do
496 , subscriberInvalidateHeight = \_ -> do
470− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed
471 oldHeight <- readIORef $ switchSubscribedHeight subscribed
497 oldHeight <- readIORef $ switchSubscribedHeight subscribed
472 when (oldHeight /= invalidHeight) $ do
498 when (oldHeight /= invalidHeight) $ do
473 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
499 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
474− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
500+ WeakBag.traverse_ (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
475− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed <> " done"
476− , subscriberRecalculateHeight = \new -> do
501+ , subscriberRecalculateHeight = (`updateSwitchHeight` subscribed)
477− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed
478− updateSwitchHeight new subscribed
479− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed <> " done"
482newSubscriberCoincidenceOuter :: forall x b. HasSpiderTimeline x => CoincidenceSubscribed x b -> IO (Subscriber x (Event x b))
504newSubscriberCoincidenceOuter :: forall x b. HasSpiderTimeline x => CoincidenceSubscribed x b -> IO (Subscriber x (Event x b))
483−newSubscriberCoincidenceOuter subscribed = return $ Subscriber
505+newSubscriberCoincidenceOuter subscribed = debugSubscriber ("SubscriberCoincidenceOuter" <> showNodeId subscribed) $ Subscriber
484 { subscriberPropagate = \a -> {-# SCC "traverseCoincidenceOuter" #-} do
506 { subscriberPropagate = \a -> {-# SCC "traverseCoincidenceOuter" #-} do
485− tracePropagate (Proxy :: Proxy x) $ "SubscriberCoincidenceOuter" <> showNodeId subscribed
486 outerHeight <- liftIO $ readIORef $ coincidenceSubscribedHeight subscribed
507 outerHeight <- liftIO $ readIORef $ coincidenceSubscribedHeight subscribed
487 tracePropagate (Proxy :: Proxy x) $ " outerHeight = " <> show outerHeight
508 tracePropagate (Proxy :: Proxy x) $ " outerHeight = " <> show outerHeight
488 (occ, innerHeight, innerSubd) <- subscribeCoincidenceInner a outerHeight subscribed
509 (occ, innerHeight, innerSubd) <- subscribeCoincidenceInner a outerHeight subscribed
489 tracePropagate (Proxy :: Proxy x) $ " isJust occ = " <> show (isJust occ)
510 tracePropagate (Proxy :: Proxy x) $ " isJust occ = " <> show (isJust occ)
490 tracePropagate (Proxy :: Proxy x) $ " innerHeight = " <> show innerHeight
511 tracePropagate (Proxy :: Proxy x) $ " innerHeight = " <> show innerHeight
491 liftIO $ writeIORef (coincidenceSubscribedInnerParent subscribed) $ Just innerSubd
513 liftIO $ writeIORef (coincidenceSubscribedInnerParent subscribed) $ Just innerSubd
492 scheduleClear $ coincidenceSubscribedInnerParent subscribed
514 scheduleClear $ coincidenceSubscribedInnerParent subscribed
493 case occ of
515 case occ of
494− Nothing -> do
516+ Nothing ->
495 when (innerHeight > outerHeight) $ liftIO $ do -- If the event fires, it will fire at a later height
517 when (innerHeight > outerHeight) $ liftIO $ do -- If the event fires, it will fire at a later height
496 writeIORef (coincidenceSubscribedHeight subscribed) $! innerHeight
518 writeIORef (coincidenceSubscribedHeight subscribed) $! innerHeight
497− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight outerHeight
519+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight outerHeight
498− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight innerHeight
520+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight innerHeight
499 Just o -> do -- Since it's already firing, no need to adjust height
521 Just o -> do -- Since it's already firing, no need to adjust height
500 liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) occ
522 liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) occ
501 scheduleClear $ coincidenceSubscribedOccurrence subscribed
523 scheduleClear $ coincidenceSubscribedOccurrence subscribed
502 propagate o $ coincidenceSubscribedSubscribers subscribed
524 propagate o $ coincidenceSubscribedSubscribers subscribed
503− , subscriberInvalidateHeight = \_ -> do
504− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed
505− invalidateCoincidenceHeight subscribed
525+ , subscriberInvalidateHeight = \_ -> invalidateCoincidenceHeight subscribed
506− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed <> " done"
507− , subscriberRecalculateHeight = \_ -> do
508− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed
509− recalculateCoincidenceHeight subscribed
526+ , subscriberRecalculateHeight = \_ -> recalculateCoincidenceHeight subscribed
510− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed <> " done"
513newSubscriberCoincidenceInner :: forall x a. HasSpiderTimeline x => CoincidenceSubscribed x a -> IO (Subscriber x a)
529newSubscriberCoincidenceInner :: forall x a. HasSpiderTimeline x => CoincidenceSubscribed x a -> IO (Subscriber x a)
514−newSubscriberCoincidenceInner subscribed = return $ Subscriber
530+newSubscriberCoincidenceInner subscribed = debugSubscriber ("SubscriberCoincidenceInner" <> showNodeId subscribed) $ Subscriber
515 { subscriberPropagate = \a -> {-# SCC "traverseCoincidenceInner" #-} do
531 { subscriberPropagate = \a -> {-# SCC "traverseCoincidenceInner" #-} do
516− tracePropagate (Proxy :: Proxy x) $ "SubscriberCoincidenceInner" <> showNodeId subscribed
517 occ <- liftIO $ readIORef $ coincidenceSubscribedOccurrence subscribed
532 occ <- liftIO $ readIORef $ coincidenceSubscribedOccurrence subscribed
518 case occ of
533 case occ of
519 Just _ -> return () -- SubscriberCoincidenceOuter must have already propagated this event
534 Just _ -> return () -- SubscriberCoincidenceOuter must have already propagated this event
@@ -521,14 +536,8 @@ newSubscriberCoincidenceInner subscribed = return $ Subscriber
521 liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) $ Just a
536 liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) $ Just a
522 scheduleClear $ coincidenceSubscribedOccurrence subscribed
537 scheduleClear $ coincidenceSubscribedOccurrence subscribed
523 propagate a $ coincidenceSubscribedSubscribers subscribed
538 propagate a $ coincidenceSubscribedSubscribers subscribed
524− , subscriberInvalidateHeight = \_ -> do
525− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed
526− invalidateCoincidenceHeight subscribed
539+ , subscriberInvalidateHeight = \_ -> invalidateCoincidenceHeight subscribed
527− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed <> " done"
528− , subscriberRecalculateHeight = \_ -> do
529− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed
530− recalculateCoincidenceHeight subscribed
540+ , subscriberRecalculateHeight = \_ -> recalculateCoincidenceHeight subscribed
531− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed <> " done"
534invalidateSubscriberHeight :: Height -> Subscriber x a -> IO ()
543invalidateSubscriberHeight :: Height -> Subscriber x a -> IO ()
@@ -538,18 +547,18 @@ recalculateSubscriberHeight :: Height -> Subscriber x a -> IO ()
538recalculateSubscriberHeight = flip subscriberRecalculateHeight
547recalculateSubscriberHeight = flip subscriberRecalculateHeight
540-- | Propagate everything at the current height
549-- | Propagate everything at the current height
541−propagate :: a -> WeakBag (Subscriber x a) -> EventM x ()
550+propagate :: forall x a. HasSpiderTimeline x => a -> WeakBag (Subscriber x a) -> EventM x ()
542−propagate a subscribers = withIncreasedDepth $ do
551+propagate a subscribers = withIncreasedDepth (Proxy::Proxy x) $
543 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
552 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
544 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
553 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
545− WeakBag.traverse subscribers $ \s -> subscriberPropagate s a
554+ WeakBag.traverse_ subscribers $ \s -> subscriberPropagate s a
547-- | Propagate everything at the current height
556-- | Propagate everything at the current height
548−propagateFast :: a -> FastWeakBag (Subscriber x a) -> EventM x ()
557+propagateFast :: forall x a. HasSpiderTimeline x => a -> FastWeakBag (Subscriber x a) -> EventM x ()
549−propagateFast a subscribers = withIncreasedDepth $ do
558+propagateFast a subscribers = withIncreasedDepth (Proxy::Proxy x) $
550 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
559 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
551 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
560 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
552− FastWeakBag.traverse subscribers $ \s -> subscriberPropagate s a
561+ FastWeakBag.traverse_ subscribers $ \s -> subscriberPropagate s a
554--------------------------------------------------------------------------------
563--------------------------------------------------------------------------------
555-- EventSubscribed
564-- EventSubscribed
@@ -567,7 +576,7 @@ data EventSubscribed x = EventSubscribed
567 { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
576 { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
568 , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
577 , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
569#ifdef DEBUG_CYCLES
578#ifdef DEBUG_CYCLES
570− , eventSubscribedGetParents :: !(IO [Some (EventSubscribed x)]) -- For debugging loops
579+ , eventSubscribedGetParents :: !(IO [EventSubscribed x]) -- For debugging loops
571 , eventSubscribedHasOwnHeightRef :: !Bool
580 , eventSubscribedHasOwnHeightRef :: !Bool
572 , eventSubscribedWhoCreated :: !(IO [String])
581 , eventSubscribedWhoCreated :: !(IO [String])
@@ -600,7 +609,7 @@ eventSubscribedFan !subscribed = EventSubscribed
600 { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
609 { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
601 , eventSubscribedRetained = toAny subscribed
610 , eventSubscribedRetained = toAny subscribed
602#ifdef DEBUG_CYCLES
611#ifdef DEBUG_CYCLES
603− , eventSubscribedGetParents = return [Some $ _eventSubscription_subscribed $ fanSubscribedParent subscribed]
612+ , eventSubscribedGetParents = return [_eventSubscription_subscribed $ fanSubscribedParent subscribed]
604 , eventSubscribedHasOwnHeightRef = False
613 , eventSubscribedHasOwnHeightRef = False
605 , eventSubscribedWhoCreated = whoCreatedIORef $ fanSubscribedCachedSubscribed subscribed
614 , eventSubscribedWhoCreated = whoCreatedIORef $ fanSubscribedCachedSubscribed subscribed
@@ -613,7 +622,7 @@ eventSubscribedSwitch !subscribed = EventSubscribed
613#ifdef DEBUG_CYCLES
622#ifdef DEBUG_CYCLES
614 , eventSubscribedGetParents = do
623 , eventSubscribedGetParents = do
615 s <- readIORef $ switchSubscribedCurrentParent subscribed
624 s <- readIORef $ switchSubscribedCurrentParent subscribed
616− return [Some $ _eventSubscription_subscribed s]
625+ return [_eventSubscription_subscribed s]
617 , eventSubscribedHasOwnHeightRef = True
626 , eventSubscribedHasOwnHeightRef = True
618 , eventSubscribedWhoCreated = whoCreatedIORef $ switchSubscribedCachedSubscribed subscribed
627 , eventSubscribedWhoCreated = whoCreatedIORef $ switchSubscribedCachedSubscribed subscribed
@@ -626,8 +635,8 @@ eventSubscribedCoincidence !subscribed = EventSubscribed
626#ifdef DEBUG_CYCLES
635#ifdef DEBUG_CYCLES
627 , eventSubscribedGetParents = do
636 , eventSubscribedGetParents = do
628 innerSubscription <- readIORef $ coincidenceSubscribedInnerParent subscribed
637 innerSubscription <- readIORef $ coincidenceSubscribedInnerParent subscribed
629− let outerParent = Some $ _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
638+ let outerParent = _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
630− innerParents = maybeToList $ fmap Some innerSubscription
639+ innerParents = maybeToList $ innerSubscription
631 return $ outerParent : innerParents
640 return $ outerParent : innerParents
632 , eventSubscribedHasOwnHeightRef = True
641 , eventSubscribedHasOwnHeightRef = True
633 , eventSubscribedWhoCreated = whoCreatedIORef $ coincidenceSubscribedCachedSubscribed subscribed
642 , eventSubscribedWhoCreated = whoCreatedIORef $ coincidenceSubscribedCachedSubscribed subscribed
@@ -641,15 +650,15 @@ getEventSubscribedHeight es = readIORef $ eventSubscribedHeightRef es
641whoCreatedEventSubscribed :: EventSubscribed x -> IO [String]
650whoCreatedEventSubscribed :: EventSubscribed x -> IO [String]
642whoCreatedEventSubscribed = eventSubscribedWhoCreated
651whoCreatedEventSubscribed = eventSubscribedWhoCreated
644−walkInvalidHeightParents :: EventSubscribed x -> IO [Some (EventSubscribed x)]
653+walkInvalidHeightParents :: EventSubscribed x -> IO [EventSubscribed x]
645walkInvalidHeightParents s0 = do
654walkInvalidHeightParents s0 = do
646− subscribers <- flip execStateT mempty $ ($ Some s0) $ fix $ \loop (Some s) -> do
655+ subscribers <- flip execStateT mempty $ ($ s0) $ fix $ \loop s -> do
647 h <- liftIO $ readIORef $ eventSubscribedHeightRef s
656 h <- liftIO $ readIORef $ eventSubscribedHeightRef s
648 when (h == invalidHeight) $ do
657 when (h == invalidHeight) $ do
649 when (eventSubscribedHasOwnHeightRef s) $ liftIO $ writeIORef (eventSubscribedHeightRef s) $! invalidHeightBeingTraversed
658 when (eventSubscribedHasOwnHeightRef s) $ liftIO $ writeIORef (eventSubscribedHeightRef s) $! invalidHeightBeingTraversed
650− modify (Some s :)
659+ modify (s :)
651 mapM_ loop =<< liftIO (eventSubscribedGetParents s)
660 mapM_ loop =<< liftIO (eventSubscribedGetParents s)
652− forM_ subscribers $ \(Some s) -> writeIORef (eventSubscribedHeightRef s) $! invalidHeight
661+ forM_ subscribers $ \s -> writeIORef (eventSubscribedHeightRef s) $! invalidHeight
653 return subscribers
662 return subscribers
@@ -971,8 +980,10 @@ instance Monad (BehaviorM x) where
971 BehaviorM x >> BehaviorM y = BehaviorM $ x >> y
980 BehaviorM x >> BehaviorM y = BehaviorM $ x >> y
972 {-# INLINE return #-}
981 {-# INLINE return #-}
973 return x = BehaviorM $ return x
982 return x = BehaviorM $ return x
983+#if !MIN_VERSION_base(4,13,0)
974 {-# INLINE fail #-}
984 {-# INLINE fail #-}
975 fail s = BehaviorM $ fail s
985 fail s = BehaviorM $ fail s
977data BehaviorSubscribed x a
988data BehaviorSubscribed x a
978 = forall p. BehaviorSubscribedHold (Hold x p)
989 = forall p. BehaviorSubscribedHold (Hold x p)
@@ -1032,7 +1043,7 @@ data SomeMergeUpdate x = SomeMergeUpdate
1032newtype SomeMergeInit x = SomeMergeInit { unSomeMergeInit :: EventM x () }
1043newtype SomeMergeInit x = SomeMergeInit { unSomeMergeInit :: EventM x () }
1034-- EventM can do everything BehaviorM can, plus create holds
1045-- EventM can do everything BehaviorM can, plus create holds
1035−newtype EventM x a = EventM { unEventM :: IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadFix, 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
1046+newtype EventM x a = EventM { unEventM :: IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadException, MonadAsyncException)
1037newtype MergeSubscribedParent x a = MergeSubscribedParent { unMergeSubscribedParent :: EventSubscription x }
1048newtype MergeSubscribedParent x a = MergeSubscribedParent { unMergeSubscribedParent :: EventSubscription x }
@@ -1057,7 +1068,8 @@ heightBagFromList :: [Height] -> HeightBag
1057heightBagFromList heights = heightBagVerify $ foldl' (flip heightBagAdd) heightBagEmpty heights
1068heightBagFromList heights = heightBagVerify $ foldl' (flip heightBagAdd) heightBagEmpty heights
1059heightBagAdd :: Height -> HeightBag -> HeightBag
1070heightBagAdd :: Height -> HeightBag -> HeightBag
1060−heightBagAdd (Height h) (HeightBag s c) = heightBagVerify $ HeightBag (succ s) $ IntMap.insertWithKey (\_ _ old -> succ old) h 0 c
1071+heightBagAdd (Height h) (HeightBag s c) = heightBagVerify $ HeightBag (succ s) $
1072+ IntMap.insertWithKey (\_ _ old -> succ old) h 0 c
1062heightBagRemove :: Height -> HeightBag -> HeightBag
1074heightBagRemove :: Height -> HeightBag -> HeightBag
1063heightBagRemove (Height h) b@(HeightBag s c) = heightBagVerify $ case IntMap.lookup h c of
1075heightBagRemove (Height h) b@(HeightBag s c) = heightBagVerify $ case IntMap.lookup h c of
@@ -1066,6 +1078,13 @@ heightBagRemove (Height h) b@(HeightBag s c) = heightBagVerify $ case IntMap.loo
1066 0 -> IntMap.delete h c
1078 0 -> IntMap.delete h c
1067 _ -> IntMap.insert h (pred old) c
1079 _ -> IntMap.insert h (pred old) c
1081+heightBagRemoveMaybe :: Height -> HeightBag -> Maybe HeightBag
1082+heightBagRemoveMaybe (Height h) b@(HeightBag s c) = heightBagVerify . removed <$> IntMap.lookup h c where
1083+ removed old = HeightBag (pred s) $ case old of
1084+ 0 -> IntMap.delete h c
1085+ _ -> IntMap.insert h (pred old) c
1069heightBagMax :: HeightBag -> Height
1088heightBagMax :: HeightBag -> Height
1070heightBagMax (HeightBag _ c) = case IntMap.maxViewWithKey c of
1089heightBagMax (HeightBag _ c) = case IntMap.maxViewWithKey c of
1071 Just ((h, _), _) -> Height h
1090 Just ((h, _), _) -> Height h
@@ -1313,55 +1332,110 @@ mkWeakPtrWithDebug x debugNote = do
1313 x' <- evaluate x
1332 x' <- evaluate x
1314 mkWeakPtr x' $
1333 mkWeakPtr x' $
1315 if debugFinalize
1334 if debugFinalize
1316− then Just $ putStrLn $ "finalizing: " ++ debugNote
1335+ then Just $ debugStrLn $ "finalizing: " ++ debugNote
1317 else Nothing
1336 else Nothing
1319type WeakList a = [Weak a]
1338type WeakList a = [Weak a]
1321−{-# INLINE withIncreasedDepth #-}
1340+type CanTrace x m = (HasSpiderTimeline x, MonadIO m)
1322#ifdef DEBUG
1345#ifdef DEBUG
1347+debugSubscriber :: forall x a. HasSpiderTimeline x => String -> Subscriber x a -> IO (Subscriber x a)
1348+debugSubscriber description = return . debugSubscriber' description
1350+debugSubscriber' :: forall x a. HasSpiderTimeline x => String -> Subscriber x a -> Subscriber x a
1351+debugSubscriber' description subscribed = Subscriber
1353+ subscriberPropagate = \m -> do
1354+ tracePropagate (Proxy :: Proxy x) ("subscriberPropagate: " <> description)
1355+ subscriberPropagate subscribed m
1356+ , subscriberInvalidateHeight = \old -> do
1357+ traceInvalidateHeight $ "invalidateSubscriberHeight: " <> description <> ", old = " <> show (unHeight old)
1358+ subscriberInvalidateHeight subscribed old
1359+ traceInvalidateHeight $ "invalidateSubscriberHeight: " <> description <> ", done"
1360+ , subscriberRecalculateHeight = \new -> do
1361+ traceInvalidateHeight $ "subscriberRecalculateHeight: " <> description <> ", new = " <> show (unHeight new)
1362+ subscriberRecalculateHeight subscribed new
1363+ traceInvalidateHeight $ "subscriberRecalculateHeight: " <> description <> ", done"
1323−withIncreasedDepth :: CanTrace x m => m a -> m a
1367+{-# INLINE withIncreasedDepth #-}
1368+withIncreasedDepth :: forall proxy x m a. CanTrace x m => proxy x -> m a -> m a
1324−withIncreasedDepth a = do
1369+withIncreasedDepth _ a = do
1325− spiderTimeline <- askSpiderTimelineEnv
1326− liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) succ
1370+ liftIO $ modifyIORef' (_spiderTimeline_depth $ unSTE (spiderTimeline :: SpiderTimelineEnv x)) succ
1327 result <- a
1371 result <- a
1328− liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) pred
1372+ liftIO $ modifyIORef' (_spiderTimeline_depth $ unSTE (spiderTimeline :: SpiderTimelineEnv x)) pred
1329 return result
1373 return result
1331−withIncreasedDepth :: m a -> m a
1332−withIncreasedDepth = id
1335−type CanTrace x m = (HasSpiderTimeline x, MonadIO m)
1337{-# INLINE tracePropagate #-}
1375{-# INLINE tracePropagate #-}
1338tracePropagate :: (CanTrace x m) => proxy x -> String -> m ()
1376tracePropagate :: (CanTrace x m) => proxy x -> String -> m ()
1339−tracePropagate p = traceWhen p debugPropagate
1377+tracePropagate p = when debugPropagate . trace p
1341{-# INLINE traceInvalidate #-}
1379{-# INLINE traceInvalidate #-}
1342traceInvalidate :: String -> IO ()
1380traceInvalidate :: String -> IO ()
1343−traceInvalidate = when debugInvalidate . liftIO . putStrLn
1381+traceInvalidate = when debugInvalidate . liftIO . debugStrLn
1383+{-# INLINE traceInvalidateHeight #-}
1384+traceInvalidateHeight :: String -> IO ()
1385+traceInvalidateHeight = when debugInvalidateHeight . liftIO . debugStrLn
1345−{-# INLINE traceWhen #-}
1387+{-# INLINE trace #-}
1346−traceWhen :: (CanTrace x m) => proxy x -> Bool -> String -> m ()
1388+trace :: (CanTrace x m) => proxy x -> String -> m ()
1347−traceWhen p b message = traceMWhen p b $ return message
1389+trace p message = traceM p $ return message
1349−{-# INLINE traceMWhen #-}
1391+{-# INLINE traceM #-}
1350−traceMWhen :: (CanTrace x m) => proxy x -> Bool -> m String -> m ()
1392+traceM :: forall x proxy m. (CanTrace x m) => proxy x -> m String -> m ()
1351−traceMWhen _ b getMessage = when b $ do
1393+traceM _ getMessage = do
1352 message <- getMessage
1394 message <- getMessage
1354− spiderTimeline <- askSpiderTimelineEnv
1355− d <- liftIO $ readIORef $ _spiderTimeline_depth $ unSTE spiderTimeline
1395+ d <- liftIO $ readIORef $ _spiderTimeline_depth $ unSTE (spiderTimeline :: SpiderTimelineEnv x)
1396+ liftIO $ debugStrLn $ replicate d ' ' <> message
1400+{-# INLINE withIncreasedDepth #-}
1401+withIncreasedDepth :: proxy x -> m a -> m a
1402+withIncreasedDepth _ = id
1404+{-# INLINE tracePropagate #-}
1405+tracePropagate :: (CanTrace x m) => proxy x -> String -> m ()
1406+tracePropagate _ _ = return ()
1408+{-# INLINE traceInvalidate #-}
1409+traceInvalidate :: String -> IO ()
1410+traceInvalidate _ = return ()
1412+{-# INLINE traceInvalidateHeight #-}
1413+traceInvalidateHeight :: String -> IO ()
1414+traceInvalidateHeight _ = return ()
1416+{-# INLINE debugSubscriber #-}
1417+debugSubscriber :: String -> Subscriber x a -> IO (Subscriber x a)
1418+debugSubscriber _ = return
1420+{-# INLINE debugSubscriber' #-}
1421+debugSubscriber' :: String -> Subscriber x a -> Subscriber x a
1422+debugSubscriber' _ = id
1426+{-# INLINE trace #-}
1427+trace :: (CanTrace x m) => proxy x -> String -> m ()
1428+trace _ _ = return ()
1430+{-# INLINE traceM #-}
1431+traceM :: (CanTrace x m) => proxy x -> m String -> m ()
1432+traceM _ _ = return ()
1359− liftIO $ putStrLn $ replicate d ' ' <> message
1361whoCreatedIORef :: IORef a -> IO [String]
1436whoCreatedIORef :: IORef a -> IO [String]
1362whoCreatedIORef (IORef a) = whoCreated $! a
1437whoCreatedIORef (IORef a) = whoCreated $! a
1365groupByHead :: Eq a => [NonEmpty a] -> [(a, NonEmpty [a])]
1439groupByHead :: Eq a => [NonEmpty a] -> [(a, NonEmpty [a])]
1366groupByHead = \case
1440groupByHead = \case
1367 [] -> []
1441 [] -> []
@@ -1372,20 +1446,54 @@ groupByHead = \case
1372 | otherwise -> (x, xs :| []) : l
1446 | otherwise -> (x, xs :| []) : l
1374listsToForest :: Eq a => [[a]] -> Forest a
1448listsToForest :: Eq a => [[a]] -> Forest a
1375−listsToForest l = fmap (\(a, l') -> Node a $ listsToForest $ toList l') $ groupByHead $ catMaybes $ fmap nonEmpty l
1449+listsToForest lists = buildForest <$> groupByHead (mapMaybe nonEmpty lists)
1450+ where buildForest (a, lists') = Node a $ listsToForest $ toList lists'
1452+showStacks :: [[String]] -> String
1453+showStacks = drawForest . listsToForest . fmap (filterStack "Reflex.Spider.Internal")
1455+filterStack :: String -> [String] -> [String]
1456+#ifdef DEBUG_HIDE_INTERNALS
1457+filterStack prefix = filter (not . (prefix `isPrefixOf`))
1459+filterStack prefix = id
1464+data EventLoopException = EventLoopException [[String]]
1465+instance Exception EventLoopException
1467+instance Show EventLoopException where
1468+ show (EventLoopException stacks) = "causality loop detected:\n" <> if null stacks
1469+ then "no location information, compile with profiling enabled for stack tree"
1470+ else showStacks stacks
1474+data EventLoopException = EventLoopException
1475+instance Exception EventLoopException
1477+instance Show EventLoopException where
1478+ show EventLoopException = "causality loop detected: \n" <>
1479+ "compile reflex with flag 'debug-cycles' and compile with profiling enabled for stack tree"
1378{-# INLINE propagateSubscriberHold #-}
1484{-# INLINE propagateSubscriberHold #-}
1379propagateSubscriberHold :: forall x p. (HasSpiderTimeline x, Patch p) => Hold x p -> p -> EventM x ()
1485propagateSubscriberHold :: forall x p. (HasSpiderTimeline x, Patch p) => Hold x p -> p -> EventM x ()
1380propagateSubscriberHold h a = do
1486propagateSubscriberHold h a = do
1381− {-# SCC "trace" #-} traceMWhen (Proxy :: Proxy x) debugPropagate $ liftIO $ do
1487+ {-# SCC "trace" #-} when debugPropagate $ traceM (Proxy :: Proxy x) $ liftIO $ do
1382 invalidators <- liftIO $ readIORef $ holdInvalidators h
1488 invalidators <- liftIO $ readIORef $ holdInvalidators h
1383 return $ "SubscriberHold" <> showNodeId h <> ": " ++ show (length invalidators)
1489 return $ "SubscriberHold" <> showNodeId h <> ": " ++ show (length invalidators)
1384 v <- {-# SCC "read" #-} liftIO $ readIORef $ holdValue h
1491 v <- {-# SCC "read" #-} liftIO $ readIORef $ holdValue h
1385 case {-# SCC "apply" #-} apply a v of
1492 case {-# SCC "apply" #-} apply a v of
1386 Nothing -> return ()
1493 Nothing -> return ()
1387 Just v' -> do
1494 Just v' -> do
1495+ {-# SCC "trace2" #-} withIncreasedDepth (Proxy :: Proxy x) $
1388− {-# SCC "trace2" #-} withIncreasedDepth $ tracePropagate (Proxy :: Proxy x) $ "propagateSubscriberHold: assigning Hold" <> showNodeId h
1496+ tracePropagate (Proxy :: Proxy x) ("propagateSubscriberHold: assigning Hold" <> showNodeId h)
1389 vRef <- {-# SCC "vRef" #-} liftIO $ evaluate $ holdValue h
1497 vRef <- {-# SCC "vRef" #-} liftIO $ evaluate $ holdValue h
1390 iRef <- {-# SCC "iRef" #-} liftIO $ evaluate $ holdInvalidators h
1498 iRef <- {-# SCC "iRef" #-} liftIO $ evaluate $ holdInvalidators h
1391 defer $ {-# SCC "assignment" #-} SomeAssignment vRef iRef v'
1499 defer $ {-# SCC "assignment" #-} SomeAssignment vRef iRef v'
@@ -1439,7 +1547,7 @@ getDynHold d = do
1439zeroRef :: IORef Height
1547zeroRef :: IORef Height
1440zeroRef = unsafePerformIO $ newIORef zeroHeight
1548zeroRef = unsafePerformIO $ newIORef zeroHeight
1442−getRootSubscribed :: GCompare k => k a -> Root x k -> Subscriber x a -> IO (WeakBagTicket, RootSubscribed x a, Maybe a)
1550+getRootSubscribed :: forall k x a. (GCompare k, HasSpiderTimeline x) => k a -> Root x k -> Subscriber x a -> IO (WeakBagTicket, RootSubscribed x a, Maybe a)
1443getRootSubscribed k r sub = do
1551getRootSubscribed k r sub = do
1444 mSubscribed <- readIORef $ rootSubscribed r
1552 mSubscribed <- readIORef $ rootSubscribed r
1445 let getOcc = fmap (coerce . DMap.lookup k) $ readIORef $ rootOccurrence r
1553 let getOcc = fmap (coerce . DMap.lookup k) $ readIORef $ rootOccurrence r
@@ -1453,7 +1561,9 @@ getRootSubscribed k r sub = do
1453 let !cached = rootSubscribed r
1561 let !cached = rootSubscribed r
1454 uninitRef <- newIORef $ error "getRootsubscribed: uninitRef not initialized"
1562 uninitRef <- newIORef $ error "getRootsubscribed: uninitRef not initialized"
1455 (subs, sln) <- WeakBag.singleton sub weakSelf cleanupRootSubscribed
1563 (subs, sln) <- WeakBag.singleton sub weakSelf cleanupRootSubscribed
1456− when debugPropagate $ putStrLn $ "getRootSubscribed: calling rootInit"
1565+ tracePropagate (Proxy::Proxy x) $ "getRootSubscribed: calling rootInit"
1457 uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
1567 uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
1458 writeIORef uninitRef $! uninit
1568 writeIORef uninitRef $! uninit
1459#ifdef DEBUG_NODEIDS
1569#ifdef DEBUG_NODEIDS
@@ -1503,6 +1613,9 @@ data FanInt x a = FanInt
1503 { _fanInt_subscribers :: {-# UNPACK #-} !(FastMutableIntMap (FastWeakBag (Subscriber x a))) --TODO: Clean up the keys in here when their child weak bags get empty --TODO: Remove our own subscription when the subscribers list is completely empty
1613 { _fanInt_subscribers :: {-# UNPACK #-} !(FastMutableIntMap (FastWeakBag (Subscriber x a))) --TODO: Clean up the keys in here when their child weak bags get empty --TODO: Remove our own subscription when the subscribers list is completely empty
1504 , _fanInt_subscriptionRef :: {-# UNPACK #-} !(IORef (EventSubscription x)) -- This should have a valid subscription iff subscribers is non-empty
1614 , _fanInt_subscriptionRef :: {-# UNPACK #-} !(IORef (EventSubscription x)) -- This should have a valid subscription iff subscribers is non-empty
1505 , _fanInt_occRef :: {-# UNPACK #-} !(IORef (IntMap a))
1615 , _fanInt_occRef :: {-# UNPACK #-} !(IORef (IntMap a))
1616+#ifdef DEBUG_NODEIDS
1617+ , _fanInt_nodeId :: {-# UNPACK #-} !Int
1508newFanInt :: IO (FanInt x a)
1621newFanInt :: IO (FanInt x a)
@@ -1510,10 +1623,16 @@ newFanInt = do
1510 subscribers <- FastMutableIntMap.newEmpty --TODO: Clean up the keys in here when their child weak bags get empty --TODO: Remove our own subscription when the subscribers list is completely empty
1623 subscribers <- FastMutableIntMap.newEmpty --TODO: Clean up the keys in here when their child weak bags get empty --TODO: Remove our own subscription when the subscribers list is completely empty
1511 subscriptionRef <- newIORef $ error "fanInt: no subscription"
1624 subscriptionRef <- newIORef $ error "fanInt: no subscription"
1512 occRef <- newIORef $ error "fanInt: no occurrence"
1625 occRef <- newIORef $ error "fanInt: no occurrence"
1626+#ifdef DEBUG_NODEIDS
1627+ nodeId <- newNodeId
1513 return $ FanInt
1629 return $ FanInt
1514 { _fanInt_subscribers = subscribers
1630 { _fanInt_subscribers = subscribers
1515 , _fanInt_subscriptionRef = subscriptionRef
1631 , _fanInt_subscriptionRef = subscriptionRef
1516 , _fanInt_occRef = occRef
1632 , _fanInt_occRef = occRef
1633+#ifdef DEBUG_NODEIDS
1634+ , _fanInt_nodeId = nodeId
1519fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
1638fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
@@ -1522,20 +1641,21 @@ fanInt p = unsafePerformIO $ do
1522 pure $ EventSelectorInt $ \k -> Event $ \sub -> do
1641 pure $ EventSelectorInt $ \k -> Event $ \sub -> do
1523 isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
1642 isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
1524 when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
1643 when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
1644+ let desc = "fanInt" <> showNodeId self <> ", k = " <> show k
1525− (subscription, parentOcc) <- subscribeAndRead p $ Subscriber
1645+ (subscription, parentOcc) <- subscribeAndRead p $ debugSubscriber' desc $ Subscriber
1526 { subscriberPropagate = \m -> do
1646 { subscriberPropagate = \m -> do
1527 liftIO $ writeIORef (_fanInt_occRef self) m
1647 liftIO $ writeIORef (_fanInt_occRef self) m
1528 scheduleIntClear $ _fanInt_occRef self
1648 scheduleIntClear $ _fanInt_occRef self
1529− FastMutableIntMap.forIntersectionWithImmutable_ (_fanInt_subscribers self) m $ \b v -> do --TODO: Do we need to know that no subscribers are being added as we traverse?
1649+ FastMutableIntMap.forIntersectionWithImmutable_ (_fanInt_subscribers self) m $ \b v -> --TODO: Do we need to know that no subscribers are being added as we traverse?
1530− FastWeakBag.traverse b $ \s -> do
1650+ FastWeakBag.traverse_ b $ \s ->
1531 subscriberPropagate s v
1651 subscriberPropagate s v
1532− , subscriberInvalidateHeight = \old -> do
1652+ , subscriberInvalidateHeight = \old ->
1533− FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1653+ FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b ->
1534− FastWeakBag.traverse b $ \s -> do
1654+ FastWeakBag.traverse_ b $ \s ->
1535 subscriberInvalidateHeight s old
1655 subscriberInvalidateHeight s old
1536− , subscriberRecalculateHeight = \new -> do
1656+ , subscriberRecalculateHeight = \new ->
1537− FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1657+ FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b ->
1538− FastWeakBag.traverse b $ \s -> do
1658+ FastWeakBag.traverse_ b $ \s ->
1539 subscriberRecalculateHeight s new
1659 subscriberRecalculateHeight s new
1541 liftIO $ do
1661 liftIO $ do
@@ -1549,10 +1669,25 @@ fanInt p = unsafePerformIO $ do
1549 FastMutableIntMap.insert (_fanInt_subscribers self) k b
1669 FastMutableIntMap.insert (_fanInt_subscribers self) k b
1550 return b
1670 return b
1551 Just b -> return b
1671 Just b -> return b
1552− t <- liftIO $ FastWeakBag.insert sub b
1672+ ticket <- liftIO $ FastWeakBag.insert sub b
1553 currentOcc <- readIORef (_fanInt_occRef self)
1673 currentOcc <- readIORef (_fanInt_occRef self)
1554− (EventSubscription _ (EventSubscribed !heightRef _)) <- readIORef (_fanInt_subscriptionRef self)
1674+
1675+ subscribed <- fanIntSubscribed ticket self
1555− return (EventSubscription (FastWeakBag.remove t) $! EventSubscribed heightRef $! toAny (_fanInt_subscriptionRef self, t), IntMap.lookup k currentOcc)
1676+ return (EventSubscription (FastWeakBag.remove ticket) subscribed, IntMap.lookup k currentOcc)
1678+fanIntSubscribed :: FastWeakBagTicket k -> FanInt x a -> IO (EventSubscribed x)
1679+fanIntSubscribed ticket self = do
1680+ subscribedParent <- _eventSubscription_subscribed <$> readIORef (_fanInt_subscriptionRef self)
1681+ return $ EventSubscribed
1682+ { eventSubscribedHeightRef = eventSubscribedHeightRef subscribedParent
1683+ , eventSubscribedRetained = toAny (_fanInt_subscriptionRef self, ticket)
1685+ , eventSubscribedGetParents = return [subscribedParent]
1686+ , eventSubscribedHasOwnHeightRef = False
1687+ , eventSubscribedWhoCreated = whoCreatedIORef $ _fanInt_subscriptionRef self
1557{-# INLINABLE getFanSubscribed #-}
1692{-# INLINABLE getFanSubscribed #-}
1558getFanSubscribed :: (HasSpiderTimeline x, GCompare k) => k a -> Fan x k v -> Subscriber x (v a) -> EventM x (WeakBagTicket, FanSubscribed x k v, Maybe (v a))
1693getFanSubscribed :: (HasSpiderTimeline x, GCompare k) => k a -> Fan x k v -> Subscriber x (v a) -> EventM x (WeakBagTicket, FanSubscribed x k v, Maybe (v a))
@@ -1750,7 +1885,7 @@ mergeCheap
1750 => (forall a. q a -> Event x (v a))
1885 => (forall a. q a -> Event x (v a))
1751 -> DynamicS x (PatchDMap k q)
1886 -> DynamicS x (PatchDMap k q)
1752 -> Event x (DMap k v)
1887 -> Event x (DMap k v)
1753−mergeCheap nt = mergeGCheap' getInitialSubscribers updateMe destroy
1888+mergeCheap nt = mergeGCheap' unMergeSubscribedParent getInitialSubscribers updateMe destroy
1755 updateMe :: MergeUpdateFunc k v x (PatchDMap k q) (MergeSubscribedParent x)
1890 updateMe :: MergeUpdateFunc k v x (PatchDMap k q) (MergeSubscribedParent x)
1756 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
1891 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
@@ -1765,7 +1900,9 @@ mergeCheap nt = mergeGCheap' getInitialSubscribers updateMe destroy
1765 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1900 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1766 return $ DMap.insertLookupWithKey' (\_ new _ -> new) k newParent ps
1901 return $ DMap.insertLookupWithKey' (\_ new _ -> new) k newParent ps
1767 forM_ mOldSubd $ \oldSubd -> do
1902 forM_ mOldSubd $ \oldSubd -> do
1903+ oldHeight <- liftIO $ getEventSubscribedHeight $
1768− oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ unMergeSubscribedParent oldSubd
1904+ _eventSubscription_subscribed $ unMergeSubscribedParent oldSubd
1769 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1906 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1770 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1907 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1771 foldM f ([], oldParents) $ DMap.toList p
1908 foldM f ([], oldParents) $ DMap.toList p
@@ -1790,7 +1927,7 @@ mergeCheapWithMove :: forall k x v q. (HasSpiderTimeline x, GCompare k)
1790 => (forall a. q a -> Event x (v a))
1927 => (forall a. q a -> Event x (v a))
1791 -> DynamicS x (PatchDMapWithMove k q)
1928 -> DynamicS x (PatchDMapWithMove k q)
1792 -> Event x (DMap k v)
1929 -> Event x (DMap k v)
1793−mergeCheapWithMove nt = mergeGCheap' getInitialSubscribers updateMe destroy
1930+mergeCheapWithMove nt = mergeGCheap' _mergeSubscribedParentWithMove_subscription getInitialSubscribers updateMe destroy
1795 updateMe :: MergeUpdateFunc k v x (PatchDMapWithMove k q) (MergeSubscribedParentWithMove x k)
1932 updateMe :: MergeUpdateFunc k v x (PatchDMapWithMove k q) (MergeSubscribedParentWithMove x k)
1796 updateMe subscriber heightBagRef oldParents p = do
1933 updateMe subscriber heightBagRef oldParents p = do
@@ -1809,13 +1946,17 @@ mergeCheapWithMove nt = mergeGCheap' getInitialSubscribers updateMe destroy
1809 let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k q a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1946 let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k q a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1810 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
1947 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
1811 Nothing -> do
1948 Nothing -> do
1812− oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
1949+ oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $
1950+ _mergeSubscribedParentWithMove_subscription parent
1813 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1952 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1814 return $ Just $ _mergeSubscribedParentWithMove_subscription parent
1953 return $ Just $ _mergeSubscribedParentWithMove_subscription parent
1815 Just toKey -> do
1954 Just toKey -> do
1816 liftIO $ writeIORef (_mergeSubscribedParentWithMove_key parent) $! toKey
1955 liftIO $ writeIORef (_mergeSubscribedParentWithMove_key parent) $! toKey
1817 return Nothing
1956 return Nothing
1957+ toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $
1818− toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
1958+ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
1819 return (toDelete, applyAlways p' oldParents)
1960 return (toDelete, applyAlways p' oldParents)
1820 getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParentWithMove x k)
1961 getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParentWithMove x k)
1821 getInitialSubscribers initialParents subscriber = do
1962 getInitialSubscribers initialParents subscriber = do
@@ -1840,6 +1981,8 @@ type MergeUpdateFunc k v x p s
1841 -> EventM x ([EventSubscription x], DMap k s)
1982 -> EventM x ([EventSubscription x], DMap k s)
1984+type MergeGetSubscription x s = forall a. s a -> EventSubscription x
1843type MergeInitFunc k v q x s
1986type MergeInitFunc k v q x s
1844 = DMap k q
1987 = DMap k q
1845 -> (forall a. EventM x (k a) -> Subscriber x (v a))
1988 -> (forall a. EventM x (k a) -> Subscriber x (v a))
@@ -1863,14 +2006,17 @@ invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_su
1863invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
2006invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
1864invalidateMergeHeight' heightRef sub = do
2007invalidateMergeHeight' heightRef sub = do
1865 oldHeight <- readIORef heightRef
2008 oldHeight <- readIORef heightRef
1866− when (oldHeight /= invalidHeight) $ do -- If the height used to be valid, it must be invalid now; we should never have *more* heights than we have parents
2009+ -- If the height used to be valid, it must be invalid now; we should never have *more* heights than we have parents
2010+ when (oldHeight /= invalidHeight) $ do
1867 writeIORef heightRef $! invalidHeight
2011 writeIORef heightRef $! invalidHeight
1868 subscriberInvalidateHeight sub oldHeight
2012 subscriberInvalidateHeight sub oldHeight
1870revalidateMergeHeight :: Merge x k v s -> IO ()
2014revalidateMergeHeight :: Merge x k v s -> IO ()
1871revalidateMergeHeight m = do
2015revalidateMergeHeight m = do
1872 currentHeight <- readIORef $ _merge_heightRef m
2016 currentHeight <- readIORef $ _merge_heightRef m
1873− when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
2018+ -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
2019+ when (currentHeight == invalidHeight) $ do
1874 heights <- readIORef $ _merge_heightBagRef m
2020 heights <- readIORef $ _merge_heightBagRef m
1875 parents <- readIORef $ _merge_parentsRef m
2021 parents <- readIORef $ _merge_parentsRef m
1876 -- When the number of heights in the bag reaches the number of parents, we should have a valid height
2022 -- When the number of heights in the bag reaches the number of parents, we should have a valid height
@@ -1878,7 +2024,7 @@ revalidateMergeHeight m = do
1878 LT -> return ()
2024 LT -> return ()
1879 EQ -> do
2025 EQ -> do
1880 let height = succHeight $ heightBagMax heights
2026 let height = succHeight $ heightBagMax heights
1881− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: height: " <> show height
2027+ traceInvalidateHeight $ "recalculateSubscriberHeight: height: " <> show height
1882 writeIORef (_merge_heightRef m) $! height
2028 writeIORef (_merge_heightRef m) $! height
1883 subscriberRecalculateHeight (_merge_sub m) height
2029 subscriberRecalculateHeight (_merge_sub m) height
1884 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
2030 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
@@ -1886,36 +2032,45 @@ revalidateMergeHeight m = do
1886scheduleMergeSelf :: HasSpiderTimeline x => Merge x k v s -> Height -> EventM x ()
2032scheduleMergeSelf :: HasSpiderTimeline x => Merge x k v s -> Height -> EventM x ()
1887scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
2033scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
1888 vals <- liftIO $ readIORef $ _merge_accumRef m
2034 vals <- liftIO $ readIORef $ _merge_accumRef m
1889− liftIO $ writeIORef (_merge_accumRef m) $! DMap.empty -- Once we're done with this, we can clear it immediately, because if there's a cacheEvent in front of us, it'll handle subsequent subscribers, and if not, we won't get subsequent subscribers
2035+ -- Once we're done with this, we can clear it immediately, because if there's a cacheEvent in front of us,
2036+ -- it'll handle subsequent subscribers, and if not, we won't get subsequent subscribers
2037+ liftIO $ writeIORef (_merge_accumRef m) $! DMap.empty
1890 --TODO: Assert that m is not empty
2038 --TODO: Assert that m is not empty
1891 subscriberPropagate (_merge_sub m) vals
2039 subscriberPropagate (_merge_sub m) vals
2041+checkCycle :: HasSpiderTimeline x => EventSubscribed x -> EventM x ()
2042+checkCycle subscribed = liftIO $ do
2043+ height <- readIORef (eventSubscribedHeightRef subscribed)
2045+ -- currentHeight <- getCurrentHeight
2046+ -- when (height <= currentHeight) $ if height /= invalidHeight
2048+ -- myStack <- liftIO $ whoCreatedIORef undefined --TODO
2049+ -- error $ "Height (" ++ show height ++ ") is not greater than current height (" ++ show currentHeight ++ ")\n" ++ unlines (reverse myStack)
2051+ when (height == invalidHeight) $
2054+ nodesInvolvedInCycle <- walkInvalidHeightParents subscribed
2055+ stacks <- forM nodesInvolvedInCycle whoCreatedEventSubscribed
2056+ throwIO (EventLoopException stacks)
2058+ throwIO EventLoopException
1893−mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
2062+mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => EventSubscribed x -> Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
1894−mergeSubscriber m getKey = Subscriber
2063+mergeSubscriber subscribed m getKey = Subscriber
1895 { subscriberPropagate = \a -> do
2064 { subscriberPropagate = \a -> do
1896 oldM <- liftIO $ readIORef $ _merge_accumRef m
2065 oldM <- liftIO $ readIORef $ _merge_accumRef m
1897 k <- getKey
2066 k <- getKey
1898− let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k a oldM
2067+ let newM = DMap.insertWith (error "Same key fired multiple times for Merge") k a oldM
1899 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
2068 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1900 liftIO $ writeIORef (_merge_accumRef m) $! newM
2069 liftIO $ writeIORef (_merge_accumRef m) $! newM
1901 when (DMap.null oldM) $ do -- Only schedule the firing once
2070 when (DMap.null oldM) $ do -- Only schedule the firing once
1902 height <- liftIO $ readIORef $ _merge_heightRef m
2071 height <- liftIO $ readIORef $ _merge_heightRef m
1903− --TODO: assertions about height
2072+ checkCycle subscribed
1904− currentHeight <- getCurrentHeight
2073+
1905− when (height <= currentHeight) $ do
1906− if height /= invalidHeight
1908− myStack <- liftIO $ whoCreatedIORef undefined --TODO
1909− error $ "Height (" ++ show height ++ ") is not greater than current height (" ++ show currentHeight ++ ")\n" ++ unlines (reverse myStack)
1912− nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1913− stacks <- forM nodesInvolvedInCycle $ \(Some es) -> whoCreatedEventSubscribed es
1914− let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1918− error $ "Causality loop found" <> cycleInfo
1919 scheduleMergeSelf m height
2074 scheduleMergeSelf m height
1920 , subscriberInvalidateHeight = \old -> do --TODO: When removing a parent doesn't actually change the height, maybe we can avoid invalidating
2075 , subscriberInvalidateHeight = \old -> do --TODO: When removing a parent doesn't actually change the height, maybe we can avoid invalidating
1921 modifyIORef' (_merge_heightBagRef m) $ heightBagRemove old
2076 modifyIORef' (_merge_heightBagRef m) $ heightBagRemove old
@@ -1926,31 +2081,45 @@ mergeSubscriber m getKey = Subscriber
1928--TODO: Be able to run as much of this as possible promptly
2083--TODO: Be able to run as much of this as possible promptly
1929−updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k v s -> MergeUpdateFunc k v x p s -> p -> SomeMergeUpdate x
2084+updateMerge :: (HasSpiderTimeline x, GCompare k) => EventSubscribed x -> Merge x k v s -> MergeUpdateFunc k v x p s -> p -> SomeMergeUpdate x
1930−updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
2085+updateMerge subscribed m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
1931 where updateMe = do
2086 where updateMe = do
1932 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
2087 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
1933− (subscriptionsToKill, newParents) <- updateFunc (mergeSubscriber m) (_merge_heightBagRef m) oldParents p
2088+ (subscriptionsToKill, newParents) <- updateFunc (mergeSubscriber subscribed m) (_merge_heightBagRef m) oldParents p
1934 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
2089 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
1935 return subscriptionsToKill
2090 return subscriptionsToKill
1937{-# INLINE mergeGCheap' #-}
2092{-# INLINE mergeGCheap' #-}
1938mergeGCheap' :: forall k v x p s q. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k q)
2093mergeGCheap' :: forall k v x p s q. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k q)
1939− => MergeInitFunc k v q x s -> MergeUpdateFunc k v x p s -> MergeDestroyFunc k s -> DynamicS x p -> Event x (DMap k v)
2094+ => MergeGetSubscription x s -> MergeInitFunc k v q x s -> MergeUpdateFunc k v x p s -> MergeDestroyFunc k s -> DynamicS x p -> Event x (DMap k v)
1940−mergeGCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
2095+mergeGCheap' getParent getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1941 initialParents <- readBehaviorUntracked $ dynamicCurrent d
2096 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1942 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
2097 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1943 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
2098 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
1944 heightBagRef <- liftIO $ newIORef $ error "merge: heightBagRef not yet initialized"
2099 heightBagRef <- liftIO $ newIORef $ error "merge: heightBagRef not yet initialized"
1945 parentsRef :: IORef (DMap k s) <- liftIO $ newIORef $ error "merge: parentsRef not yet initialized"
2100 parentsRef :: IORef (DMap k s) <- liftIO $ newIORef $ error "merge: parentsRef not yet initialized"
2101+ changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
2103+ let subscribed = EventSubscribed
2104+ { eventSubscribedHeightRef = heightRef
2105+ , eventSubscribedRetained = toAny (parentsRef, changeSubdRef)
2107+ , eventSubscribedGetParents = do
2108+ let getParent' (_ :=> v) = _eventSubscription_subscribed (getParent v)
2109+ fmap getParent' . DMap.toList <$> readIORef parentsRef
2110+ , eventSubscribedHasOwnHeightRef = False
2111+ , eventSubscribedWhoCreated = whoCreatedIORef heightRef
1946− let m = Merge
2115+ m = Merge
1947 { _merge_parentsRef = parentsRef
2116 { _merge_parentsRef = parentsRef
1948 , _merge_heightBagRef = heightBagRef
2117 , _merge_heightBagRef = heightBagRef
1949 , _merge_heightRef = heightRef
2118 , _merge_heightRef = heightRef
1950 , _merge_sub = sub
2119 , _merge_sub = sub
1951 , _merge_accumRef = accumRef
2120 , _merge_accumRef = accumRef
1953− (dm, heights, initialParentState) <- getInitialSubscribers initialParents $ mergeSubscriber m
2122+ (dm, heights, initialParentState) <- getInitialSubscribers initialParents $ mergeSubscriber subscribed m
1954 let myHeightBag = heightBagFromList $ filter (/= invalidHeight) heights
2123 let myHeightBag = heightBagFromList $ filter (/= invalidHeight) heights
1955 myHeight = if invalidHeight `elem` heights
2124 myHeight = if invalidHeight `elem` heights
1956 then invalidHeight
2125 then invalidHeight
@@ -1959,31 +2128,29 @@ mergeGCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1959 let (occ, accum) = if currentHeight >= myHeight -- If we should have fired by now
2128 let (occ, accum) = if currentHeight >= myHeight -- If we should have fired by now
1960 then (if DMap.null dm then Nothing else Just dm, DMap.empty)
2129 then (if DMap.null dm then Nothing else Just dm, DMap.empty)
1961 else (Nothing, dm)
2130 else (Nothing, dm)
1962− unless (DMap.null accum) $ do
1963− scheduleMergeSelf m myHeight
2131+ unless (DMap.null accum) $ scheduleMergeSelf m myHeight
1964 liftIO $ writeIORef accumRef $! accum
2132 liftIO $ writeIORef accumRef $! accum
1965 liftIO $ writeIORef heightRef $! myHeight
2133 liftIO $ writeIORef heightRef $! myHeight
1966 liftIO $ writeIORef heightBagRef $! myHeightBag
2134 liftIO $ writeIORef heightBagRef $! myHeightBag
1967− changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
1968 liftIO $ writeIORef parentsRef $! initialParentState
2135 liftIO $ writeIORef parentsRef $! initialParentState
1969 defer $ SomeMergeInit $ do
2136 defer $ SomeMergeInit $ do
1970− let s = Subscriber
2137+ let changeSubscriber = Subscriber
1971 { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
2138 { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
1972− tracePropagate (Proxy :: Proxy x) $ "SubscriberMerge/Change"
2139+ tracePropagate (Proxy :: Proxy x) "SubscriberMerge/Change"
1973− defer $ updateMerge m updateFunc a
2140+ defer $ updateMerge subscribed m updateFunc a
1974 , subscriberInvalidateHeight = \_ -> return ()
2141 , subscriberInvalidateHeight = \_ -> return ()
1975 , subscriberRecalculateHeight = \_ -> return ()
2142 , subscriberRecalculateHeight = \_ -> return ()
1977− (changeSubscription, change) <- subscribeAndRead (dynamicUpdated d) s
2144+ (changeSubscription, change) <- subscribeAndRead (dynamicUpdated d) changeSubscriber
1978− forM_ change $ \c -> defer $ updateMerge m updateFunc c
2145+ forM_ change $ \c -> defer $ updateMerge subscribed m updateFunc c
1979 -- We explicitly hold on to the unsubscribe function from subscribing to the update event.
2146 -- We explicitly hold on to the unsubscribe function from subscribing to the update event.
1980 -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
2147 -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
1981 -- its subscription.
2148 -- its subscription.
1982− liftIO $ writeIORef changeSubdRef (s, changeSubscription)
2149+ liftIO $ writeIORef changeSubdRef (changeSubscriber, changeSubscription)
1983 let unsubscribeAll = destroy =<< readIORef parentsRef
2150 let unsubscribeAll = destroy =<< readIORef parentsRef
1984− return ( EventSubscription unsubscribeAll $ EventSubscribed heightRef $ toAny (parentsRef, changeSubdRef)
2152+ return (EventSubscription unsubscribeAll subscribed, occ)
1988mergeInt :: forall x a. (HasSpiderTimeline x) => DynamicS x (PatchIntMap (Event x a)) -> Event x (IntMap a)
2155mergeInt :: forall x a. (HasSpiderTimeline x) => DynamicS x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1989mergeInt = cacheEvent . mergeIntCheap
2156mergeInt = cacheEvent . mergeIntCheap
@@ -1996,13 +2163,22 @@ mergeIntCheap d = Event $ \sub -> do
1996 heightRef <- liftIO $ newIORef zeroHeight
2163 heightRef <- liftIO $ newIORef zeroHeight
1997 heightBagRef <- liftIO $ newIORef heightBagEmpty
2164 heightBagRef <- liftIO $ newIORef heightBagEmpty
1998 parents <- liftIO $ FastMutableIntMap.newEmpty
2165 parents <- liftIO $ FastMutableIntMap.newEmpty
2166+ changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
2167+ let subscribed = EventSubscribed
2168+ { eventSubscribedHeightRef = heightRef
2169+ , eventSubscribedRetained = toAny (parents, changeSubdRef)
2171+ , eventSubscribedGetParents = fmap (_eventSubscription_subscribed . snd) <$> FastMutableIntMap.toList parents
2172+ , eventSubscribedHasOwnHeightRef = False
2173+ , eventSubscribedWhoCreated = whoCreatedIORef heightRef
1999 let scheduleSelf = do
2176 let scheduleSelf = do
2000 height <- liftIO $ readIORef $ heightRef
2177 height <- liftIO $ readIORef $ heightRef
2001 scheduleMerge' height heightRef $ do
2178 scheduleMerge' height heightRef $ do
2002 vals <- liftIO $ FastMutableIntMap.getFrozenAndClear accum
2179 vals <- liftIO $ FastMutableIntMap.getFrozenAndClear accum
2003 subscriberPropagate sub vals
2180 subscriberPropagate sub vals
2004− invalidateMyHeight = do
2005− invalidateMergeHeight' heightRef sub
2181+ invalidateMyHeight = invalidateMergeHeight' heightRef sub
2006 recalculateMyHeight = do
2182 recalculateMyHeight = do
2007 currentHeight <- readIORef heightRef
2183 currentHeight <- readIORef heightRef
2008 when (currentHeight == invalidHeight) $ do --TODO: This will almost always be true; can we get rid of this check and just proceed to the next one always?
2184 when (currentHeight == invalidHeight) $ do --TODO: This will almost always be true; can we get rid of this check and just proceed to the next one always?
@@ -2012,12 +2188,14 @@ mergeIntCheap d = Event $ \sub -> do
2012 LT -> return ()
2188 LT -> return ()
2013 EQ -> do
2189 EQ -> do
2014 let height = succHeight $ heightBagMax heights
2190 let height = succHeight $ heightBagMax heights
2015− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: height: " <> show height
2191+ traceInvalidateHeight $ "recalculateSubscriberHeight: height: " <> show height
2016 writeIORef heightRef $! height
2192 writeIORef heightRef $! height
2017 subscriberRecalculateHeight sub height
2193 subscriberRecalculateHeight sub height
2018 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show numParents <> ") for Merge"
2194 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show numParents <> ") for Merge"
2019 mySubscriber k = Subscriber
2195 mySubscriber k = Subscriber
2020 { subscriberPropagate = \a -> do
2196 { subscriberPropagate = \a -> do
2197+ checkCycle subscribed
2021 wasEmpty <- liftIO $ FastMutableIntMap.isEmpty accum
2199 wasEmpty <- liftIO $ FastMutableIntMap.isEmpty accum
2022 liftIO $ FastMutableIntMap.insert accum k a
2200 liftIO $ FastMutableIntMap.insert accum k a
2023 when wasEmpty scheduleSelf
2201 when wasEmpty scheduleSelf
@@ -2051,7 +2229,6 @@ mergeIntCheap d = Event $ \sub -> do
2051 else liftIO $ Just <$> FastMutableIntMap.getFrozenAndClear accum
2229 else liftIO $ Just <$> FastMutableIntMap.getFrozenAndClear accum
2052 else do when (not isEmpty) scheduleSelf -- We have things accumulated, but we shouldn't have fired them yet
2230 else do when (not isEmpty) scheduleSelf -- We have things accumulated, but we shouldn't have fired them yet
2053 return Nothing
2231 return Nothing
2054− changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
2055 defer $ SomeMergeInit $ do
2232 defer $ SomeMergeInit $ do
2056 let updateMe a = SomeMergeUpdate u invalidateMyHeight recalculateMyHeight
2233 let updateMe a = SomeMergeUpdate u invalidateMyHeight recalculateMyHeight
@@ -2065,25 +2242,27 @@ mergeIntCheap d = Event $ \sub -> do
2065 oldParents <- liftIO $ FastMutableIntMap.applyPatch parents newSubscriptions
2242 oldParents <- liftIO $ FastMutableIntMap.applyPatch parents newSubscriptions
2066 liftIO $ for_ oldParents $ \oldParent -> do
2243 liftIO $ for_ oldParents $ \oldParent -> do
2067 oldParentHeight <- getEventSubscribedHeight $ _eventSubscription_subscribed oldParent
2244 oldParentHeight <- getEventSubscribedHeight $ _eventSubscription_subscribed oldParent
2246+ print ("updateMe", oldParentHeight)
2068 modifyIORef' heightBagRef $ heightBagRemove oldParentHeight
2247 modifyIORef' heightBagRef $ heightBagRemove oldParentHeight
2069 return $ IntMap.elems oldParents
2248 return $ IntMap.elems oldParents
2070− let s = Subscriber
2249+ let changeSubscriber = Subscriber
2071 { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
2250 { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
2072 tracePropagate (Proxy :: Proxy x) $ "SubscriberMergeInt/Change"
2251 tracePropagate (Proxy :: Proxy x) $ "SubscriberMergeInt/Change"
2073 defer $ updateMe a
2252 defer $ updateMe a
2074 , subscriberInvalidateHeight = \_ -> return ()
2253 , subscriberInvalidateHeight = \_ -> return ()
2075 , subscriberRecalculateHeight = \_ -> return ()
2254 , subscriberRecalculateHeight = \_ -> return ()
2077− (changeSubscription, change) <- subscribeAndRead (dynamicUpdated d) s
2256+ (changeSubscription, change) <- subscribeAndRead (dynamicUpdated d) changeSubscriber
2078 forM_ change $ \c -> defer $ updateMe c
2257 forM_ change $ \c -> defer $ updateMe c
2079 -- We explicitly hold on to the unsubscribe function from subscribing to the update event.
2258 -- We explicitly hold on to the unsubscribe function from subscribing to the update event.
2080 -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
2259 -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
2081 -- its subscription.
2260 -- its subscription.
2082− liftIO $ writeIORef changeSubdRef (s, changeSubscription)
2261+ liftIO $ writeIORef changeSubdRef (changeSubscriber, changeSubscription)
2083 let unsubscribeAll = traverse_ unsubscribe =<< FastMutableIntMap.getFrozenAndClear parents
2262 let unsubscribeAll = traverse_ unsubscribe =<< FastMutableIntMap.getFrozenAndClear parents
2084− return ( EventSubscription unsubscribeAll $ EventSubscribed heightRef $ toAny (parents, changeSubdRef)
2265+ return (EventSubscription unsubscribeAll subscribed, occ)
2088newtype EventSelector x k = EventSelector { select :: forall a. k a -> Event x a }
2267newtype EventSelector x k = EventSelector { select :: forall a. k a -> Event x a }
2089newtype EventSelectorG x k v = EventSelectorG { selectG :: forall a. k a -> Event x (v a) }
2268newtype EventSelectorG x k v = EventSelectorG { selectG :: forall a. k a -> Event x (v a) }
@@ -2166,19 +2345,19 @@ runFrame a = SpiderHost $ do
2166 coincidenceInfos <- readIORef $ eventEnvResetCoincidences env
2345 coincidenceInfos <- readIORef $ eventEnvResetCoincidences env
2167 forM_ toAssign $ \(SomeAssignment vRef iRef v) -> {-# SCC "assignment" #-} do
2346 forM_ toAssign $ \(SomeAssignment vRef iRef v) -> {-# SCC "assignment" #-} do
2168 writeIORef vRef v
2347 writeIORef vRef v
2169− when debugInvalidate $ putStrLn $ "Invalidating Hold"
2348+ traceInvalidate $ "Invalidating Hold"
2170 writeIORef iRef =<< evaluate =<< invalidate toReconnectRef =<< readIORef iRef
2349 writeIORef iRef =<< evaluate =<< invalidate toReconnectRef =<< readIORef iRef
2171 mergeUpdates <- readIORef $ eventEnvMergeUpdates env
2350 mergeUpdates <- readIORef $ eventEnvMergeUpdates env
2172 writeIORef (eventEnvMergeUpdates env) []
2351 writeIORef (eventEnvMergeUpdates env) []
2173− when debugPropagate $ putStrLn "Updating merges"
2352+ tracePropagate (Proxy::Proxy x) $ "Updating merges"
2174 mergeSubscriptionsToKill <- runEventM $ concat <$> mapM _someMergeUpdate_update mergeUpdates
2353 mergeSubscriptionsToKill <- runEventM $ concat <$> mapM _someMergeUpdate_update mergeUpdates
2175− when debugPropagate $ putStrLn "Updating merges done"
2354+ tracePropagate (Proxy::Proxy x) $ "Updating merges done"
2176 toReconnect <- readIORef toReconnectRef
2355 toReconnect <- readIORef toReconnectRef
2177 clearEventEnv env
2356 clearEventEnv env
2178 switchSubscriptionsToKill <- forM toReconnect $ \(SomeSwitchSubscribed subscribed) -> {-# SCC "switchSubscribed" #-} do
2357 switchSubscriptionsToKill <- forM toReconnect $ \(SomeSwitchSubscribed subscribed) -> {-# SCC "switchSubscribed" #-} do
2179 oldSubscription <- readIORef $ switchSubscribedCurrentParent subscribed
2358 oldSubscription <- readIORef $ switchSubscribedCurrentParent subscribed
2180 wi <- readIORef $ switchSubscribedOwnWeakInvalidator subscribed
2359 wi <- readIORef $ switchSubscribedOwnWeakInvalidator subscribed
2181− when debugInvalidate $ putStrLn $ "Finalizing invalidator for Switch" <> showNodeId subscribed
2360+ traceInvalidate $ "Finalizing invalidator for Switch" <> showNodeId subscribed
2182 finalize wi
2361 finalize wi
2183 i <- evaluate $ switchSubscribedOwnInvalidator subscribed
2362 i <- evaluate $ switchSubscribedOwnInvalidator subscribed
2184 wi' <- mkWeakPtrWithDebug i "wi'"
2363 wi' <- mkWeakPtrWithDebug i "wi'"
@@ -2192,7 +2371,7 @@ runFrame a = SpiderHost $ do
2192 subscription <- unSpiderHost $ runFrame $ {-# SCC "subscribeSwitch" #-} subscribe e sub --TODO: Assert that the event isn't firing --TODO: This should not loop because none of the events should be firing, but still, it is inefficient
2371 subscription <- unSpiderHost $ runFrame $ {-# SCC "subscribeSwitch" #-} subscribe e sub --TODO: Assert that the event isn't firing --TODO: This should not loop because none of the events should be firing, but still, it is inefficient
2194 stackTrace <- liftIO $ fmap renderStack $ ccsToStrings =<< (getCCSOf $! switchSubscribedParent subscribed)
2373 stackTrace <- liftIO $ fmap renderStack $ ccsToStrings =<< (getCCSOf $! switchSubscribedParent subscribed)
2195− liftIO $ putStrLn $ (++stackTrace) $ "subd' subscribed to " ++ case e of
2374+ liftIO $ debugStrLn $ (++stackTrace) $ "subd' subscribed to " ++ case e of
2196 EventRoot _ -> "EventRoot"
2375 EventRoot _ -> "EventRoot"
2197 EventNever -> "EventNever"
2376 EventNever -> "EventNever"
2198 _ -> "something else"
2377 _ -> "something else"
@@ -2207,7 +2386,7 @@ runFrame a = SpiderHost $ do
2207 myHeight <- readIORef $ switchSubscribedHeight subscribed
2386 myHeight <- readIORef $ switchSubscribedHeight subscribed
2208 when (parentHeight /= myHeight) $ do
2387 when (parentHeight /= myHeight) $ do
2209 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
2388 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
2210− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight myHeight
2389+ WeakBag.traverse_ (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight myHeight
2211 mapM_ _someMergeUpdate_invalidateHeight mergeUpdates --TODO: In addition to when the patch is completely empty, we should also not run this if it has some Nothing values, but none of them have actually had any effect; potentially, we could even check for Just values with no effect (e.g. by comparing their IORefs and ignoring them if they are unchanged); actually, we could just check if the new height is different
2390 mapM_ _someMergeUpdate_invalidateHeight mergeUpdates --TODO: In addition to when the patch is completely empty, we should also not run this if it has some Nothing values, but none of them have actually had any effect; potentially, we could even check for Just values with no effect (e.g. by comparing their IORefs and ignoring them if they are unchanged); actually, we could just check if the new height is different
2212 forM_ coincidenceInfos $ \(SomeResetCoincidence subscription mcs) -> do
2391 forM_ coincidenceInfos $ \(SomeResetCoincidence subscription mcs) -> do
2213 unsubscribe subscription
2392 unsubscribe subscription
@@ -2248,7 +2427,7 @@ invalidateCoincidenceHeight subscribed = do
2248 oldHeight <- readIORef $ coincidenceSubscribedHeight subscribed
2427 oldHeight <- readIORef $ coincidenceSubscribedHeight subscribed
2249 when (oldHeight /= invalidHeight) $ do
2428 when (oldHeight /= invalidHeight) $ do
2250 writeIORef (coincidenceSubscribedHeight subscribed) $! invalidHeight
2429 writeIORef (coincidenceSubscribedHeight subscribed) $! invalidHeight
2251− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
2430+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
2253updateSwitchHeight :: Height -> SwitchSubscribed x a -> IO ()
2432updateSwitchHeight :: Height -> SwitchSubscribed x a -> IO ()
2254updateSwitchHeight new subscribed = do
2433updateSwitchHeight new subscribed = do
@@ -2256,7 +2435,7 @@ updateSwitchHeight new subscribed = do
2256 when (oldHeight == invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2435 when (oldHeight == invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2257 when (new /= invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2436 when (new /= invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2258 writeIORef (switchSubscribedHeight subscribed) $! new
2437 writeIORef (switchSubscribedHeight subscribed) $! new
2259− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ recalculateSubscriberHeight new
2438+ WeakBag.traverse_ (switchSubscribedSubscribers subscribed) $ recalculateSubscriberHeight new
2261recalculateCoincidenceHeight :: CoincidenceSubscribed x a -> IO ()
2440recalculateCoincidenceHeight :: CoincidenceSubscribed x a -> IO ()
2262recalculateCoincidenceHeight subscribed = do
2441recalculateCoincidenceHeight subscribed = do
@@ -2265,7 +2444,7 @@ recalculateCoincidenceHeight subscribed = do
2265 height <- calculateCoincidenceHeight subscribed
2444 height <- calculateCoincidenceHeight subscribed
2266 when (height /= invalidHeight) $ do
2445 when (height /= invalidHeight) $ do
2267 writeIORef (coincidenceSubscribedHeight subscribed) $! height
2446 writeIORef (coincidenceSubscribedHeight subscribed) $! height
2268− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight height
2447+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight height
2270calculateSwitchHeight :: SwitchSubscribed x a -> IO Height
2449calculateSwitchHeight :: SwitchSubscribed x a -> IO Height
2271calculateSwitchHeight subscribed = getEventSubscribedHeight . _eventSubscription_subscribed =<< readIORef (switchSubscribedCurrentParent subscribed)
2450calculateSwitchHeight subscribed = getEventSubscribedHeight . _eventSubscription_subscribed =<< readIORef (switchSubscribedCurrentParent subscribed)
@@ -2356,8 +2535,10 @@ instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x))
2356 x >>= f = SpiderDynamic $ dynamicDynIdentity $ newJoinDyn $ newMapDyn (unSpiderDynamic . f) $ unSpiderDynamic x
2535 x >>= f = SpiderDynamic $ dynamicDynIdentity $ newJoinDyn $ newMapDyn (unSpiderDynamic . f) $ unSpiderDynamic x
2357 {-# INLINE (>>) #-}
2536 {-# INLINE (>>) #-}
2358 (>>) = (*>)
2537 (>>) = (*>)
2538+#if !MIN_VERSION_base(4,13,0)
2359 {-# INLINE fail #-}
2539 {-# INLINE fail #-}
2360 fail _ = error "Dynamic does not support 'fail'"
2540 fail _ = error "Dynamic does not support 'fail'"
2362{-# INLINABLE newJoinDyn #-}
2543{-# INLINABLE newJoinDyn #-}
2363newJoinDyn :: HasSpiderTimeline x => DynamicS x (Identity (DynamicS x (Identity a))) -> Reflex.Spider.Internal.Dyn x (Identity a)
2544newJoinDyn :: HasSpiderTimeline x => DynamicS x (Identity (DynamicS x (Identity a))) -> Reflex.Spider.Internal.Dyn x (Identity a)
@@ -2482,13 +2663,13 @@ instance HasSpiderTimeline x => Reflex.Host.Class.MonadReadEvent (SpiderTimeline
2483 return result
2664 return result
2485−instance Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHost x) where
2666+instance HasSpiderTimeline x => Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHost x) where
2486 newEventWithTrigger = SpiderHost . fmap SpiderEvent . newEventWithTriggerIO
2667 newEventWithTrigger = SpiderHost . fmap SpiderEvent . newEventWithTriggerIO
2487 newFanEventWithTrigger f = SpiderHost $ do
2668 newFanEventWithTrigger f = SpiderHost $ do
2488 es <- newFanEventWithTriggerIO f
2669 es <- newFanEventWithTriggerIO f
2489 return $ Reflex.Class.EventSelector $ SpiderEvent . Reflex.Spider.Internal.select es
2670 return $ Reflex.Class.EventSelector $ SpiderEvent . Reflex.Spider.Internal.select es
2491−instance Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHostFrame x) where
2672+instance HasSpiderTimeline x => Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHostFrame x) where
2492 newEventWithTrigger = SpiderHostFrame . EventM . liftIO . fmap SpiderEvent . newEventWithTriggerIO
2673 newEventWithTrigger = SpiderHostFrame . EventM . liftIO . fmap SpiderEvent . newEventWithTriggerIO
2493 newFanEventWithTrigger f = SpiderHostFrame $ EventM $ liftIO $ do
2674 newFanEventWithTrigger f = SpiderHostFrame $ EventM $ liftIO $ do
2494 es <- newFanEventWithTriggerIO f
2675 es <- newFanEventWithTriggerIO f
@@ -2636,8 +2817,14 @@ instance Monad (SpiderHost x) where
2636 SpiderHost x >> SpiderHost y = SpiderHost $ x >> y
2817 SpiderHost x >> SpiderHost y = SpiderHost $ x >> y
2637 {-# INLINABLE return #-}
2818 {-# INLINABLE return #-}
2638 return x = SpiderHost $ return x
2819 return x = SpiderHost $ return x
2820+#if !MIN_VERSION_base(4,13,0)
2821+ {-# INLINABLE fail #-}
2822+ fail = MonadFail.fail
2825+instance MonadFail (SpiderHost x) where
2639 {-# INLINABLE fail #-}
2826 {-# INLINABLE fail #-}
2640− fail s = SpiderHost $ fail s
2827+ fail s = SpiderHost $ MonadFail.fail s
2642-- | Run an action affecting the global Spider timeline; this will be guarded by
2829-- | Run an action affecting the global Spider timeline; this will be guarded by
2643-- a mutex for that timeline
2830-- a mutex for that timeline
@@ -2659,19 +2846,21 @@ instance Monad (SpiderHostFrame x) where
2659 SpiderHostFrame x >> SpiderHostFrame y = SpiderHostFrame $ x >> y
2846 SpiderHostFrame x >> SpiderHostFrame y = SpiderHostFrame $ x >> y
2660 {-# INLINABLE return #-}
2847 {-# INLINABLE return #-}
2661 return x = SpiderHostFrame $ return x
2848 return x = SpiderHostFrame $ return x
2849+#if !MIN_VERSION_base(4,13,0)
2662 {-# INLINABLE fail #-}
2850 {-# INLINABLE fail #-}
2663 fail s = SpiderHostFrame $ fail s
2851 fail s = SpiderHostFrame $ fail s
2665instance NotReady (SpiderTimeline x) (SpiderHostFrame x) where
2854instance NotReady (SpiderTimeline x) (SpiderHostFrame x) where
2666 notReadyUntil _ = pure ()
2855 notReadyUntil _ = pure ()
2667 notReady = pure ()
2856 notReady = pure ()
2669−newEventWithTriggerIO :: (RootTrigger x a -> IO (IO ())) -> IO (Event x a)
2858+newEventWithTriggerIO :: forall x a. HasSpiderTimeline x => (RootTrigger x a -> IO (IO ())) -> IO (Event x a)
2670newEventWithTriggerIO f = do
2859newEventWithTriggerIO f = do
2671 es <- newFanEventWithTriggerIO $ \Refl -> f
2860 es <- newFanEventWithTriggerIO $ \Refl -> f
2672 return $ select es Refl
2861 return $ select es Refl
2674−newFanEventWithTriggerIO :: GCompare k => (forall a. k a -> RootTrigger x a -> IO (IO ())) -> IO (EventSelector x k)
2863+newFanEventWithTriggerIO :: (HasSpiderTimeline x, GCompare k) => (forall a. k a -> RootTrigger x a -> IO (IO ())) -> IO (EventSelector x k)
2675newFanEventWithTriggerIO f = do
2864newFanEventWithTriggerIO f = do
2676 occRef <- newIORef DMap.empty
2865 occRef <- newIORef DMap.empty
2677 subscribedRef <- newIORef DMap.empty
2866 subscribedRef <- newIORef DMap.empty
@@ -2705,3 +2894,11 @@ instance MonadAtomicRef (SpiderHostFrame x) where
2705instance PrimMonad (SpiderHostFrame x) where
2894instance PrimMonad (SpiderHostFrame x) where
2706 type PrimState (SpiderHostFrame x) = PrimState IO
2895 type PrimState (SpiderHostFrame x) = PrimState IO
2707 primitive = SpiderHostFrame . EventM . primitive
2896 primitive = SpiderHostFrame . EventM . primitive
2898+instance NotReady (SpiderTimeline x) (SpiderHost x) where
2899+ notReadyUntil _ = return ()
2900+ notReady = return ()
2902+instance HasSpiderTimeline x => NotReady (SpiderTimeline x) (PerformEventT (SpiderTimeline x) (SpiderHost x)) where
2903+ notReadyUntil _ = return ()
2904+ notReady = return ()