1use std::{
2 any::{Any, type_name},
3 fmt,
4 sync::Arc,
5};
6
7use indexmap::IndexMap;
8
9use super::{
10 error::BspError,
11 graph::{NodeId, OutputPin, PortIndex},
12 node::NodeOutcome,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct BspSkip;
18
19#[derive(Clone)]
21pub struct BspValue {
22 inner: Arc<dyn Any + Send + Sync>,
23 type_name: &'static str,
24}
25
26impl fmt::Debug for BspValue {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.debug_struct("BspValue")
29 .field("type_name", &self.type_name)
30 .finish_non_exhaustive()
31 }
32}
33
34impl BspValue {
35 pub fn new<T: Any + Send + Sync>(val: T) -> Self {
36 Self {
37 inner: Arc::new(val) as Arc<dyn Any + Send + Sync>,
38 type_name: type_name::<T>(),
39 }
40 }
41
42 #[must_use]
43 pub const fn type_name(&self) -> &'static str {
44 self.type_name
45 }
46
47 #[must_use]
48 pub fn is<T: Any>(&self) -> bool {
49 self.inner.as_ref().is::<T>()
50 }
51
52 pub fn downcast<T: Any + Send + Sync>(self) -> Result<Arc<T>, Self> {
53 if self.is::<T>() {
54 let type_name = self.type_name;
55 match self.inner.downcast::<T>() {
56 Ok(arc_t) => Ok(arc_t),
57 Err(arc_any) => Err(Self {
58 inner: arc_any,
59 type_name,
60 }),
61 }
62 } else {
63 Err(self)
64 }
65 }
66
67 #[must_use]
68 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
69 self.inner.as_ref().downcast_ref::<T>()
70 }
71
72 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
73 Arc::get_mut(&mut self.inner)?.downcast_mut::<T>()
74 }
75}
76
77pub trait BspFromValue: Sized {
83 fn from_value(value: BspValue, node_id: NodeId, port: PortIndex) -> Result<Self, BspError>;
84}
85
86pub trait BspToValue {
88 fn to_value(self) -> BspValue;
89}
90
91pub trait BspOutputPacker {
93 fn output_ports() -> Vec<PortIndex>;
94 fn pack(self, node_id: NodeId, node_name: &str) -> Result<NodeOutcome, BspError>;
95
96 fn pack_outputs(
103 self,
104 node_id: NodeId,
105 node_name: &str,
106 ) -> Result<IndexMap<PortIndex, BspValue>, BspError>
107 where
108 Self: Sized,
109 {
110 match self.pack(node_id, node_name)? {
111 NodeOutcome::Success(outputs) => Ok(outputs),
112 NodeOutcome::Suspend { .. } => Err(BspError::ValidationError(format!(
113 "node '{node_name}' suspended: suspend outcomes have no port map; \
114 implement BspNode directly for suspend-capable nodes"
115 ))),
116 }
117 }
118
119 #[must_use]
121 fn is_dynamic() -> bool {
122 false
123 }
124}
125
126impl<T: Any + Send + Sync> BspFromValue for Arc<T> {
128 fn from_value(value: BspValue, node_id: NodeId, port: PortIndex) -> Result<Self, BspError> {
129 let found_type = value.type_name();
130 value.downcast::<T>().map_err(|_| BspError::TypeMismatch {
131 node_id,
132 port_index: port,
133 expected: type_name::<T>(),
134 found: found_type,
135 })
136 }
137}
138
139impl<T: Any + Send + Sync> BspToValue for Arc<T> {
140 fn to_value(self) -> BspValue {
141 BspValue {
142 inner: self as Arc<dyn Any + Send + Sync>,
143 type_name: type_name::<T>(),
144 }
145 }
146}
147
148impl<T: BspFromValue> BspFromValue for Option<T> {
149 fn from_value(value: BspValue, node_id: NodeId, port: PortIndex) -> Result<Self, BspError> {
150 if value.is::<BspSkip>() {
151 Ok(None)
152 } else {
153 T::from_value(value, node_id, port).map(Some)
154 }
155 }
156}
157
158impl<T: BspToValue + 'static> BspToValue for Option<T> {
159 fn to_value(self) -> BspValue {
160 self.map_or_else(|| BspValue::new(BspSkip), BspToValue::to_value)
161 }
162}
163
164impl<T: BspToValue + 'static> BspOutputPacker for Option<T> {
165 fn output_ports() -> Vec<PortIndex> {
166 vec![0]
167 }
168 fn pack(self, _node_id: NodeId, _node_name: &str) -> Result<NodeOutcome, BspError> {
169 let mut outputs = IndexMap::new();
170 outputs.insert(0, self.to_value());
171 Ok(NodeOutcome::Success(outputs))
172 }
173}
174
175impl BspOutputPacker for NodeOutcome {
177 fn output_ports() -> Vec<PortIndex> {
178 vec![0]
179 }
180 fn pack(self, _node_id: NodeId, _node_name: &str) -> Result<NodeOutcome, BspError> {
181 Ok(self)
182 }
183 fn is_dynamic() -> bool {
184 true
185 }
186}
187
188impl<T: Any + Send + Sync> BspOutputPacker for Arc<T> {
190 fn output_ports() -> Vec<PortIndex> {
191 vec![0]
192 }
193 fn pack(self, _node_id: NodeId, _node_name: &str) -> Result<NodeOutcome, BspError> {
194 let mut outputs = IndexMap::new();
195 outputs.insert(0, self.to_value());
196 Ok(NodeOutcome::Success(outputs))
197 }
198}
199
200impl BspOutputPacker for () {
202 fn output_ports() -> Vec<PortIndex> {
203 Vec::new()
204 }
205 fn pack(self, _node_id: NodeId, _node_name: &str) -> Result<NodeOutcome, BspError> {
206 Ok(NodeOutcome::Success(IndexMap::new()))
207 }
208}
209
210impl<T: BspOutputPacker, E: std::fmt::Display> BspOutputPacker for Result<T, E> {
212 fn output_ports() -> Vec<PortIndex> {
213 T::output_ports()
214 }
215 fn pack(self, node_id: NodeId, node_name: &str) -> Result<NodeOutcome, BspError> {
216 match self {
217 Ok(val) => val.pack(node_id, node_name),
218 Err(e) => Err(BspError::NodeExecutionFailed {
219 node_id,
220 node_name: node_name.to_string(),
221 message: e.to_string(),
222 }),
223 }
224 }
225 fn is_dynamic() -> bool {
226 T::is_dynamic()
227 }
228}
229
230impl<T1, T2> BspOutputPacker for (T1, T2)
235where
236 T1: BspToValue + 'static,
237 T2: BspToValue + 'static,
238{
239 fn output_ports() -> Vec<PortIndex> {
240 vec![0, 1]
241 }
242 fn pack(self, _node_id: NodeId, _node_name: &str) -> Result<NodeOutcome, BspError> {
243 let mut outputs = IndexMap::new();
244 outputs.insert(0, self.0.to_value());
245 outputs.insert(1, self.1.to_value());
246 Ok(NodeOutcome::Success(outputs))
247 }
248}
249
250impl<T1, T2, T3> BspOutputPacker for (T1, T2, T3)
251where
252 T1: BspToValue + 'static,
253 T2: BspToValue + 'static,
254 T3: BspToValue + 'static,
255{
256 fn output_ports() -> Vec<PortIndex> {
257 vec![0, 1, 2]
258 }
259 fn pack(self, _node_id: NodeId, _node_name: &str) -> Result<NodeOutcome, BspError> {
260 let mut outputs = IndexMap::new();
261 outputs.insert(0, self.0.to_value());
262 outputs.insert(1, self.1.to_value());
263 outputs.insert(2, self.2.to_value());
264 Ok(NodeOutcome::Success(outputs))
265 }
266}
267
268impl<T: BspFromValue + Clone + Send + Sync + 'static> BspFromValue for Vec<T> {
273 fn from_value(value: BspValue, node_id: NodeId, port: PortIndex) -> Result<Self, BspError> {
274 if value.is::<BspSkip>() {
275 return Ok(Self::new());
276 }
277
278 if value.is::<Self>() {
280 let arc_vec = value
281 .downcast::<Self>()
282 .map_err(|err| BspError::TypeMismatch {
283 node_id,
284 port_index: port,
285 expected: std::any::type_name::<Self>(),
286 found: err.type_name(), })?;
288 return Ok((*arc_vec).clone());
289 }
290
291 if let Some(vec_bsp) = value.downcast_ref::<Vec<BspValue>>() {
292 let mut result = Self::with_capacity(vec_bsp.len());
293 for val in vec_bsp {
294 if !val.is::<BspSkip>() {
295 result.push(T::from_value(val.clone(), node_id, port)?);
296 }
297 }
298 Ok(result)
299 } else {
300 Ok(vec![T::from_value(value, node_id, port)?])
301 }
302 }
303}
304
305impl<T: BspToValue + Send + Sync + 'static> BspToValue for Vec<T> {
306 fn to_value(self) -> BspValue {
307 BspValue::new(self)
308 }
309}
310
311impl<T: BspToValue + Send + Sync + 'static> BspOutputPacker for Vec<T> {
312 fn output_ports() -> Vec<PortIndex> {
313 vec![0]
314 }
315 fn pack(self, _node_id: NodeId, _node_name: &str) -> Result<NodeOutcome, BspError> {
316 let mut outputs = IndexMap::new();
317 outputs.insert(0, self.to_value());
318 Ok(NodeOutcome::Success(outputs))
319 }
320}
321
322pub trait BspOutputMapExt {
327 fn get_typed<T: std::any::Any + Send + Sync + Clone>(
328 &self,
329 pin: OutputPin,
330 ) -> Result<T, BspError>;
331}
332
333impl BspOutputMapExt for IndexMap<OutputPin, BspValue> {
334 fn get_typed<T: std::any::Any + Send + Sync + Clone>(
335 &self,
336 pin: OutputPin,
337 ) -> Result<T, BspError> {
338 let value = self.get(&pin).ok_or(BspError::NodeNotFound {
339 node_id: pin.node_id,
340 })?;
341 let found_type = value.type_name();
342 let arc_t = value
343 .clone()
344 .downcast::<T>()
345 .map_err(|_| BspError::TypeMismatch {
346 node_id: pin.node_id,
347 port_index: pin.port,
348 expected: std::any::type_name::<T>(),
349 found: found_type,
350 })?;
351 Ok((*arc_t).clone())
352 }
353}
354
355#[macro_export]
360macro_rules! register_bsp_type {
361 ($t:ty) => {
362 impl $crate::value::BspFromValue for $t {
363 fn from_value(
364 value: $crate::value::BspValue,
365 node_id: $crate::graph::NodeId,
366 port: $crate::graph::PortIndex,
367 ) -> Result<Self, $crate::error::BspError> {
368 let found_type = value.type_name();
369 let arc_t =
370 value
371 .downcast::<$t>()
372 .map_err(|_| $crate::error::BspError::TypeMismatch {
373 node_id,
374 port_index: port,
375 expected: std::any::type_name::<$t>(),
376 found: found_type,
377 })?;
378 Ok((*arc_t).clone())
379 }
380 }
381
382 impl $crate::value::BspToValue for $t {
383 fn to_value(self) -> $crate::value::BspValue {
384 $crate::value::BspValue::new(self)
385 }
386 }
387
388 impl $crate::value::BspOutputPacker for $t {
389 fn output_ports() -> Vec<$crate::graph::PortIndex> {
390 vec![0]
391 }
392 fn pack(
393 self,
394 _node_id: $crate::graph::NodeId,
395 _node_name: &str,
396 ) -> Result<$crate::node::NodeOutcome, $crate::error::BspError> {
397 let mut outputs = ::indexmap::IndexMap::new();
398 outputs.insert(0, $crate::value::BspToValue::to_value(self));
399 Ok($crate::node::NodeOutcome::Success(outputs))
400 }
401 }
402 };
403}
404
405register_bsp_type!(i64);
407register_bsp_type!(f64);
408register_bsp_type!(bool);
409register_bsp_type!(String);
410register_bsp_type!(serde_json::Value);
411register_bsp_type!(BspSkip);