1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::fmt;
6
7pub type PortId = String;
9
10pub type NodeId = String;
12
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15pub enum PortData {
16 None,
18 Bool(bool),
20 Int(i64),
22 Float(f64),
24 String(String),
26 Bytes(Vec<u8>),
28 Json(serde_json::Value),
30 List(Vec<PortData>),
32 Map(HashMap<String, PortData>),
34}
35
36impl fmt::Display for PortData {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match self {
39 PortData::None => write!(f, "None"),
40 PortData::Bool(b) => write!(f, "{}", b),
41 PortData::Int(i) => write!(f, "{}", i),
42 PortData::Float(fl) => write!(f, "{}", fl),
43 PortData::String(s) => write!(f, "\"{}\"", s),
44 PortData::Bytes(b) => write!(f, "Bytes({})", b.len()),
45 PortData::Json(j) => write!(f, "{}", j),
46 PortData::List(l) => write!(f, "List({})", l.len()),
47 PortData::Map(m) => write!(f, "Map({})", m.len()),
48 }
49 }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct Port {
55 pub broadcast_name: PortId,
57 pub impl_name: String,
59 pub display_name: String,
61 pub description: Option<String>,
63 pub required: bool,
65}
66
67impl Port {
68 pub fn new(broadcast_name: impl Into<String>, impl_name: impl Into<String>) -> Self {
70 let broadcast = broadcast_name.into();
71 let impl_name = impl_name.into();
72 let display_name = broadcast.clone();
73 Self {
74 broadcast_name: broadcast,
75 impl_name,
76 display_name,
77 description: None,
78 required: true,
79 }
80 }
81
82 pub fn simple(name: impl Into<String>) -> Self {
84 let name = name.into();
85 Self::new(name.clone(), name)
86 }
87
88 pub fn optional(broadcast_name: impl Into<String>, impl_name: impl Into<String>) -> Self {
90 let mut port = Self::new(broadcast_name, impl_name);
91 port.required = false;
92 port
93 }
94
95 pub fn with_display_name(mut self, display_name: impl Into<String>) -> Self {
97 self.display_name = display_name.into();
98 self
99 }
100
101 pub fn with_description(mut self, description: impl Into<String>) -> Self {
103 self.description = Some(description.into());
104 self
105 }
106}
107
108#[derive(Debug, Clone, Default, Serialize, Deserialize)]
110pub struct GraphData {
111 ports: HashMap<PortId, PortData>,
113}
114
115impl GraphData {
116 pub fn new() -> Self {
118 Self {
119 ports: HashMap::new(),
120 }
121 }
122
123 pub fn set(&mut self, port_id: impl Into<PortId>, data: PortData) {
125 self.ports.insert(port_id.into(), data);
126 }
127
128 pub fn get(&self, port_id: &str) -> Option<&PortData> {
130 self.ports.get(port_id)
131 }
132
133 pub fn remove(&mut self, port_id: &str) -> Option<PortData> {
135 self.ports.remove(port_id)
136 }
137
138 pub fn has(&self, port_id: &str) -> bool {
140 self.ports.contains_key(port_id)
141 }
142
143 pub fn port_ids(&self) -> impl Iterator<Item = &PortId> {
145 self.ports.keys()
146 }
147
148 pub fn clear(&mut self) {
150 self.ports.clear();
151 }
152
153 pub fn len(&self) -> usize {
155 self.ports.len()
156 }
157
158 pub fn is_empty(&self) -> bool {
160 self.ports.is_empty()
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_port_creation() {
170 let port = Port::new("input1", "input1");
171 assert_eq!(port.broadcast_name, "input1");
172 assert_eq!(port.display_name, "input1");
173 assert!(port.required);
174 assert!(port.description.is_none());
175 }
176
177 #[test]
178 fn test_optional_port() {
179 let port = Port::optional("opt1", "Optional 1").with_description("An optional port");
180 assert!(!port.required);
181 assert_eq!(port.description.unwrap(), "An optional port");
182 }
183
184 #[test]
185 fn test_graph_data_operations() {
186 let mut data = GraphData::new();
187
188 data.set("port1", PortData::Int(42));
190 assert!(data.has("port1"));
191 assert_eq!(data.len(), 1);
192
193 if let Some(PortData::Int(val)) = data.get("port1") {
194 assert_eq!(*val, 42);
195 } else {
196 panic!("Expected Int(42)");
197 }
198
199 let removed = data.remove("port1");
201 assert!(removed.is_some());
202 assert!(!data.has("port1"));
203 assert!(data.is_empty());
204 }
205
206 #[test]
207 fn test_port_data_types() {
208 let mut data = GraphData::new();
209
210 data.set("bool", PortData::Bool(true));
211 data.set("int", PortData::Int(123));
212 data.set("float", PortData::Float(3.14));
213 data.set("string", PortData::String("hello".to_string()));
214
215 assert_eq!(data.len(), 4);
216 assert!(data.has("bool"));
217 assert!(data.has("int"));
218 assert!(data.has("float"));
219 assert!(data.has("string"));
220 }
221}