directed/
node.rs

1//! Nodes contain all logic and state, but no information on order of execution.
2use std::{
3    any::{Any, TypeId},
4    collections::HashMap,
5    sync::Arc,
6};
7
8use crate::{
9    stage::{EvalStrategy, ReevaluationRule, Stage}, types::{DataLabel, NodeOutput}, InjectionError, RefType
10};
11
12/// Used for single-output functions
13pub(crate) const UNNAMED_OUTPUT_NAME: DataLabel = DataLabel::new_const("_");
14
15/// Every node wraps a Stage, which is a decorated function that has some
16/// number of inputs and some number of outputs.
17///
18/// TODO: Explain the caching functionality in detail
19#[derive(Debug)]
20pub struct Node<S: Stage> {
21    pub(super) stage: S,
22    // Arbitrary state, by default will be (). Can be used to make nodes even
23    // MORE stateful.
24    pub(super) state: S::State,
25    pub(super) inputs: HashMap<DataLabel, (Arc<dyn Any + Send + Sync>, ReevaluationRule)>,
26    pub(super) outputs: HashMap<DataLabel, Arc<dyn Any + Send + Sync>>,
27    pub(super) input_changed: bool,
28}
29
30impl<S: Stage> Node<S> {
31    pub fn new(stage: S, initial_state: S::State) -> Self {
32        Self {
33            stage,
34            state: initial_state,
35            inputs: HashMap::new(),
36            outputs: HashMap::new(),
37            input_changed: true,
38        }
39    }
40}
41
42/// This is used to type-erase a node. It's public because the macro needs to
43/// use this, but there should be no reason anyone should manually implement
44/// this.
45pub trait AnyNode: Any {
46    /// Upcast to `dyn Any` to get its more-specific downcast capabilities
47    fn into_any(self: Box<Self>) -> Box<dyn Any>;
48    /// Primarily used for internal checks
49    fn as_any(&self) -> &dyn Any;
50    /// USed to get mutable access to state
51    fn as_any_mut(&mut self) -> &mut dyn Any;
52    /// Evaluates the node. Returns a map of prior outputs
53    fn eval(&mut self) -> Result<HashMap<DataLabel, Arc<dyn Any + Send + Sync>>, InjectionError>;
54    fn eval_strategy(&self) -> EvalStrategy;
55    fn reeval_rule(&self) -> ReevaluationRule;
56    /// Set the outputs and return any existing outputs.
57    // TODO: Update this doc when cache-all is implemented.
58    fn replace_output(
59        &mut self,
60        key: &DataLabel,
61        output: Arc<dyn Any + Send + Sync>,
62    ) -> Result<Option<Arc<dyn Any + Send + Sync>>, InjectionError>;
63    /// This a a core part of the plumbing of this crate - take the outputs of
64    /// a parent node and use them to set the inputs of a child node.
65    fn flow_data(
66        &mut self,
67        parent: &mut Box<dyn AnyNode>,
68        output: DataLabel,
69        input: DataLabel,
70    ) -> Result<(), InjectionError>;
71    /// Used to support `[Self::flow_data]`
72    fn inputs_mut(
73        &mut self,
74    ) -> &mut HashMap<DataLabel, (Arc<dyn Any + Send + Sync>, ReevaluationRule)>;
75    /// Used to support `[Self::flow_data]`
76    fn outputs_mut(&mut self) -> &mut HashMap<DataLabel, Arc<dyn Any + Send + Sync>>;
77    /// Look of the reftype of a particular input
78    fn input_reftype(&self, name: &DataLabel) -> Option<RefType>;
79    /// Used to indicate that an input has been modified from a previous run.
80    fn set_input_changed(&mut self, val: bool);
81    /// See `[Self::set_input_changed]`
82    fn input_changed(&self) -> bool;
83    fn input_names(&self) -> std::iter::Cloned<std::collections::hash_map::Keys<'_, DataLabel, (TypeId, RefType)>>;
84    fn output_names(&self) -> std::iter::Cloned<std::collections::hash_map::Keys<'_, DataLabel, TypeId>>;
85    fn stage_name(&self) -> &str;
86}
87
88impl<S: Stage + 'static> AnyNode for Node<S> {
89    fn into_any(self: Box<Self>) -> Box<dyn Any> {
90        Box::new(*self)
91    }
92
93    fn as_any(&self) -> &dyn Any {
94        self as &dyn Any
95    }
96
97    fn as_any_mut(&mut self) -> &mut dyn Any {
98        self as &mut dyn Any
99    }
100
101    fn eval_strategy(&self) -> EvalStrategy {
102        self.stage.eval_strategy()
103    }
104
105    fn reeval_rule(&self) -> ReevaluationRule {
106        self.stage.reeval_rule()
107    }
108
109    fn replace_output(
110        &mut self,
111        key: &DataLabel,
112        output: Arc<dyn Any + Send + Sync>,
113    ) -> Result<Option<Arc<dyn Any + Send + Sync>>, InjectionError> {
114        let output_type = self
115            .stage
116            .outputs()
117            .get(key)
118            .ok_or_else(|| InjectionError::OutputNotFound(key.clone()))?;
119        match (&*output).type_id() {
120            id if id != *output_type => {
121                return Err(InjectionError::OutputTypeMismatch(key.clone()));
122            }
123            _ => Ok(self.outputs.insert(key.clone(), output)),
124        }
125    }
126
127    fn eval(&mut self) -> Result<HashMap<DataLabel, Arc<dyn Any + Send + Sync>>, InjectionError> {
128        let mut old_outputs = HashMap::new();
129        // TODO: This stage clone is silly spaghetti
130        let outputs = self.stage.evaluate(&mut self.state, &mut self.inputs)?;
131
132        match outputs {
133            NodeOutput::Standard(val) => {
134                if let Some(old_output) = self.replace_output(&UNNAMED_OUTPUT_NAME, val)? {
135                    old_outputs.insert(UNNAMED_OUTPUT_NAME, old_output);
136                }
137            }
138            NodeOutput::Named(hash_map) => {
139                for (key, val) in hash_map.into_iter() {
140                    if let Some(old_output) = self.replace_output(&key, val)? {
141                        old_outputs.insert(key, old_output);
142                    }
143                }
144            }
145        }
146        Ok(old_outputs)
147    }
148
149    fn flow_data(
150        &mut self,
151        parent: &mut Box<dyn AnyNode>,
152        output: DataLabel,
153        input: DataLabel,
154    ) -> Result<(), InjectionError> {
155        let stage_clone = self.stage.clone();
156        stage_clone.inject_input(self, parent, output, input)
157    }
158
159    fn inputs_mut(
160        &mut self,
161    ) -> &mut HashMap<DataLabel, (Arc<dyn Any + Send + Sync>, ReevaluationRule)> {
162        &mut self.inputs
163    }
164
165    fn outputs_mut(&mut self) -> &mut HashMap<DataLabel, Arc<dyn Any + Send + Sync>> {
166        &mut self.outputs
167    }
168
169    fn set_input_changed(&mut self, val: bool) {
170        self.input_changed = val;
171    }
172
173    fn input_changed(&self) -> bool {
174        self.input_changed
175    }
176
177    fn input_reftype(&self, name: &DataLabel) -> Option<RefType> {
178        self.stage.inputs().get(name).map(|input| input.1)
179    }
180    
181    fn input_names(&self) -> std::iter::Cloned<std::collections::hash_map::Keys<'_, DataLabel, (TypeId, RefType)>> {
182        self.stage.inputs().keys().cloned()
183    }
184    
185    fn output_names(&self) -> std::iter::Cloned<std::collections::hash_map::Keys<'_, DataLabel, TypeId>> {
186        self.stage.outputs().keys().cloned()
187    }
188    
189    fn stage_name(&self) -> &str {
190        self.stage.name()
191    }
192}