flow_graph/
node.rs

1use std::collections::HashMap;
2
3use crate::error::Error;
4use crate::port::{PortDirection, PortReference};
5use crate::schematic::{ConnectionIndex, NodeIndex, PortIndex};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[must_use]
9#[allow(clippy::exhaustive_enums)]
10pub enum NodeKind {
11  Input(NodeReference),
12  Output(NodeReference),
13  Inherent(NodeReference),
14  External(NodeReference),
15}
16
17impl NodeKind {
18  pub fn input() -> Self {
19    NodeKind::Input(NodeReference {
20      name: crate::SCHEMATIC_INPUT.to_owned(),
21      component_id: crate::NS_SCHEMATIC.to_owned(),
22    })
23  }
24  pub fn output() -> Self {
25    NodeKind::Output(NodeReference {
26      name: crate::SCHEMATIC_OUTPUT.to_owned(),
27      component_id: crate::NS_SCHEMATIC.to_owned(),
28    })
29  }
30  pub const fn cref(&self) -> &NodeReference {
31    match self {
32      NodeKind::Input(c) => c,
33      NodeKind::Output(c) => c,
34      NodeKind::Inherent(c) => c,
35      NodeKind::External(c) => c,
36    }
37  }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41#[must_use]
42pub struct NodeReference {
43  name: String,
44  component_id: String,
45}
46
47impl NodeReference {
48  pub fn new<T: Into<String>, U: Into<String>>(component_id: T, name: U) -> Self {
49    Self {
50      name: name.into(),
51      component_id: component_id.into(),
52    }
53  }
54
55  #[must_use]
56  pub fn component_id(&self) -> &str {
57    &self.component_id
58  }
59
60  #[must_use]
61  pub fn name(&self) -> &str {
62    &self.name
63  }
64}
65
66impl std::fmt::Display for NodeReference {
67  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68    write!(f, "{}::{}", self.component_id, self.name)
69  }
70}
71
72impl std::fmt::Display for NodeKind {
73  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74    write!(
75      f,
76      "{}",
77      match self {
78        NodeKind::Input(v) => format!("Input({})", v),
79        NodeKind::Output(v) => format!("Output({})", v),
80        NodeKind::Inherent(v) => format!("Inherent({})", v),
81        NodeKind::External(v) => format!("External({})", v),
82      }
83    )
84  }
85}
86
87#[derive(Debug, Clone, Eq)]
88#[must_use]
89pub struct Node<DATA> {
90  pub name: String,
91  kind: NodeKind,
92  index: NodeIndex,
93  data: DATA,
94  inputs: PortList,
95  outputs: PortList,
96}
97
98impl<DATA> PartialEq for Node<DATA> {
99  fn eq(&self, other: &Self) -> bool {
100    self.index == other.index
101  }
102}
103
104impl<DATA> Node<DATA>
105where
106  DATA: Clone,
107{
108  pub(crate) fn new<T: Into<String>>(name: T, index: NodeIndex, kind: NodeKind, data: DATA) -> Self {
109    Self {
110      name: name.into(),
111      kind,
112      index,
113      data,
114      inputs: PortList::new(PortDirection::In),
115      outputs: PortList::new(PortDirection::Out),
116    }
117  }
118
119  pub const fn kind(&self) -> &NodeKind {
120    &self.kind
121  }
122
123  pub const fn cref(&self) -> &NodeReference {
124    self.kind.cref()
125  }
126
127  #[must_use]
128  pub const fn index(&self) -> NodeIndex {
129    self.index
130  }
131
132  #[must_use]
133  pub fn id(&self) -> &str {
134    &self.name
135  }
136
137  #[must_use]
138  pub const fn data(&self) -> &DATA {
139    &self.data
140  }
141
142  pub fn inputs(&self) -> &[NodePort] {
143    self.inputs.inner()
144  }
145
146  #[must_use]
147  pub fn input_refs(&self) -> Vec<PortReference> {
148    self.inputs.inner().iter().map(|c| c.port).collect()
149  }
150
151  #[must_use]
152  pub fn find_input(&self, name: &str) -> Option<&NodePort> {
153    self.inputs.find(name)
154  }
155
156  #[must_use]
157  pub fn get_input(&self, index: PortIndex) -> Option<&NodePort> {
158    self.inputs.get(index)
159  }
160
161  pub fn add_input<T: Into<String>>(&mut self, port: T) -> PortReference {
162    match self.kind {
163      NodeKind::Output(_) => {
164        let port = port.into();
165        self.outputs.add(port.clone(), self.index);
166        self.inputs.add(port, self.index)
167      }
168      NodeKind::Input(_) | NodeKind::Inherent(_) => {
169        // Input/Output nodes have the same ports in & out.
170        panic!("You can not manually add inputs to {} nodes", self.kind);
171      }
172      NodeKind::External(_) => self.inputs.add(port, self.index),
173    }
174  }
175
176  pub(crate) fn connect_input(&mut self, port: PortIndex, connection: ConnectionIndex) -> Result<(), Error> {
177    self.inputs.add_connection(port, connection)
178  }
179
180  pub(crate) fn input_connections(&self, port: PortIndex) -> Option<&Vec<ConnectionIndex>> {
181    self.inputs.port_connections(port)
182  }
183
184  pub(crate) fn all_upstreams(&self) -> Vec<ConnectionIndex> {
185    self.inputs.all_connections()
186  }
187
188  pub fn outputs(&self) -> &[NodePort] {
189    self.outputs.inner()
190  }
191
192  #[must_use]
193  pub fn output_refs(&self) -> Vec<PortReference> {
194    self.outputs.inner().iter().map(|c| c.port).collect()
195  }
196
197  #[must_use]
198  pub fn find_output(&self, name: &str) -> Option<&NodePort> {
199    self.outputs.find(name)
200  }
201
202  #[must_use]
203  pub fn get_output(&self, index: PortIndex) -> Option<&NodePort> {
204    self.outputs.get(index)
205  }
206
207  pub fn add_output<T: Into<String>>(&mut self, port: T) -> PortReference {
208    match self.kind {
209      NodeKind::Input(_) | NodeKind::Inherent(_) => {
210        let port = port.into();
211        self.inputs.add(port.clone(), self.index);
212        self.outputs.add(port, self.index)
213      }
214      NodeKind::Output(_) => {
215        // Input/Output nodes have the same ports in & out.
216        panic!("You can not manually add outputs to {} nodes", self.kind);
217      }
218      NodeKind::External(_) => self.outputs.add(port, self.index),
219    }
220  }
221
222  pub(crate) fn connect_output(&mut self, port: PortIndex, connection: ConnectionIndex) -> Result<(), Error> {
223    self.outputs.add_connection(port, connection)
224  }
225
226  pub(crate) fn output_connections(&self, port: PortIndex) -> Option<&Vec<ConnectionIndex>> {
227    self.outputs.port_connections(port)
228  }
229
230  pub(crate) fn all_downstreams(&self) -> Vec<ConnectionIndex> {
231    self.outputs.all_connections()
232  }
233}
234
235#[derive(Debug, Clone, PartialEq, Eq)]
236struct PortList {
237  direction: PortDirection,
238  map: HashMap<String, PortIndex>,
239  list: Vec<NodePort>,
240}
241
242impl PortList {
243  fn new(direction: PortDirection) -> Self {
244    Self {
245      direction,
246      map: Default::default(),
247      list: Default::default(),
248    }
249  }
250  fn find(&self, name: &str) -> Option<&NodePort> {
251    self.map.get(name).map(|index| &self.list[*index])
252  }
253
254  fn get(&self, index: PortIndex) -> Option<&NodePort> {
255    self.list.get(index)
256  }
257
258  fn inner(&self) -> &[NodePort] {
259    &self.list
260  }
261
262  fn add<T: Into<String>>(&mut self, port_name: T, node_index: NodeIndex) -> PortReference {
263    let name = port_name.into();
264    let existing_index = self.map.get(&name);
265    match existing_index {
266      Some(index) => self.list[*index].port,
267      None => {
268        let index = self.list.len();
269        let port_ref = PortReference::new(node_index, index, self.direction);
270        self.map.insert(name.clone(), index);
271        let port = NodePort::new(name, port_ref);
272        self.list.push(port);
273        port_ref
274      }
275    }
276  }
277
278  fn add_connection(&mut self, port: PortIndex, connection: ConnectionIndex) -> Result<(), Error> {
279    let node_port = self.list.get_mut(port).ok_or(Error::InvalidPortIndex(port))?;
280
281    if node_port.direction() == &PortDirection::In && !node_port.connections.is_empty() {
282      return Err(Error::MultipleInputConnections(node_port.to_string()));
283    }
284    node_port.connections.push(connection);
285    Ok(())
286  }
287
288  fn port_connections(&self, port: PortIndex) -> Option<&Vec<ConnectionIndex>> {
289    self.list.get(port).map(|node| &node.connections)
290  }
291
292  fn all_connections(&self) -> Vec<ConnectionIndex> {
293    self.list.iter().cloned().flat_map(|port| port.connections).collect()
294  }
295}
296
297impl<DATA> std::fmt::Display for Node<DATA> {
298  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299    write!(f, "{}", self.name)
300  }
301}
302
303#[derive(Debug, Clone, PartialEq, Eq)]
304#[must_use]
305pub struct NodePort {
306  name: String,
307  port: PortReference,
308  connections: Vec<ConnectionIndex>,
309}
310
311impl NodePort {
312  pub(crate) fn new<T: Into<String>>(name: T, port: PortReference) -> Self {
313    Self {
314      name: name.into(),
315      port,
316      connections: Default::default(),
317    }
318  }
319
320  #[must_use]
321  pub const fn is_graph_output(&self) -> bool {
322    self.port.node_index == crate::schematic::SCHEMATIC_OUTPUT_INDEX
323  }
324
325  #[must_use]
326  pub const fn is_graph_input(&self) -> bool {
327    self.port.node_index == crate::schematic::SCHEMATIC_INPUT_INDEX
328  }
329
330  #[must_use]
331  pub fn connections(&self) -> &[ConnectionIndex] {
332    &self.connections
333  }
334
335  #[must_use]
336  pub fn name(&self) -> &str {
337    &self.name
338  }
339
340  #[must_use]
341  pub const fn detached(&self) -> PortReference {
342    self.port
343  }
344
345  pub const fn direction(&self) -> &PortDirection {
346    self.port.direction()
347  }
348}
349
350impl From<&NodePort> for PortReference {
351  fn from(port: &NodePort) -> Self {
352    port.port
353  }
354}
355
356impl AsRef<PortReference> for NodePort {
357  fn as_ref(&self) -> &PortReference {
358    &self.port
359  }
360}
361
362impl std::fmt::Display for NodePort {
363  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364    write!(f, "{}", self.name)
365  }
366}