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>(
&mut self,
value: V,
) -> (Input<V>, ValueInvalidationSignal<V, S>) {
) -> (Input<V>, ValueInvalidationSignal<V>) {
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<O: 'static, S: Synchronicity> GraphBuilder<O, S> {
pub fn add_invalidatable_rule<R: Rule>(
&mut self,
rule: R,
) -> (Input<R::Output>, InvalidationSignal<S>) {
) -> (Input<R::Output>, 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<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.
///
/// 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,
/// 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>
where
R: AsyncRule,
F: FnMut(InvalidationSignal<Asynchronous>) -> 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<R: AsyncRule>(
&mut self,
rule: R,
) -> (Input<R::Output>, InvalidationSignal) {
let input = self.add_async_rule(rule);
let signal = self.make_invalidation_signal(&input);
(input, signal)
}
}

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.
// 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<Synch: Synchronicity> {
node_idx: Rc<Cell<Option<NodeId>>>,
graph: Rc<RefCell<NodeGraph<Synch>>>,
graph_is_valid: Rc<Cell<bool>>,
pub struct InvalidationSignal {
do_invalidate: Rc<Box<dyn Fn() -> ()>>,
}
impl<S: Synchronicity> InvalidationSignal<S> {
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<S: Synchronicity> Clone for InvalidationSignal<S> {
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<S: Synchronicity> Clone for InvalidationSignal<S> {
/// A type representing a node with an externally injected value.
///
/// See [`GraphBuilder::add_invalidatable_value`].
pub struct ValueInvalidationSignal<V, Synch: Synchronicity> {
node_idx: NodeId,
pub struct ValueInvalidationSignal<V> {
value: Rc<RefCell<Option<V>>>,
graph: Rc<RefCell<NodeGraph<Synch>>>,
graph_is_valid: Rc<Cell<bool>>,
signal: InvalidationSignal,
}
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.
pub fn value(&self) -> impl Deref<Target = V> + '_ {
Ref::map(self.value.borrow(), |opt| {
@ -361,10 +351,16 @@ impl<V: NodeValue, S: Synchronicity> ValueInvalidationSignal<V, S> {
.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<V> Clone for ValueInvalidationSignal<V> {
fn clone(&self) -> Self {
Self {
value: Rc::clone(&self.value),
signal: self.signal.clone(),
}
}
}