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 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 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}