Split graph crate into multiple files
This commit is contained in:
parent
6de1999b8d
commit
a6e94340ee
153
crates/graph/src/builder.rs
Normal file
153
crates/graph/src/builder.rs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
use crate::node::{AsyncRuleNode, ConstNode, Node, RuleNode};
|
||||||
|
use crate::util;
|
||||||
|
use crate::{
|
||||||
|
AsyncRule, Asynchronous, ErasedNode, Graph, Input, InvalidationSignal, NodeGraph, NodeId, Rule,
|
||||||
|
Synchronicity, Synchronous,
|
||||||
|
};
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct GraphBuilder<Output, Synch: Synchronicity> {
|
||||||
|
pub(crate) node_graph: Rc<RefCell<NodeGraph<Synch>>>,
|
||||||
|
pub(crate) output: Option<Input<Output>>,
|
||||||
|
pub(crate) output_type: std::marker::PhantomData<Output>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: 'static> GraphBuilder<O, Synchronous> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
node_graph: Rc::new(RefCell::new(NodeGraph::new())),
|
||||||
|
output: None,
|
||||||
|
output_type: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: 'static> GraphBuilder<O, Asynchronous> {
|
||||||
|
pub fn new_async() -> Self {
|
||||||
|
Self {
|
||||||
|
node_graph: Rc::new(RefCell::new(NodeGraph::new())),
|
||||||
|
output: None,
|
||||||
|
output_type: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: 'static, S: Synchronicity> GraphBuilder<O, S> {
|
||||||
|
pub fn set_output<R: Rule<Output = O>>(&mut self, rule: R) {
|
||||||
|
let input = self.add_rule(rule);
|
||||||
|
self.output = Some(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_node<V: 'static>(&mut self, node: impl Node<V, S> + 'static) -> Input<V> {
|
||||||
|
let value = Rc::clone(node.value_rc());
|
||||||
|
let erased = ErasedNode::new(node);
|
||||||
|
let idx = self.node_graph.borrow_mut().add_node(erased);
|
||||||
|
Input {
|
||||||
|
node_idx: idx,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_value<V: 'static>(&mut self, value: V) -> Input<V> {
|
||||||
|
return self.add_node(ConstNode::new(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_rule<R>(&mut self, rule: R) -> Input<R::Output>
|
||||||
|
where
|
||||||
|
R: Rule,
|
||||||
|
{
|
||||||
|
return self.add_node(RuleNode::new(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_invalidatable_rule<R, F>(&mut self, mut f: F) -> Input<R::Output>
|
||||||
|
where
|
||||||
|
R: Rule,
|
||||||
|
F: FnMut(InvalidationSignal<S>) -> R,
|
||||||
|
{
|
||||||
|
let node_idx = Rc::new(Cell::new(None));
|
||||||
|
let signal = InvalidationSignal {
|
||||||
|
node_idx: Rc::clone(&node_idx),
|
||||||
|
graph: Rc::clone(&self.node_graph),
|
||||||
|
};
|
||||||
|
let input = self.add_rule(f(signal));
|
||||||
|
node_idx.set(Some(input.node_idx));
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Result<Graph<O, S>, BuildGraphError> {
|
||||||
|
let output: &Input<O> = match &self.output {
|
||||||
|
None => return Err(BuildGraphError::NoOutput),
|
||||||
|
Some(output) => output,
|
||||||
|
};
|
||||||
|
|
||||||
|
let graph = self.node_graph.borrow();
|
||||||
|
let indices = graph.node_indices().collect::<Vec<_>>();
|
||||||
|
drop(graph);
|
||||||
|
let mut edges = vec![];
|
||||||
|
for idx in indices {
|
||||||
|
let node = &mut self.node_graph.borrow_mut()[idx];
|
||||||
|
node.visit_inputs(&mut |input_idx| {
|
||||||
|
edges.push((input_idx, idx));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (source, dest) in edges {
|
||||||
|
self.node_graph.borrow_mut().add_edge(source, dest, ());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut graph = self.node_graph.borrow_mut();
|
||||||
|
util::remove_nodes_not_connected_to(&mut *graph, output.node_idx);
|
||||||
|
drop(graph);
|
||||||
|
|
||||||
|
let sorted = petgraph::algo::toposort(&**self.node_graph.borrow(), None);
|
||||||
|
if let Err(_cycle) = sorted {
|
||||||
|
self.node_graph.borrow_mut().clear_edges();
|
||||||
|
// TODO: actually build a vec describing the cycle path for debugging
|
||||||
|
return Err(BuildGraphError::Cyclic(vec![]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let graph = Graph {
|
||||||
|
node_graph: self.node_graph,
|
||||||
|
output: self.output.unwrap(),
|
||||||
|
output_type: std::marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(graph)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: 'static> GraphBuilder<O, Asynchronous> {
|
||||||
|
pub fn set_async_output<R: AsyncRule<Output = O>>(&mut self, rule: R) {
|
||||||
|
let input = self.add_async_rule(rule);
|
||||||
|
self.output = Some(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_async_rule<R>(&mut self, rule: R) -> Input<R::Output>
|
||||||
|
where
|
||||||
|
R: AsyncRule,
|
||||||
|
{
|
||||||
|
self.add_node(AsyncRuleNode::new(rule))
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
let input = self.add_async_rule(f(signal));
|
||||||
|
node_idx.set(Some(input.node_idx));
|
||||||
|
input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BuildGraphError {
|
||||||
|
NoOutput,
|
||||||
|
Cyclic(Vec<NodeId>),
|
||||||
|
}
|
@ -1,18 +1,28 @@
|
|||||||
|
mod builder;
|
||||||
|
mod node;
|
||||||
|
mod synchronicity;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
use builder::{BuildGraphError, GraphBuilder};
|
||||||
|
use node::ErasedNode;
|
||||||
use petgraph::visit::{IntoEdgeReferences, NodeIndexable};
|
use petgraph::visit::{IntoEdgeReferences, NodeIndexable};
|
||||||
use petgraph::{graph::NodeIndex, stable_graph::StableDiGraph, visit::EdgeRef};
|
use petgraph::{stable_graph::StableDiGraph, visit::EdgeRef};
|
||||||
use std::any::Any;
|
|
||||||
use std::cell::{Cell, Ref, RefCell};
|
use std::cell::{Cell, Ref, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::future::Future;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::pin::Pin;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use synchronicity::*;
|
||||||
|
|
||||||
// use a struct for this, not a type alias, because generic bounds of type aliases aren't enforced
|
// use a struct for this, not a type alias, because generic bounds of type aliases aren't enforced
|
||||||
struct NodeGraph<S: Synchronicity>(StableDiGraph<ErasedNode<S>, (), u32>);
|
struct NodeGraph<S: Synchronicity>(StableDiGraph<ErasedNode<S>, (), u32>);
|
||||||
|
type NodeId = petgraph::stable_graph::NodeIndex<u32>;
|
||||||
|
|
||||||
|
impl<S: Synchronicity> NodeGraph<S> {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self(StableDiGraph::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: Synchronicity> Deref for NodeGraph<S> {
|
impl<S: Synchronicity> Deref for NodeGraph<S> {
|
||||||
type Target = StableDiGraph<ErasedNode<S>, (), u32>;
|
type Target = StableDiGraph<ErasedNode<S>, (), u32>;
|
||||||
@ -28,200 +38,6 @@ impl<S: Synchronicity> DerefMut for NodeGraph<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Synchronicity: 'static {
|
|
||||||
type UpdateFn;
|
|
||||||
fn make_update_fn<V: 'static>() -> Self::UpdateFn;
|
|
||||||
|
|
||||||
type UpdateResult<'a>;
|
|
||||||
fn make_update_result<'a>() -> Self::UpdateResult<'a>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Synchronous;
|
|
||||||
|
|
||||||
impl Synchronicity for Synchronous {
|
|
||||||
type UpdateFn = Box<dyn Fn(&mut Box<dyn Any>) -> ()>;
|
|
||||||
|
|
||||||
fn make_update_fn<V: 'static>() -> Self::UpdateFn {
|
|
||||||
Box::new(|any| {
|
|
||||||
let x = any.downcast_mut::<Box<dyn Node<V, Self>>>().unwrap();
|
|
||||||
x.update();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type UpdateResult<'a> = ();
|
|
||||||
|
|
||||||
fn make_update_result<'a>() -> Self::UpdateResult<'a> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Asynchronous;
|
|
||||||
|
|
||||||
impl Synchronicity for Asynchronous {
|
|
||||||
type UpdateFn =
|
|
||||||
Box<dyn for<'a> Fn(&'a mut Box<dyn Any>) -> Pin<Box<dyn Future<Output = ()> + 'a>>>;
|
|
||||||
|
|
||||||
fn make_update_fn<V: 'static>() -> Self::UpdateFn {
|
|
||||||
Box::new(|any| Box::pin(Asynchronous::do_async_update::<V>(any)))
|
|
||||||
}
|
|
||||||
|
|
||||||
type UpdateResult<'a> = Pin<Box<dyn Future<Output = ()> + 'a>>;
|
|
||||||
|
|
||||||
fn make_update_result<'a>() -> Self::UpdateResult<'a> {
|
|
||||||
Box::pin(std::future::ready(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Asynchronous {
|
|
||||||
async fn do_async_update<V: 'static>(any: &mut Box<dyn Any>) {
|
|
||||||
let x = any.downcast_mut::<Box<dyn Node<V, Self>>>().unwrap();
|
|
||||||
x.update().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GraphBuilder<Output, Synch: Synchronicity> {
|
|
||||||
node_graph: Rc<RefCell<NodeGraph<Synch>>>,
|
|
||||||
output: Option<Input<Output>>,
|
|
||||||
output_type: std::marker::PhantomData<Output>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: 'static> GraphBuilder<O, Synchronous> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
node_graph: Rc::new(RefCell::new(NodeGraph(StableDiGraph::new()))),
|
|
||||||
output: None,
|
|
||||||
output_type: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: 'static> GraphBuilder<O, Asynchronous> {
|
|
||||||
pub fn new_async() -> Self {
|
|
||||||
Self {
|
|
||||||
node_graph: Rc::new(RefCell::new(NodeGraph(StableDiGraph::new()))),
|
|
||||||
output: None,
|
|
||||||
output_type: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: 'static, S: Synchronicity> GraphBuilder<O, S> {
|
|
||||||
pub fn set_output<R: Rule<Output = O>>(&mut self, rule: R) {
|
|
||||||
let input = self.add_rule(rule);
|
|
||||||
self.output = Some(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_node<V: 'static>(&mut self, node: impl Node<V, S> + 'static) -> Input<V> {
|
|
||||||
let value = Rc::clone(node.value_rc());
|
|
||||||
let erased = ErasedNode::new(node);
|
|
||||||
let idx = self.node_graph.borrow_mut().add_node(erased);
|
|
||||||
Input {
|
|
||||||
node_idx: idx,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_value<V: 'static>(&mut self, value: V) -> Input<V> {
|
|
||||||
return self.add_node(ConstNode::new(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rule<R>(&mut self, rule: R) -> Input<R::Output>
|
|
||||||
where
|
|
||||||
R: Rule,
|
|
||||||
{
|
|
||||||
return self.add_node(RuleNode::new(rule));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_invalidatable_rule<R, F>(&mut self, mut f: F) -> Input<R::Output>
|
|
||||||
where
|
|
||||||
R: Rule,
|
|
||||||
F: FnMut(InvalidationSignal<S>) -> R,
|
|
||||||
{
|
|
||||||
let node_idx = Rc::new(Cell::new(None));
|
|
||||||
let signal = InvalidationSignal {
|
|
||||||
node_idx: Rc::clone(&node_idx),
|
|
||||||
graph: Rc::clone(&self.node_graph),
|
|
||||||
};
|
|
||||||
let input = self.add_rule(f(signal));
|
|
||||||
node_idx.set(Some(input.node_idx));
|
|
||||||
input
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> Result<Graph<O, S>, BuildGraphError> {
|
|
||||||
let output: &Input<O> = match &self.output {
|
|
||||||
None => return Err(BuildGraphError::NoOutput),
|
|
||||||
Some(output) => output,
|
|
||||||
};
|
|
||||||
|
|
||||||
let graph = self.node_graph.borrow();
|
|
||||||
let indices = graph.node_indices().collect::<Vec<_>>();
|
|
||||||
drop(graph);
|
|
||||||
let mut edges = vec![];
|
|
||||||
for idx in indices {
|
|
||||||
let node = &mut self.node_graph.borrow_mut()[idx];
|
|
||||||
node.visit_inputs(&mut |input_idx| {
|
|
||||||
edges.push((input_idx, idx));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (source, dest) in edges {
|
|
||||||
self.node_graph.borrow_mut().add_edge(source, dest, ());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut graph = self.node_graph.borrow_mut();
|
|
||||||
util::remove_nodes_not_connected_to(&mut *graph, output.node_idx);
|
|
||||||
drop(graph);
|
|
||||||
|
|
||||||
let sorted = petgraph::algo::toposort(&**self.node_graph.borrow(), None);
|
|
||||||
if let Err(_cycle) = sorted {
|
|
||||||
self.node_graph.borrow_mut().clear_edges();
|
|
||||||
// TODO: actually build a vec describing the cycle path for debugging
|
|
||||||
return Err(BuildGraphError::Cyclic(vec![]));
|
|
||||||
}
|
|
||||||
|
|
||||||
let graph = Graph {
|
|
||||||
node_graph: self.node_graph,
|
|
||||||
output: self.output.unwrap(),
|
|
||||||
output_type: std::marker::PhantomData,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(graph)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: 'static> GraphBuilder<O, Asynchronous> {
|
|
||||||
pub fn set_async_output<R: AsyncRule<Output = O>>(&mut self, rule: R) {
|
|
||||||
let input = self.add_async_rule(rule);
|
|
||||||
self.output = Some(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_async_rule<R>(&mut self, rule: R) -> Input<R::Output>
|
|
||||||
where
|
|
||||||
R: AsyncRule,
|
|
||||||
{
|
|
||||||
self.add_node(AsyncRuleNode::new(rule))
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
let input = self.add_async_rule(f(signal));
|
|
||||||
node_idx.set(Some(input.node_idx));
|
|
||||||
input
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum BuildGraphError {
|
|
||||||
NoOutput,
|
|
||||||
Cyclic(Vec<NodeIndex<u32>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Graph<Output, Synch: Synchronicity> {
|
pub struct Graph<Output, Synch: Synchronicity> {
|
||||||
node_graph: Rc<RefCell<NodeGraph<Synch>>>,
|
node_graph: Rc<RefCell<NodeGraph<Synch>>>,
|
||||||
output: Input<Output>,
|
output: Input<Output>,
|
||||||
@ -287,7 +103,7 @@ impl<O: 'static, S: Synchronicity> Graph<O, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<O: 'static> Graph<O, Synchronous> {
|
impl<O: 'static> Graph<O, Synchronous> {
|
||||||
fn update_node(&mut self, idx: NodeIndex<u32>) {
|
fn update_node(&mut self, idx: NodeId) {
|
||||||
let graph = self.node_graph.borrow();
|
let graph = self.node_graph.borrow();
|
||||||
let node = &graph[idx];
|
let node = &graph[idx];
|
||||||
if !node.is_valid() {
|
if !node.is_valid() {
|
||||||
@ -307,7 +123,7 @@ impl<O: 'static> Graph<O, Synchronous> {
|
|||||||
|
|
||||||
let node = &mut self.node_graph.borrow_mut()[idx];
|
let node = &mut self.node_graph.borrow_mut()[idx];
|
||||||
// Actually update the node's value.
|
// Actually update the node's value.
|
||||||
(node.update)(&mut node.any);
|
node.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +134,7 @@ impl<O: 'static> Graph<O, Synchronous> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<O: 'static> Graph<O, Asynchronous> {
|
impl<O: 'static> Graph<O, Asynchronous> {
|
||||||
async fn update_node_async(&mut self, idx: NodeIndex<u32>) {
|
async fn update_node_async(&mut self, idx: NodeId) {
|
||||||
// TODO: same note about recursing as above, and consider doing this in parallel
|
// TODO: same note about recursing as above, and consider doing this in parallel
|
||||||
let graph = self.node_graph.borrow();
|
let graph = self.node_graph.borrow();
|
||||||
let node = &graph[idx];
|
let node = &graph[idx];
|
||||||
@ -335,7 +151,7 @@ impl<O: 'static> Graph<O, Asynchronous> {
|
|||||||
|
|
||||||
let mut graph = self.node_graph.borrow_mut();
|
let mut graph = self.node_graph.borrow_mut();
|
||||||
let node = &mut graph[idx];
|
let node = &mut graph[idx];
|
||||||
(node.update)(&mut node.any).await;
|
node.update().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +163,7 @@ impl<O: 'static> Graph<O, Asynchronous> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Input<T> {
|
pub struct Input<T> {
|
||||||
node_idx: NodeIndex<u32>,
|
node_idx: NodeId,
|
||||||
value: Rc<RefCell<Option<T>>>,
|
value: Rc<RefCell<Option<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +188,7 @@ impl<T> Clone for Input<T> {
|
|||||||
|
|
||||||
// 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
|
||||||
pub struct InvalidationSignal<Synch: Synchronicity> {
|
pub struct InvalidationSignal<Synch: Synchronicity> {
|
||||||
node_idx: Rc<Cell<Option<NodeIndex<u32>>>>,
|
node_idx: Rc<Cell<Option<NodeId>>>,
|
||||||
graph: Rc<RefCell<NodeGraph<Synch>>>,
|
graph: Rc<RefCell<NodeGraph<Synch>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,10 +200,7 @@ impl<S: Synchronicity> InvalidationSignal<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalidate_nodes<S: Synchronicity>(
|
fn invalidate_nodes<S: Synchronicity>(graph: &mut NodeGraph<S>, mut queue: VecDeque<NodeId>) {
|
||||||
graph: &mut NodeGraph<S>,
|
|
||||||
mut queue: VecDeque<NodeIndex<u32>>,
|
|
||||||
) {
|
|
||||||
while let Some(idx) = queue.pop_front() {
|
while let Some(idx) = queue.pop_front() {
|
||||||
let node = &mut graph[idx];
|
let node = &mut graph[idx];
|
||||||
if node.is_valid() {
|
if node.is_valid() {
|
||||||
@ -402,189 +215,6 @@ fn invalidate_nodes<S: Synchronicity>(
|
|||||||
|
|
||||||
// TODO: i really want Input to be able to implement Deref somehow
|
// TODO: i really want Input to be able to implement Deref somehow
|
||||||
|
|
||||||
pub struct ErasedNode<Synch: Synchronicity> {
|
|
||||||
any: Box<dyn Any>,
|
|
||||||
is_valid: Box<dyn Fn(&Box<dyn Any>) -> bool>,
|
|
||||||
invalidate: Box<dyn Fn(&mut Box<dyn Any>) -> ()>,
|
|
||||||
visit_inputs: Box<dyn Fn(&Box<dyn Any>, &mut dyn FnMut(NodeIndex<u32>) -> ()) -> ()>,
|
|
||||||
update: Synch::UpdateFn,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Synchronicity> ErasedNode<S> {
|
|
||||||
fn new<N: Node<V, S> + 'static, V: 'static>(base: N) -> Self {
|
|
||||||
// i don't love the double boxing, but i'm not sure how else to do this
|
|
||||||
let thing: Box<dyn Node<V, S>> = Box::new(base);
|
|
||||||
let any: Box<dyn Any> = Box::new(thing);
|
|
||||||
Self {
|
|
||||||
any,
|
|
||||||
is_valid: Box::new(|any| {
|
|
||||||
let x = any.downcast_ref::<Box<dyn Node<V, S>>>().unwrap();
|
|
||||||
x.is_valid()
|
|
||||||
}),
|
|
||||||
invalidate: Box::new(|any| {
|
|
||||||
let x = any.downcast_mut::<Box<dyn Node<V, S>>>().unwrap();
|
|
||||||
x.invalidate();
|
|
||||||
}),
|
|
||||||
visit_inputs: Box::new(|any, visitor| {
|
|
||||||
let x = any.downcast_ref::<Box<dyn Node<V, S>>>().unwrap();
|
|
||||||
x.visit_inputs(visitor);
|
|
||||||
}),
|
|
||||||
update: S::make_update_fn::<V>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_valid(&self) -> bool {
|
|
||||||
(self.is_valid)(&self.any)
|
|
||||||
}
|
|
||||||
fn invalidate(&mut self) {
|
|
||||||
(self.invalidate)(&mut self.any);
|
|
||||||
}
|
|
||||||
fn visit_inputs(&self, f: &mut dyn FnMut(NodeIndex<u32>) -> ()) {
|
|
||||||
(self.visit_inputs)(&self.any, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Node<Value: 'static, Synch: Synchronicity> {
|
|
||||||
fn is_valid(&self) -> bool;
|
|
||||||
fn invalidate(&mut self);
|
|
||||||
fn visit_inputs(&self, visitor: &mut dyn FnMut(NodeIndex<u32>) -> ());
|
|
||||||
fn update(&mut self) -> Synch::UpdateResult<'_>;
|
|
||||||
fn value_rc(&self) -> &Rc<RefCell<Option<Value>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ConstNode<V, S> {
|
|
||||||
value: Rc<RefCell<Option<V>>>,
|
|
||||||
synchronicity: std::marker::PhantomData<S>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V, S> ConstNode<V, S> {
|
|
||||||
fn new(value: V) -> Self {
|
|
||||||
Self {
|
|
||||||
value: Rc::new(RefCell::new(Some(value))),
|
|
||||||
synchronicity: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: 'static, S: Synchronicity> Node<V, S> for ConstNode<V, S> {
|
|
||||||
fn is_valid(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invalidate(&mut self) {}
|
|
||||||
|
|
||||||
fn visit_inputs(&self, _visitor: &mut dyn FnMut(NodeIndex<u32>) -> ()) {}
|
|
||||||
|
|
||||||
fn update(&mut self) -> S::UpdateResult<'_> {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value_rc(&self) -> &Rc<RefCell<Option<V>>> {
|
|
||||||
&self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RuleNode<R, V, S> {
|
|
||||||
rule: R,
|
|
||||||
value: Rc<RefCell<Option<V>>>,
|
|
||||||
valid: bool,
|
|
||||||
synchronicity: std::marker::PhantomData<S>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Rule, S> RuleNode<R, R::Output, S> {
|
|
||||||
fn new(rule: R) -> Self {
|
|
||||||
Self {
|
|
||||||
rule,
|
|
||||||
value: Rc::new(RefCell::new(None)),
|
|
||||||
valid: false,
|
|
||||||
synchronicity: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Rule, S: Synchronicity> Node<R::Output, S> for RuleNode<R, R::Output, S> {
|
|
||||||
fn is_valid(&self) -> bool {
|
|
||||||
self.valid
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invalidate(&mut self) {
|
|
||||||
self.valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_inputs(&self, visitor: &mut dyn FnMut(NodeIndex<u32>) -> ()) {
|
|
||||||
struct InputIndexVisitor<'a>(&'a mut dyn FnMut(NodeIndex<u32>) -> ());
|
|
||||||
impl<'a> InputVisitor for InputIndexVisitor<'a> {
|
|
||||||
fn visit<T>(&mut self, input: &Input<T>) {
|
|
||||||
self.0(input.node_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.rule.visit_inputs(&mut InputIndexVisitor(visitor));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self) -> S::UpdateResult<'_> {
|
|
||||||
let new_value = self.rule.evaluate();
|
|
||||||
self.valid = true;
|
|
||||||
*self.value.borrow_mut() = Some(new_value);
|
|
||||||
S::make_update_result()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value_rc(&self) -> &Rc<RefCell<Option<R::Output>>> {
|
|
||||||
&self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AsyncRuleNode<R, V> {
|
|
||||||
rule: R,
|
|
||||||
value: Rc<RefCell<Option<V>>>,
|
|
||||||
valid: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: AsyncRule> AsyncRuleNode<R, R::Output> {
|
|
||||||
fn new(rule: R) -> Self {
|
|
||||||
Self {
|
|
||||||
rule,
|
|
||||||
value: Rc::new(RefCell::new(None)),
|
|
||||||
valid: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: AsyncRule> Node<R::Output, Asynchronous> for AsyncRuleNode<R, R::Output> {
|
|
||||||
fn is_valid(&self) -> bool {
|
|
||||||
self.valid
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invalidate(&mut self) {
|
|
||||||
self.valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_inputs(&self, visitor: &mut dyn FnMut(NodeIndex<u32>) -> ()) {
|
|
||||||
struct InputIndexVisitor<'a>(&'a mut dyn FnMut(NodeIndex<u32>) -> ());
|
|
||||||
impl<'a> InputVisitor for InputIndexVisitor<'a> {
|
|
||||||
fn visit<T>(&mut self, input: &Input<T>) {
|
|
||||||
self.0(input.node_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.rule.visit_inputs(&mut InputIndexVisitor(visitor));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self) -> <Asynchronous as Synchronicity>::UpdateResult<'_> {
|
|
||||||
Box::pin(self.do_update())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value_rc(&self) -> &Rc<RefCell<Option<R::Output>>> {
|
|
||||||
&self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: AsyncRule> AsyncRuleNode<R, R::Output> {
|
|
||||||
async fn do_update(&mut self) {
|
|
||||||
let new_value = self.rule.evaluate().await;
|
|
||||||
self.valid = true;
|
|
||||||
*self.value.borrow_mut() = Some(new_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Rule: 'static {
|
pub trait Rule: 'static {
|
||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
|
200
crates/graph/src/node.rs
Normal file
200
crates/graph/src/node.rs
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
use crate::synchronicity::{Asynchronous, Synchronicity};
|
||||||
|
use crate::{AsyncRule, Input, InputVisitor, NodeId, Rule, Synchronous};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub(crate) struct ErasedNode<Synch: Synchronicity> {
|
||||||
|
any: Box<dyn Any>,
|
||||||
|
is_valid: Box<dyn Fn(&Box<dyn Any>) -> bool>,
|
||||||
|
invalidate: Box<dyn Fn(&mut Box<dyn Any>) -> ()>,
|
||||||
|
visit_inputs: Box<dyn Fn(&Box<dyn Any>, &mut dyn FnMut(NodeId) -> ()) -> ()>,
|
||||||
|
update: Synch::UpdateFn,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Synchronicity> ErasedNode<S> {
|
||||||
|
pub(crate) fn new<N: Node<V, S> + 'static, V: 'static>(base: N) -> Self {
|
||||||
|
// i don't love the double boxing, but i'm not sure how else to do this
|
||||||
|
let thing: Box<dyn Node<V, S>> = Box::new(base);
|
||||||
|
let any: Box<dyn Any> = Box::new(thing);
|
||||||
|
Self {
|
||||||
|
any,
|
||||||
|
is_valid: Box::new(|any| {
|
||||||
|
let x = any.downcast_ref::<Box<dyn Node<V, S>>>().unwrap();
|
||||||
|
x.is_valid()
|
||||||
|
}),
|
||||||
|
invalidate: Box::new(|any| {
|
||||||
|
let x = any.downcast_mut::<Box<dyn Node<V, S>>>().unwrap();
|
||||||
|
x.invalidate();
|
||||||
|
}),
|
||||||
|
visit_inputs: Box::new(|any, visitor| {
|
||||||
|
let x = any.downcast_ref::<Box<dyn Node<V, S>>>().unwrap();
|
||||||
|
x.visit_inputs(visitor);
|
||||||
|
}),
|
||||||
|
update: S::make_update_fn::<V>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_valid(&self) -> bool {
|
||||||
|
(self.is_valid)(&self.any)
|
||||||
|
}
|
||||||
|
pub(crate) fn invalidate(&mut self) {
|
||||||
|
(self.invalidate)(&mut self.any);
|
||||||
|
}
|
||||||
|
pub(crate) fn visit_inputs(&self, f: &mut dyn FnMut(NodeId) -> ()) {
|
||||||
|
(self.visit_inputs)(&self.any, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErasedNode<Synchronous> {
|
||||||
|
pub(crate) fn update(&mut self) {
|
||||||
|
(self.update)(&mut self.any)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErasedNode<Asynchronous> {
|
||||||
|
pub(crate) async fn update(&mut self) {
|
||||||
|
(self.update)(&mut self.any).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait Node<Value: 'static, Synch: Synchronicity> {
|
||||||
|
fn is_valid(&self) -> bool;
|
||||||
|
fn invalidate(&mut self);
|
||||||
|
fn visit_inputs(&self, visitor: &mut dyn FnMut(NodeId) -> ());
|
||||||
|
fn update(&mut self) -> Synch::UpdateResult<'_>;
|
||||||
|
fn value_rc(&self) -> &Rc<RefCell<Option<Value>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ConstNode<V, S> {
|
||||||
|
value: Rc<RefCell<Option<V>>>,
|
||||||
|
synchronicity: std::marker::PhantomData<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, S> ConstNode<V, S> {
|
||||||
|
pub(crate) fn new(value: V) -> Self {
|
||||||
|
Self {
|
||||||
|
value: Rc::new(RefCell::new(Some(value))),
|
||||||
|
synchronicity: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: 'static, S: Synchronicity> Node<V, S> for ConstNode<V, S> {
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalidate(&mut self) {}
|
||||||
|
|
||||||
|
fn visit_inputs(&self, _visitor: &mut dyn FnMut(NodeId) -> ()) {}
|
||||||
|
|
||||||
|
fn update(&mut self) -> S::UpdateResult<'_> {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_rc(&self) -> &Rc<RefCell<Option<V>>> {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct RuleNode<R, V, S> {
|
||||||
|
rule: R,
|
||||||
|
value: Rc<RefCell<Option<V>>>,
|
||||||
|
valid: bool,
|
||||||
|
synchronicity: std::marker::PhantomData<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Rule, S> RuleNode<R, R::Output, S> {
|
||||||
|
pub(crate) fn new(rule: R) -> Self {
|
||||||
|
Self {
|
||||||
|
rule,
|
||||||
|
value: Rc::new(RefCell::new(None)),
|
||||||
|
valid: false,
|
||||||
|
synchronicity: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Rule, S: Synchronicity> Node<R::Output, S> for RuleNode<R, R::Output, S> {
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
self.valid
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalidate(&mut self) {
|
||||||
|
self.valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_inputs(&self, visitor: &mut dyn FnMut(NodeId) -> ()) {
|
||||||
|
struct InputIndexVisitor<'a>(&'a mut dyn FnMut(NodeId) -> ());
|
||||||
|
impl<'a> InputVisitor for InputIndexVisitor<'a> {
|
||||||
|
fn visit<T>(&mut self, input: &Input<T>) {
|
||||||
|
self.0(input.node_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.rule.visit_inputs(&mut InputIndexVisitor(visitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self) -> S::UpdateResult<'_> {
|
||||||
|
let new_value = self.rule.evaluate();
|
||||||
|
self.valid = true;
|
||||||
|
*self.value.borrow_mut() = Some(new_value);
|
||||||
|
S::make_update_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_rc(&self) -> &Rc<RefCell<Option<R::Output>>> {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct AsyncRuleNode<R, V> {
|
||||||
|
rule: R,
|
||||||
|
value: Rc<RefCell<Option<V>>>,
|
||||||
|
valid: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: AsyncRule> AsyncRuleNode<R, R::Output> {
|
||||||
|
pub(crate) fn new(rule: R) -> Self {
|
||||||
|
Self {
|
||||||
|
rule,
|
||||||
|
value: Rc::new(RefCell::new(None)),
|
||||||
|
valid: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: AsyncRule> Node<R::Output, Asynchronous> for AsyncRuleNode<R, R::Output> {
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
self.valid
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalidate(&mut self) {
|
||||||
|
self.valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_inputs(&self, visitor: &mut dyn FnMut(NodeId) -> ()) {
|
||||||
|
struct InputIndexVisitor<'a>(&'a mut dyn FnMut(NodeId) -> ());
|
||||||
|
impl<'a> InputVisitor for InputIndexVisitor<'a> {
|
||||||
|
fn visit<T>(&mut self, input: &Input<T>) {
|
||||||
|
self.0(input.node_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.rule.visit_inputs(&mut InputIndexVisitor(visitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self) -> <Asynchronous as Synchronicity>::UpdateResult<'_> {
|
||||||
|
Box::pin(self.do_update())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_rc(&self) -> &Rc<RefCell<Option<R::Output>>> {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: AsyncRule> AsyncRuleNode<R, R::Output> {
|
||||||
|
async fn do_update(&mut self) {
|
||||||
|
let new_value = self.rule.evaluate().await;
|
||||||
|
self.valid = true;
|
||||||
|
*self.value.borrow_mut() = Some(new_value);
|
||||||
|
}
|
||||||
|
}
|
53
crates/graph/src/synchronicity.rs
Normal file
53
crates/graph/src/synchronicity.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use crate::node::Node;
|
||||||
|
use std::any::Any;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
pub trait Synchronicity: 'static {
|
||||||
|
type UpdateFn;
|
||||||
|
fn make_update_fn<V: 'static>() -> Self::UpdateFn;
|
||||||
|
|
||||||
|
type UpdateResult<'a>;
|
||||||
|
fn make_update_result<'a>() -> Self::UpdateResult<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Synchronous;
|
||||||
|
|
||||||
|
impl Synchronicity for Synchronous {
|
||||||
|
type UpdateFn = Box<dyn Fn(&mut Box<dyn Any>) -> ()>;
|
||||||
|
|
||||||
|
fn make_update_fn<V: 'static>() -> Self::UpdateFn {
|
||||||
|
Box::new(|any| {
|
||||||
|
let x = any.downcast_mut::<Box<dyn Node<V, Self>>>().unwrap();
|
||||||
|
x.update();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateResult<'a> = ();
|
||||||
|
|
||||||
|
fn make_update_result<'a>() -> Self::UpdateResult<'a> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Asynchronous;
|
||||||
|
|
||||||
|
impl Synchronicity for Asynchronous {
|
||||||
|
type UpdateFn =
|
||||||
|
Box<dyn for<'a> Fn(&'a mut Box<dyn Any>) -> Pin<Box<dyn Future<Output = ()> + 'a>>>;
|
||||||
|
|
||||||
|
fn make_update_fn<V: 'static>() -> Self::UpdateFn {
|
||||||
|
Box::new(|any| Box::pin(Asynchronous::do_async_update::<V>(any)))
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateResult<'a> = Pin<Box<dyn Future<Output = ()> + 'a>>;
|
||||||
|
|
||||||
|
fn make_update_result<'a>() -> Self::UpdateResult<'a> {
|
||||||
|
Box::pin(std::future::ready(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Asynchronous {
|
||||||
|
async fn do_async_update<V: 'static>(any: &mut Box<dyn Any>) {
|
||||||
|
let x = any.downcast_mut::<Box<dyn Node<V, Self>>>().unwrap();
|
||||||
|
x.update().await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user