1use serde_json::Value;
2
3use jellyflow_core::core::{
4 CanvasPoint, Node, NodeId, NodeKindKey, Port, PortCapacity, PortDirection, PortId, PortKey,
5 PortKind,
6};
7use jellyflow_core::types::TypeDesc;
8
9#[derive(Debug, Clone)]
13pub struct InsertNodeSpec {
14 pub node_id: NodeId,
15 pub node: Node,
16 pub ports: Vec<(PortId, Port)>,
17 pub input: PortId,
18 pub output: PortId,
19}
20
21#[derive(Debug, Clone)]
23pub struct PortTemplate {
24 pub key: PortKey,
25 pub dir: PortDirection,
26 pub kind: PortKind,
27 pub capacity: PortCapacity,
28 pub ty: Option<TypeDesc>,
29 pub data: Value,
30}
31
32#[derive(Debug, Clone)]
36pub struct InsertNodeTemplate {
37 pub kind: NodeKindKey,
38 pub kind_version: u32,
39 pub collapsed: bool,
40 pub data: Value,
41 pub ports: Vec<PortTemplate>,
42
43 pub input: PortKey,
45 pub output: PortKey,
47}
48
49impl InsertNodeTemplate {
50 pub fn instantiate(&self, at: CanvasPoint) -> Result<InsertNodeSpec, String> {
52 let node_id = NodeId::new();
53 let ports = InstantiatedTemplatePorts::from_template(self, node_id)?;
54
55 Ok(InsertNodeSpec {
56 node_id,
57 node: self.instantiate_node(at),
58 ports: ports.ports,
59 input: ports.input,
60 output: ports.output,
61 })
62 }
63
64 fn instantiate_node(&self, at: CanvasPoint) -> Node {
65 Node {
66 kind: self.kind.clone(),
67 kind_version: self.kind_version,
68 pos: at,
69 origin: None,
70 selectable: None,
71 focusable: None,
72 draggable: None,
73 connectable: None,
74 deletable: None,
75 parent: None,
76 extent: None,
77 expand_parent: None,
78 size: None,
79 hidden: false,
80 collapsed: self.collapsed,
81 ports: Vec::new(),
82 data: self.data.clone(),
83 }
84 }
85}
86
87struct InstantiatedTemplatePorts {
88 ports: Vec<(PortId, Port)>,
89 input: PortId,
90 output: PortId,
91}
92
93impl InstantiatedTemplatePorts {
94 fn from_template(template: &InsertNodeTemplate, node_id: NodeId) -> Result<Self, String> {
95 let mut ports: Vec<(PortId, Port)> = Vec::new();
96 let mut input: Option<PortId> = None;
97 let mut output: Option<PortId> = None;
98
99 for port_template in &template.ports {
100 let port_id = PortId::new();
101 if port_template.key == template.input {
102 input = Some(port_id);
103 }
104 if port_template.key == template.output {
105 output = Some(port_id);
106 }
107
108 ports.push((port_id, instantiate_port(node_id, port_template)));
109 }
110
111 let input = required_template_port(input, "input", &template.input)?;
112 let output = required_template_port(output, "output", &template.output)?;
113 if input == output {
114 return Err("template input/output ports must be distinct".to_string());
115 }
116
117 Ok(Self {
118 ports,
119 input,
120 output,
121 })
122 }
123}
124
125fn instantiate_port(node_id: NodeId, template: &PortTemplate) -> Port {
126 Port {
127 node: node_id,
128 key: template.key.clone(),
129 dir: template.dir,
130 kind: template.kind,
131 capacity: template.capacity,
132 connectable: None,
133 connectable_start: None,
134 connectable_end: None,
135 ty: template.ty.clone(),
136 data: template.data.clone(),
137 }
138}
139
140fn required_template_port(
141 port: Option<PortId>,
142 role: &str,
143 key: &PortKey,
144) -> Result<PortId, String> {
145 port.ok_or_else(|| format!("template is missing {role} port: {}", key.0))
146}