{-# LANGUAGE RecordWildCards, NamedFieldPuns #-}
module Reactive.Banana.Prim.Dependencies (
addChild, changeParent, buildDependencies,
) where
import Control.Monad
import Data.Functor
import Data.Monoid
import System.Mem.Weak
import qualified Reactive.Banana.Prim.Graph as Graph
import Reactive.Banana.Prim.Types
import Reactive.Banana.Prim.Util
addChild :: SomeNode -> SomeNode -> DependencyBuilder
addChild parent child = (Endo $ Graph.insertEdge (parent,child), mempty)
changeParent :: Pulse a -> Pulse b -> DependencyBuilder
changeParent child parent = (mempty, [(P child, P parent)])
buildDependencies :: DependencyBuilder -> IO ()
buildDependencies (Endo f, parents) = do
sequence_ [x `doAddChild` y | x <- Graph.listParents gr, y <- Graph.getChildren gr x]
sequence_ [x `doChangeParent` y | (P x, P y) <- parents]
where
gr :: Graph.Graph SomeNode
gr = f Graph.emptyGraph
connectChild
:: Pulse a
-> SomeNode
-> IO (Weak SomeNode)
connectChild parent child = do
w <- mkWeakNodeValue child child
modify' parent $ update childrenP (w:)
mkWeakNodeValue child (P parent)
doAddChild :: SomeNode -> SomeNode -> IO ()
doAddChild (P parent) (P child) = do
level1 <- _levelP <$> readRef child
level2 <- _levelP <$> readRef parent
let level = level1 `max` (level2 + 1)
w <- parent `connectChild` (P child)
modify' child $ set levelP level . update parentsP (w:)
doAddChild (P parent) node = void $ parent `connectChild` node
removeParents :: Pulse a -> IO ()
removeParents child = do
c@Pulse{_parentsP} <- readRef child
forM_ _parentsP $ \w -> do
Just (P parent) <- deRefWeak w
finalize w
let isGoodChild w = not . maybe True (== P child) <$> deRefWeak w
new <- filterM isGoodChild . _childrenP =<< readRef parent
modify' parent $ set childrenP new
put child $ c{_parentsP = []}
doChangeParent :: Pulse a -> Pulse b -> IO ()
doChangeParent child parent = do
removeParents child
w <- parent `connectChild` (P child)
modify' child $ update parentsP (w:)
levelParent <- _levelP <$> readRef parent
levelChild <- _levelP <$> readRef child
let d = levelParent - levelChild + 1
when (d > 0) $ do
parents <- Graph.dfs (P parent) getParents
forM_ parents $ \(P node) -> do
modify' node $ update levelP (subtract d)
getChildren :: SomeNode -> IO [SomeNode]
getChildren (P p) = deRefWeaks =<< fmap _childrenP (readRef p)
getChildren _ = return []
getParents :: SomeNode -> IO [SomeNode]
getParents (P p) = deRefWeaks =<< fmap _parentsP (readRef p)
getParents _ = return []