From 365d2db571fdde96fa9f32ce83b10ce5a9fd71de Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 2 Nov 2024 19:08:15 -0400 Subject: [PATCH] Make InvalidationSignal not generic over synchronicity --- crates/compute_graph/src/builder.rs | 49 +++++++++++++++-------------- crates/compute_graph/src/lib.rs | 42 +++++++++++-------------- 2 files changed, 44 insertions(+), 47 deletions(-) diff --git a/crates/compute_graph/src/builder.rs b/crates/compute_graph/src/builder.rs index 3c14bb4..d1a0bcb 100644 --- a/crates/compute_graph/src/builder.rs +++ b/crates/compute_graph/src/builder.rs @@ -103,13 +103,11 @@ impl GraphBuilder { pub fn add_invalidatable_value( &mut self, value: V, - ) -> (Input, ValueInvalidationSignal) { + ) -> (Input, ValueInvalidationSignal) { let input = self.add_node(InvalidatableConstNode::new(value)); let signal = ValueInvalidationSignal { - node_idx: input.node_idx, value: Rc::clone(&input.value), - graph: Rc::clone(&self.node_graph), - graph_is_valid: Rc::clone(&self.is_valid), + signal: self.make_invalidation_signal(&input), }; (input, signal) } @@ -162,16 +160,26 @@ impl GraphBuilder { pub fn add_invalidatable_rule( &mut self, rule: R, - ) -> (Input, InvalidationSignal) { + ) -> (Input, InvalidationSignal) { let input = self.add_rule(rule); - let signal = InvalidationSignal { - node_idx: Rc::new(Cell::new(Some(input.node_idx))), - graph: Rc::clone(&self.node_graph), - graph_is_valid: Rc::clone(&self.is_valid), - }; + let signal = self.make_invalidation_signal(&input); (input, signal) } + fn make_invalidation_signal(&self, input: &Input) -> InvalidationSignal { + let node_idx = input.node_idx; + let graph = Rc::clone(&self.node_graph); + let graph_is_valid = Rc::clone(&self.is_valid); + InvalidationSignal { + do_invalidate: Rc::new(Box::new(move || { + graph_is_valid.set(false); + let mut graph = graph.borrow_mut(); + let node = &mut graph[node_idx]; + node.invalidate(); + })), + } + } + /// Creates a graph from this builder, consuming the builder. /// /// To successfully build a graph, there must be an output node set (using either @@ -259,20 +267,13 @@ impl GraphBuilder { /// /// Returns an [`Input`] representing the newly-added node, which can be used to construct further rules, /// as well as an [`InvalidationSignal`] which can be used to indicate that the node has been invalidated. - pub fn add_invalidatable_async_rule(&mut self, mut f: F) -> Input - where - R: AsyncRule, - F: FnMut(InvalidationSignal) -> R, - { - let node_idx = Rc::new(Cell::new(None)); - let signal = InvalidationSignal { - node_idx: Rc::clone(&node_idx), - graph: Rc::clone(&self.node_graph), - graph_is_valid: Rc::clone(&self.is_valid), - }; - let input = self.add_async_rule(f(signal)); - node_idx.set(Some(input.node_idx)); - input + pub fn add_invalidatable_async_rule( + &mut self, + rule: R, + ) -> (Input, InvalidationSignal) { + let input = self.add_async_rule(rule); + let signal = self.make_invalidation_signal(&input); + (input, signal) } } diff --git a/crates/compute_graph/src/lib.rs b/crates/compute_graph/src/lib.rs index 0fbeb63..455a926 100644 --- a/crates/compute_graph/src/lib.rs +++ b/crates/compute_graph/src/lib.rs @@ -298,33 +298,25 @@ impl Graph { /// /// `InvalidationSignal` implements `Clone`, so the signal can be cloned and used from multiple places. // TODO: there's a lot happening here, make sure this doesn't create a reference cycle -// TODO: would be better if this didn't have to be generic over Synchronicity -pub struct InvalidationSignal { - node_idx: Rc>>, - graph: Rc>>, - graph_is_valid: Rc>, +pub struct InvalidationSignal { + do_invalidate: Rc ()>>, } -impl InvalidationSignal { +impl InvalidationSignal { /// Tell the graph that the node corresponding to this signal is now invalid. /// /// Note: Calling this method does not trigger a graph evaluation, it merely marks the corresponding /// node as invalid. The graph will not be re-evaluated until [`Graph::evaluate`] or /// [`Graph::evaluate_async`] is next called. pub fn invalidate(&self) { - self.graph_is_valid.set(false); - let mut graph = self.graph.borrow_mut(); - let node = &mut graph[self.node_idx.get().unwrap()]; - node.invalidate(); + (self.do_invalidate)(); } } -impl Clone for InvalidationSignal { +impl Clone for InvalidationSignal { fn clone(&self) -> Self { Self { - node_idx: Rc::clone(&self.node_idx), - graph: Rc::clone(&self.graph), - graph_is_valid: Rc::clone(&self.graph_is_valid), + do_invalidate: Rc::clone(&self.do_invalidate), } } } @@ -332,14 +324,12 @@ impl Clone for InvalidationSignal { /// A type representing a node with an externally injected value. /// /// See [`GraphBuilder::add_invalidatable_value`]. -pub struct ValueInvalidationSignal { - node_idx: NodeId, +pub struct ValueInvalidationSignal { value: Rc>>, - graph: Rc>>, - graph_is_valid: Rc>, + signal: InvalidationSignal, } -impl ValueInvalidationSignal { +impl ValueInvalidationSignal { /// Get a reference to current value for the node corresponding to this signal. pub fn value(&self) -> impl Deref + '_ { Ref::map(self.value.borrow(), |opt| { @@ -361,10 +351,16 @@ impl ValueInvalidationSignal { .node_value_eq(&value) { *current_value = Some(value); - self.graph_is_valid.set(false); - let mut graph = self.graph.borrow_mut(); - let node = &mut graph[self.node_idx]; - node.invalidate(); + self.signal.invalidate(); + } + } +} + +impl Clone for ValueInvalidationSignal { + fn clone(&self) -> Self { + Self { + value: Rc::clone(&self.value), + signal: self.signal.clone(), } } }