1use std::marker::PhantomData;
9
10use indexmap::IndexMap;
11use serde::{Deserialize, Serialize};
12
13use super::{
14 condition::{Condition, ConditionMap},
15 merge::MergerMap,
16 node::BspNode,
17 value::BspValue,
18};
19
20pub type NodeId = usize;
27pub type PortIndex = usize;
29pub type EdgeId = usize;
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
34pub struct OutputPin {
35 pub node_id: NodeId,
36 pub port: PortIndex,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
41pub struct InputPin {
42 pub node_id: NodeId,
43 pub port: PortIndex,
44}
45
46pub const ERROR_PORT: PortIndex = usize::MAX;
50
51#[derive(Clone)]
57pub struct Edge<S> {
58 pub source: NodeId,
60 pub target: NodeId,
62 pub condition: Condition<S>,
64 pub max_iterations: Option<u64>,
67 pub source_port: Option<PortIndex>,
69 pub target_port: Option<PortIndex>,
71}
72
73impl<S> Edge<S> {
74 fn control(source: NodeId, target: NodeId) -> Self {
75 Self {
76 source,
77 target,
78 condition: Condition::Always,
79 max_iterations: None,
80 source_port: None,
81 target_port: None,
82 }
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
88pub struct NodeHandle {
89 pub id: NodeId,
90}
91
92impl NodeHandle {
93 #[must_use]
94 pub const fn new(id: NodeId) -> Self {
95 Self { id }
96 }
97
98 #[must_use]
99 pub const fn output(self, port: PortIndex) -> OutputPin {
100 OutputPin {
101 node_id: self.id,
102 port,
103 }
104 }
105
106 #[must_use]
107 pub const fn input(self, port: PortIndex) -> InputPin {
108 InputPin {
109 node_id: self.id,
110 port,
111 }
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118pub struct TypedNodeHandle<N> {
119 pub id: NodeId,
120 _marker: PhantomData<fn() -> N>,
121}
122
123impl<N> TypedNodeHandle<N> {
124 #[must_use]
125 pub const fn new(id: NodeId) -> Self {
126 Self {
127 id,
128 _marker: PhantomData,
129 }
130 }
131
132 #[must_use]
134 pub const fn get_output_pin(&self, port: PortIndex) -> OutputPin {
135 OutputPin {
136 node_id: self.id,
137 port,
138 }
139 }
140
141 #[must_use]
143 pub const fn get_input_pin(&self, port: PortIndex) -> InputPin {
144 InputPin {
145 node_id: self.id,
146 port,
147 }
148 }
149
150 #[must_use]
151 pub const fn as_untyped(&self) -> NodeHandle {
152 NodeHandle::new(self.id)
153 }
154}
155
156impl<N> From<TypedNodeHandle<N>> for NodeHandle {
157 fn from(typed: TypedNodeHandle<N>) -> Self {
158 Self::new(typed.id)
159 }
160}
161
162impl<N> serde::Serialize for TypedNodeHandle<N> {
163 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
164 where
165 S: serde::Serializer,
166 {
167 self.id.serialize(serializer)
168 }
169}
170
171impl<'de, N> serde::Deserialize<'de> for TypedNodeHandle<N> {
172 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
173 where
174 D: serde::Deserializer<'de>,
175 {
176 let id = NodeId::deserialize(deserializer)?;
177 Ok(Self::new(id))
178 }
179}
180
181pub struct EdgeBuilder<'a, S> {
184 graph: &'a mut BspGraph<S>,
185 id: EdgeId,
186}
187
188impl<S> EdgeBuilder<'_, S> {
189 pub fn when(self, condition: Condition<S>) -> Self {
191 self.graph.edges[self.id].condition = condition;
192 self
193 }
194
195 pub fn with_max_iterations(self, max: u64) -> Self {
197 self.graph.edges[self.id].max_iterations = Some(max);
198 self
199 }
200
201 pub fn with_ports(self, source_port: PortIndex, target_port: PortIndex) -> Self {
203 let edge = &mut self.graph.edges[self.id];
204 edge.source_port = Some(source_port);
205 edge.target_port = Some(target_port);
206 self.graph.reindex_edge_ports(self.id);
207 self
208 }
209
210 #[must_use]
212 pub const fn id(&self) -> EdgeId {
213 self.id
214 }
215}
216
217pub struct BspGraph<S = ()> {
222 pub(crate) nodes: IndexMap<NodeId, Box<dyn BspNode<S>>>,
223 pub(crate) edges: Vec<Edge<S>>,
224 pub(crate) static_inputs: IndexMap<InputPin, BspValue>,
225 pub(crate) conditions: ConditionMap<S>,
227 pub(crate) mergers: MergerMap<S>,
229 pub(crate) labels: IndexMap<NodeId, String>,
231 pub(crate) entry: Vec<NodeId>,
233 pub(crate) node_defs: IndexMap<NodeId, crate::def::NodeDef>,
235 pub(crate) incoming: IndexMap<NodeId, Vec<EdgeId>>,
237 pub(crate) incoming_by_pin: IndexMap<InputPin, Vec<EdgeId>>,
239 pub(crate) outgoing: IndexMap<NodeId, Vec<EdgeId>>,
241 next_node_id: NodeId,
242}
243
244impl<S> Default for BspGraph<S> {
245 fn default() -> Self {
246 Self::new()
247 }
248}
249
250impl<S> BspGraph<S> {
251 #[must_use]
253 pub fn new() -> Self {
254 Self {
255 nodes: IndexMap::new(),
256 edges: Vec::new(),
257 static_inputs: IndexMap::new(),
258 conditions: ConditionMap::default(),
259 mergers: MergerMap::default(),
260 labels: IndexMap::new(),
261 entry: Vec::new(),
262 node_defs: IndexMap::new(),
263 incoming: IndexMap::new(),
264 incoming_by_pin: IndexMap::new(),
265 outgoing: IndexMap::new(),
266 next_node_id: 1,
267 }
268 }
269
270 pub fn add_node<N: BspNode<S> + 'static>(&mut self, node: N) -> TypedNodeHandle<N> {
272 let id = self.next_node_id;
273 self.next_node_id += 1;
274 self.nodes.insert(id, Box::new(node));
275 self.labels.insert(id, id.to_string());
276 TypedNodeHandle::new(id)
277 }
278
279 pub fn add_node_with_id(&mut self, id: impl Into<NodeId>, node: Box<dyn BspNode<S>>) {
281 let id = id.into();
282 self.nodes.insert(id, node);
283 self.labels.entry(id).or_insert_with(|| id.to_string());
284 if id >= self.next_node_id {
285 self.next_node_id = id + 1;
286 }
287 }
288
289 pub fn add_link(&mut self, source: OutputPin, target: InputPin) {
294 let id = self.edges.len();
295 let mut edge = Edge::control(source.node_id, target.node_id);
296 edge.source_port = Some(source.port);
297 edge.target_port = Some(target.port);
298 self.push_edge(edge);
299 debug_assert_eq!(id, self.edges.len() - 1);
300 }
301
302 pub fn add_link_indices(
304 &mut self,
305 source_node: NodeId,
306 source_port: PortIndex,
307 target_node: NodeId,
308 target_port: PortIndex,
309 ) {
310 self.add_link(
311 OutputPin {
312 node_id: source_node,
313 port: source_port,
314 },
315 InputPin {
316 node_id: target_node,
317 port: target_port,
318 },
319 );
320 }
321
322 pub fn add_edge(
325 &mut self,
326 source: impl Into<NodeId>,
327 target: impl Into<NodeId>,
328 ) -> EdgeBuilder<'_, S> {
329 let id = self.edges.len();
330 self.push_edge(Edge::control(source.into(), target.into()));
331 EdgeBuilder { graph: self, id }
332 }
333
334 pub fn add_edge_with(
336 &mut self,
337 source: impl Into<NodeId>,
338 target: impl Into<NodeId>,
339 condition: Condition<S>,
340 ) -> EdgeId {
341 let id = self.edges.len();
342 let mut edge = Edge::control(source.into(), target.into());
343 edge.condition = condition;
344 self.push_edge(edge);
345 id
346 }
347
348 pub fn set_static_input<T: std::any::Any + Send + Sync>(&mut self, target: InputPin, value: T) {
350 self.static_inputs.insert(target, BspValue::new(value));
351 }
352
353 pub fn register_condition(
355 &mut self,
356 name: impl Into<String>,
357 f: impl Fn(&S, &crate::run::ValueStore) -> bool + Send + Sync + 'static,
358 ) {
359 self.conditions.insert(name.into(), std::sync::Arc::new(f));
360 }
361
362 pub fn register_merger<M: crate::merge::Merger<S> + 'static>(
364 &mut self,
365 name: impl Into<String>,
366 merger: M,
367 ) {
368 self.mergers
369 .insert(name.into(), std::sync::Arc::new(merger));
370 }
371
372 pub fn add_entry(&mut self, id: impl Into<NodeId>) {
374 self.entry.push(id.into());
375 }
376
377 #[must_use]
379 pub fn node_label(&self, id: NodeId) -> Option<&str> {
380 self.labels.get(&id).map(String::as_str)
381 }
382
383 pub fn node_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
385 self.nodes.keys().copied()
386 }
387
388 #[must_use]
390 pub fn edges(&self) -> &[Edge<S>] {
391 &self.edges
392 }
393
394 pub(crate) fn entries(&self) -> indexmap::IndexSet<NodeId> {
396 let mut entries: indexmap::IndexSet<NodeId> = indexmap::IndexSet::new();
397 for &id in &self.entry {
398 entries.insert(id);
399 }
400 for &id in self.nodes.keys() {
401 if self.incoming.get(&id).is_none_or(Vec::is_empty) {
402 entries.insert(id);
403 }
404 }
405 entries
406 }
407
408 pub(crate) fn push_edge(&mut self, edge: Edge<S>) {
410 let id = self.edges.len();
411 if let Some(target_port) = edge.target_port {
412 self.incoming_by_pin
413 .entry(InputPin {
414 node_id: edge.target,
415 port: target_port,
416 })
417 .or_default()
418 .push(id);
419 }
420 self.incoming.entry(edge.target).or_default().push(id);
421 self.outgoing.entry(edge.source).or_default().push(id);
422 self.edges.push(edge);
423 }
424
425 fn reindex_edge_ports(&mut self, id: EdgeId) {
427 let edge = &self.edges[id];
428 if let Some(target_port) = edge.target_port {
429 let pin = InputPin {
430 node_id: edge.target,
431 port: target_port,
432 };
433 let list = self.incoming_by_pin.entry(pin).or_default();
434 if !list.contains(&id) {
435 list.push(id);
436 }
437 }
438 }
439
440 #[must_use]
445 pub fn with_node_id(mut self, id: impl Into<NodeId>, node: Box<dyn BspNode<S>>) -> Self {
446 self.add_node_with_id(id, node);
447 self
448 }
449
450 #[must_use]
451 pub fn with_link(mut self, source: OutputPin, target: InputPin) -> Self {
452 self.add_link(source, target);
453 self
454 }
455
456 #[must_use]
457 pub fn with_static_input<T: std::any::Any + Send + Sync>(
458 mut self,
459 target: InputPin,
460 value: T,
461 ) -> Self {
462 self.set_static_input(target, value);
463 self
464 }
465
466 #[must_use]
467 pub fn with_condition(
468 mut self,
469 name: impl Into<String>,
470 f: impl Fn(&S, &crate::run::ValueStore) -> bool + Send + Sync + 'static,
471 ) -> Self {
472 self.register_condition(name, f);
473 self
474 }
475
476 #[must_use]
477 pub fn with_merger<M: crate::merge::Merger<S> + 'static>(
478 mut self,
479 name: impl Into<String>,
480 merger: M,
481 ) -> Self {
482 self.register_merger(name, merger);
483 self
484 }
485}