1use std::{collections::HashMap, fmt::Display, str::FromStr};
2
3use gpui::{Bounds, Pixels, Point, Size, px};
4use serde::{Deserialize, Serialize};
5use serde_json::json;
6use uuid::Uuid;
7
8use crate::Graph;
9
10pub const DEFAULT_NODE_WIDTH: Pixels = px(120.0);
11pub const DEFAULT_NODE_HEIGHT: Pixels = px(60.0);
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub struct NodeId(Uuid);
15
16impl Display for NodeId {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 write!(f, "{}", self.0)
19 }
20}
21
22impl NodeId {
23 pub fn new() -> Self {
24 Self(Uuid::new_v4())
25 }
26 pub fn from_string(s: impl Into<String>) -> Option<Self> {
27 let string = s.into();
28 Uuid::from_str(&string).ok().map(Self)
29 }
30 pub fn from_uuid(uuid: Uuid) -> Self {
31 Self(uuid)
32 }
33
34 pub fn as_uuid(&self) -> &Uuid {
35 &self.0
36 }
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct Node {
41 pub id: NodeId,
42 pub node_type: String,
43 pub execute_type: String,
44 pub x: Pixels,
45 pub y: Pixels,
46 pub size: Size<Pixels>,
47
48 pub inputs: Vec<PortId>,
49 pub outputs: Vec<PortId>,
50 pub data: serde_json::Value,
51}
52
53impl Node {
54 pub fn new(x: f32, y: f32) -> Self {
55 Self {
56 id: NodeId::new(),
57 node_type: String::new(),
58 execute_type: String::new(),
59 x: x.into(),
60 y: y.into(),
61 size: Size {
62 width: DEFAULT_NODE_WIDTH,
63 height: DEFAULT_NODE_HEIGHT,
64 },
65 inputs: vec![],
66 outputs: vec![],
67 data: json!({}),
68 }
69 }
70
71 pub fn node_type(mut self, ty: impl Into<String>) -> Self {
72 self.node_type = ty.into();
73 self
74 }
75
76 pub fn point(&self) -> Point<Pixels> {
77 Point::new(self.x, self.y)
78 }
79
80 pub fn bounds(&self) -> Bounds<Pixels> {
81 Bounds::new(self.point(), self.size)
82 }
83
84 pub fn set_size(mut self, size: Size<Pixels>) -> Self {
85 self.size = size;
86 self
87 }
88
89 pub fn output(mut self, id: PortId) -> Self {
90 self.outputs.push(id);
91 self
92 }
93
94 pub fn input(mut self, id: PortId) -> Self {
95 self.inputs.push(id);
96 self
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
101pub struct PortId(Uuid);
102
103impl Display for PortId {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 write!(f, "{}", self.0)
106 }
107}
108
109impl PortId {
110 pub fn new() -> Self {
111 Self(Uuid::new_v4())
112 }
113 pub fn from_string(s: impl Into<String>) -> Option<Self> {
114 let string = s.into();
115 Uuid::from_str(&string).ok().map(Self)
116 }
117 pub fn from_uuid(uuid: Uuid) -> Self {
118 Self(uuid)
119 }
120
121 pub fn as_uuid(&self) -> &Uuid {
122 &self.0
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
127pub enum PortKind {
128 Input,
129 Output,
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
133pub enum PortPosition {
134 Left,
135 Right,
136 Top,
137 Bottom,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct Port {
142 pub id: PortId,
143 pub kind: PortKind,
144 pub index: usize,
145 pub node_id: NodeId,
146 pub position: PortPosition,
147 pub size: Size<Pixels>,
148}
149
150impl ToString for PortKind {
151 fn to_string(&self) -> String {
152 match self {
153 PortKind::Input => "input".into(),
154 PortKind::Output => "output".into(),
155 }
156 }
157}
158impl ToString for PortPosition {
159 fn to_string(&self) -> String {
160 match self {
161 PortPosition::Left => "left".into(),
162 PortPosition::Right => "right".into(),
163 PortPosition::Top => "top".into(),
164 PortPosition::Bottom => "bottom".into(),
165 }
166 }
167}
168
169impl PortPosition {
170 pub fn from_str(str: &str) -> Option<Self> {
171 match str {
172 "right" => Some(Self::Right),
173 "top" => Some(Self::Top),
174 "bottom" => Some(Self::Bottom),
175 "left" => Some(Self::Left),
176 _ => None,
177 }
178 }
179}
180
181pub struct NodeBuilder {
182 node_type: String,
183 execute_type: String,
184 x: Pixels,
185 y: Pixels,
186 size: Size<Pixels>,
187 inputs: Vec<PortSpec>,
188 outputs: Vec<PortSpec>,
189 data: serde_json::Value,
190}
191
192#[derive(Clone)]
193struct PortSpec {
194 position: PortPosition,
195 size: Size<Pixels>,
196}
197
198const DEFAULT_PORT_SIZE: Size<Pixels> = Size {
199 width: px(12.0),
200 height: px(12.0),
201};
202
203impl NodeBuilder {
204 pub fn new(node_type: impl Into<String>) -> Self {
205 Self {
206 node_type: node_type.into(),
207 execute_type: String::new(),
208 x: px(0.0),
209 y: px(0.0),
210 size: Size {
211 width: DEFAULT_NODE_WIDTH,
212 height: DEFAULT_NODE_HEIGHT,
213 },
214 inputs: vec![],
215 outputs: vec![],
216 data: serde_json::Value::Null,
217 }
218 }
219
220 pub fn execute_type(mut self, execute_type: impl Into<String>) -> Self {
221 self.execute_type = execute_type.into();
222 self
223 }
224
225 pub fn position(mut self, x: f32, y: f32) -> Self {
226 self.x = x.into();
227 self.y = y.into();
228 self
229 }
230
231 pub fn size(mut self, w: f32, h: f32) -> Self {
232 self.size = Size {
233 width: w.into(),
234 height: h.into(),
235 };
236 self
237 }
238
239 pub fn input(mut self) -> Self {
240 self.inputs.push(PortSpec {
241 position: PortPosition::Left,
242 size: DEFAULT_PORT_SIZE,
243 });
244 self
245 }
246
247 pub fn output(mut self) -> Self {
248 self.outputs.push(PortSpec {
249 position: PortPosition::Right,
250 size: DEFAULT_PORT_SIZE,
251 });
252 self
253 }
254
255 pub fn input_at(mut self, pos: PortPosition) -> Self {
256 self.inputs.push(PortSpec {
257 position: pos,
258 size: DEFAULT_PORT_SIZE,
259 });
260 self
261 }
262
263 pub fn output_at(mut self, pos: PortPosition) -> Self {
264 self.outputs.push(PortSpec {
265 position: pos,
266 size: DEFAULT_PORT_SIZE,
267 });
268 self
269 }
270
271 pub fn input_with(mut self, pos: PortPosition, size: Size<Pixels>) -> Self {
272 self.inputs.push(PortSpec {
273 position: pos,
274 size,
275 });
276 self
277 }
278
279 pub fn output_with(mut self, pos: PortPosition, size: Size<Pixels>) -> Self {
280 self.outputs.push(PortSpec {
281 position: pos,
282 size,
283 });
284 self
285 }
286
287 pub fn data(mut self, data: serde_json::Value) -> Self {
288 self.data = data;
289 self
290 }
291
292 pub fn only_build(self, graph: &Graph) -> (Node, Vec<Port>) {
293 let node_id = graph.next_node_id();
294
295 let mut inputs = Vec::new();
296 let mut outputs = Vec::new();
297
298 let mut input_counters: HashMap<PortPosition, usize> = HashMap::new();
299
300 let mut ports = vec![];
302 for spec in self.inputs {
303 let port_id = graph.next_port_id();
304
305 let index = input_counters.entry(spec.position).or_insert(0);
306 let current_index = *index;
307 *index += 1;
308
309 ports.push(Port {
310 id: port_id,
311 kind: PortKind::Input,
312 index: current_index,
313 node_id,
314 position: spec.position,
315 size: spec.size,
316 });
317
318 inputs.push(port_id);
319 }
320
321 let mut output_counters: HashMap<PortPosition, usize> = HashMap::new();
322
323 for spec in self.outputs {
325 let port_id = graph.next_port_id();
326
327 let index = output_counters.entry(spec.position).or_insert(0);
328 let current_index = *index;
329 *index += 1;
330
331 ports.push(Port {
332 id: port_id,
333 kind: PortKind::Output,
334 index: current_index,
335 node_id,
336 position: spec.position,
337 size: spec.size,
338 });
339
340 outputs.push(port_id);
341 }
342
343 (
344 Node {
345 id: node_id,
346 node_type: self.node_type,
347 execute_type: self.execute_type,
348 x: self.x,
349 y: self.y,
350 size: self.size,
351 inputs,
352 outputs,
353 data: self.data,
354 },
355 ports,
356 )
357 }
358
359 pub fn build(self, graph: &mut Graph) -> NodeId {
360 let (node, ports) = self.only_build(graph);
361 graph.nodes.insert(node.id, node.clone());
362 graph.node_order_mut().push(node.id);
363 for port in ports {
364 graph.ports.insert(port.id, port);
365 }
366 node.id
367 }
368}