Make InvalidationSignal not generic over synchronicity

This commit is contained in:
Shadowfacts 2024-11-02 19:08:15 -04:00
parent a556b14188
commit 365d2db571
2 changed files with 44 additions and 47 deletions

View File

@ -103,13 +103,11 @@ impl<O: 'static, S: Synchronicity> GraphBuilder<O, S> {
pub fn add_invalidatable_value<V: NodeValue>( pub fn add_invalidatable_value<V: NodeValue>(
&mut self, &mut self,
value: V, value: V,
) -> (Input<V>, ValueInvalidationSignal<V, S>) { ) -> (Input<V>, ValueInvalidationSignal<V>) {
let input = self.add_node(InvalidatableConstNode::new(value)); let input = self.add_node(InvalidatableConstNode::new(value));
let signal = ValueInvalidationSignal { let signal = ValueInvalidationSignal {
node_idx: input.node_idx,
value: Rc::clone(&input.value), value: Rc::clone(&input.value),
graph: Rc::clone(&self.node_graph), signal: self.make_invalidation_signal(&input),
graph_is_valid: Rc::clone(&self.is_valid),
}; };
(input, signal) (input, signal)
} }
@ -162,16 +160,26 @@ impl<O: 'static, S: Synchronicity> GraphBuilder<O, S> {
pub fn add_invalidatable_rule<R: Rule>( pub fn add_invalidatable_rule<R: Rule>(
&mut self, &mut self,
rule: R, rule: R,
) -> (Input<R::Output>, InvalidationSignal<S>) { ) -> (Input<R::Output>, InvalidationSignal) {
let input = self.add_rule(rule); let input = self.add_rule(rule);
let signal = InvalidationSignal { let signal = self.make_invalidation_signal(&input);
node_idx: Rc::new(Cell::new(Some(input.node_idx))),
graph: Rc::clone(&self.node_graph),
graph_is_valid: Rc::clone(&self.is_valid),
};
(input, signal) (input, signal)
} }
fn make_invalidation_signal<V>(&self, input: &Input<V>) -> 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. /// Creates a graph from this builder, consuming the builder.
/// ///
/// To successfully build a graph, there must be an output node set (using either /// To successfully build a graph, there must be an output node set (using either
@ -259,20 +267,13 @@ impl<O: 'static> GraphBuilder<O, Asynchronous> {
/// ///
/// Returns an [`Input`] representing the newly-added node, which can be used to construct further rules, /// 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. /// as well as an [`InvalidationSignal`] which can be used to indicate that the node has been invalidated.
pub fn add_invalidatable_async_rule<R, F>(&mut self, mut f: F) -> Input<R::Output> pub fn add_invalidatable_async_rule<R: AsyncRule>(
where &mut self,
R: AsyncRule, rule: R,
F: FnMut(InvalidationSignal<Asynchronous>) -> R, ) -> (Input<R::Output>, InvalidationSignal) {
{ let input = self.add_async_rule(rule);
let node_idx = Rc::new(Cell::new(None)); let signal = self.make_invalidation_signal(&input);
let signal = InvalidationSignal { (input, signal)
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
} }
} }

View File

@ -298,33 +298,25 @@ impl<O: 'static> Graph<O, Asynchronous> {
/// ///
/// `InvalidationSignal` implements `Clone`, so the signal can be cloned and used from multiple places. /// `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: 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 {
pub struct InvalidationSignal<Synch: Synchronicity> { do_invalidate: Rc<Box<dyn Fn() -> ()>>,
node_idx: Rc<Cell<Option<NodeId>>>,
graph: Rc<RefCell<NodeGraph<Synch>>>,
graph_is_valid: Rc<Cell<bool>>,
} }
impl<S: Synchronicity> InvalidationSignal<S> { impl InvalidationSignal {
/// Tell the graph that the node corresponding to this signal is now invalid. /// 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 /// 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 /// node as invalid. The graph will not be re-evaluated until [`Graph::evaluate`] or
/// [`Graph::evaluate_async`] is next called. /// [`Graph::evaluate_async`] is next called.
pub fn invalidate(&self) { pub fn invalidate(&self) {
self.graph_is_valid.set(false); (self.do_invalidate)();
let mut graph = self.graph.borrow_mut();
let node = &mut graph[self.node_idx.get().unwrap()];
node.invalidate();
} }
} }
impl<S: Synchronicity> Clone for InvalidationSignal<S> { impl Clone for InvalidationSignal {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
node_idx: Rc::clone(&self.node_idx), do_invalidate: Rc::clone(&self.do_invalidate),
graph: Rc::clone(&self.graph),
graph_is_valid: Rc::clone(&self.graph_is_valid),
} }
} }
} }
@ -332,14 +324,12 @@ impl<S: Synchronicity> Clone for InvalidationSignal<S> {
/// A type representing a node with an externally injected value. /// A type representing a node with an externally injected value.
/// ///
/// See [`GraphBuilder::add_invalidatable_value`]. /// See [`GraphBuilder::add_invalidatable_value`].
pub struct ValueInvalidationSignal<V, Synch: Synchronicity> { pub struct ValueInvalidationSignal<V> {
node_idx: NodeId,
value: Rc<RefCell<Option<V>>>, value: Rc<RefCell<Option<V>>>,
graph: Rc<RefCell<NodeGraph<Synch>>>, signal: InvalidationSignal,
graph_is_valid: Rc<Cell<bool>>,
} }
impl<V: NodeValue, S: Synchronicity> ValueInvalidationSignal<V, S> { impl<V: NodeValue> ValueInvalidationSignal<V> {
/// Get a reference to current value for the node corresponding to this signal. /// Get a reference to current value for the node corresponding to this signal.
pub fn value(&self) -> impl Deref<Target = V> + '_ { pub fn value(&self) -> impl Deref<Target = V> + '_ {
Ref::map(self.value.borrow(), |opt| { Ref::map(self.value.borrow(), |opt| {
@ -361,10 +351,16 @@ impl<V: NodeValue, S: Synchronicity> ValueInvalidationSignal<V, S> {
.node_value_eq(&value) .node_value_eq(&value)
{ {
*current_value = Some(value); *current_value = Some(value);
self.graph_is_valid.set(false); self.signal.invalidate();
let mut graph = self.graph.borrow_mut(); }
let node = &mut graph[self.node_idx]; }
node.invalidate(); }
impl<V> Clone for ValueInvalidationSignal<V> {
fn clone(&self) -> Self {
Self {
value: Rc::clone(&self.value),
signal: self.signal.clone(),
} }
} }
} }