Skip to main content

nadi_core/
node.rs

1use crate::{
2    attrs::{AttrMap, Attribute, HasAttributes},
3    timeseries::{HasSeries, HasTimeSeries, SeriesMap, TsMap},
4};
5use abi_stable::{
6    external_types::RMutex,
7    std_types::{
8        RArc,
9        ROption::{self, RSome},
10        RString, RVec,
11    },
12    StableAbi,
13};
14
15/// Thread safe Mutex of [`NodeInner`]
16pub type Node = RArc<RMutex<NodeInner>>;
17
18/// Create a new [`Node`]
19pub fn new_node(index: usize, name: &str) -> Node {
20    RArc::new(RMutex::new(NodeInner::new(index, name)))
21}
22
23/// Represents points with attributes and timeseries. These can be any
24/// point as long as they'll be on the network and connection to each
25/// other.
26///
27/// The attributes format is [`Attribute`], which has
28/// [`Attribute::Array`] and [`Attribute::Table`] which means users
29/// are free to make their own attributes with custom combinations and
30/// plugins + functions that can work with those attributes.
31///
32/// Since attributes are loaded using TOML file, simple attributes can
33/// be stored and parsed from strings, and complex ones can be saved in
34/// different files and their path can be stored as node attributes.
35///
36/// Here is an example node attribute file. Here we have string,
37/// float, int and boolean values.
38/// ```toml
39///     stn="smithland"
40///     nat_7q10=12335.94850131619
41///     orsanco_7q10=16900
42///     lock=true
43///     ...
44/// ```
45///    
46#[repr(C)]
47#[derive(StableAbi, Default, Clone)]
48pub struct NodeInner {
49    /// index of the current node in the [`crate::Network`]
50    pub(crate) index: usize,
51    /// name of the node
52    pub(crate) name: RString,
53    /// level represents the rank of the tributary, 0 for main branch
54    /// and 1 for tributaries connected to main branch and so on
55    pub(crate) level: u64,
56    /// Number of inputs connected to the current node
57    pub(crate) order: u64,
58    /// Node attributes in a  Hashmap of [`RString`] to [`Attribute`]
59    pub(crate) attributes: AttrMap,
60    /// Hashmap of [`RString`] to [`Series`]
61    pub(crate) series: SeriesMap,
62    /// Hashmap of [`RString`] to [`TimeSeries`]
63    pub(crate) timeseries: TsMap,
64    /// List of immediate inputs
65    pub(crate) inputs: RVec<Node>,
66    /// Output of the node if present
67    pub(crate) output: ROption<Node>,
68}
69
70impl HasAttributes for NodeInner {
71    fn node_name(&self) -> Option<&str> {
72        Some(self.name())
73    }
74    fn attr_map(&self) -> &AttrMap {
75        &self.attributes
76    }
77
78    fn attr_map_mut(&mut self) -> &mut AttrMap {
79        &mut self.attributes
80    }
81}
82
83impl HasSeries for NodeInner {
84    fn series_map(&self) -> &SeriesMap {
85        &self.series
86    }
87
88    fn series_map_mut(&mut self) -> &mut SeriesMap {
89        &mut self.series
90    }
91}
92
93impl HasTimeSeries for NodeInner {
94    fn ts_map(&self) -> &TsMap {
95        &self.timeseries
96    }
97
98    fn ts_map_mut(&mut self) -> &mut TsMap {
99        &mut self.timeseries
100    }
101}
102
103impl NodeInner {
104    /// new node data
105    pub fn new(index: usize, name: &str) -> Self {
106        let mut node = Self {
107            index,
108            name: name.into(),
109            ..Default::default()
110        };
111        node.set_attr("NAME", Attribute::String(name.into()));
112        node.set_attr("INDEX", Attribute::Integer(index as i64));
113        node
114    }
115
116    /// name of the node
117    pub fn name(&self) -> &str {
118        &self.name
119    }
120
121    /// index of the node
122    pub fn index(&self) -> usize {
123        self.index
124    }
125
126    /// set index of the node
127    pub fn set_index(&mut self, index: usize) {
128        self.index = index;
129        self.set_attr("INDEX", Attribute::Integer(index as i64));
130    }
131
132    /// level of the node
133    pub fn level(&self) -> u64 {
134        self.level
135    }
136
137    /// order of the node
138    pub fn order(&self) -> u64 {
139        self.order
140    }
141
142    /// set level of the node
143    pub fn set_level(&mut self, level: u64) {
144        self.level = level;
145        self.set_attr("LEVEL", Attribute::Integer(level as i64));
146    }
147
148    /// set order of the node
149    pub fn set_order(&mut self, order: u64) {
150        self.order = order;
151        self.set_attr("ORDER", Attribute::Integer(order as i64));
152    }
153
154    /// input nodes of the node
155    pub fn inputs(&self) -> &[Node] {
156        &self.inputs
157    }
158
159    /// input nodes as a mutable reference
160    pub(crate) fn inputs_mut(&mut self) -> &mut RVec<Node> {
161        &mut self.inputs
162    }
163
164    /// add a input node to the node
165    pub fn add_input(&mut self, input: Node) {
166        self.inputs.push(input);
167    }
168
169    /// remove the input nodes of the node
170    pub fn unset_inputs(&mut self) {
171        self.inputs = RVec::new();
172    }
173
174    /// order the input nodes in the network
175    pub fn order_inputs(&mut self) {
176        self.inputs
177            .sort_by(|a, b| b.lock().order.partial_cmp(&a.lock().order).unwrap());
178    }
179
180    /// output of the node
181    pub fn output(&self) -> ROption<&Node> {
182        self.output.as_ref()
183    }
184
185    /// set the output of the node
186    pub fn set_output(&mut self, output: Node) -> ROption<Node> {
187        self.output.replace(output)
188    }
189
190    /// unset the output of the node
191    pub fn unset_output(&mut self) -> ROption<Node> {
192        self.output.take()
193    }
194
195    /// Move the node to the side (move the inputs to its output)
196    pub fn move_aside(&mut self) {
197        if let RSome(o) = self.output() {
198            self.inputs().iter().for_each(|i| {
199                o.lock().add_input(i.clone());
200                i.lock().set_output(o.clone());
201            });
202        } else {
203            self.inputs().iter().for_each(|i| {
204                i.lock().unset_output();
205            });
206        }
207        self.unset_inputs();
208    }
209
210    /// Move the network down one step, (swap places with its output)
211    pub fn move_down(&mut self) {
212        if let RSome(out) = self.unset_output() {
213            let i = out
214                .lock()
215                .inputs()
216                .iter()
217                // HACK current node will fail to lock
218                .position(|c| c.try_lock().is_none())
219                .unwrap();
220            let o = out.lock().inputs.remove(i);
221            self.output = out.lock().output.clone();
222            out.lock().set_output(o);
223            self.add_input(out.clone());
224        }
225    }
226}