token_value_map/
data.rs

1use crate::{
2    DataTypeOps,
3    macros::{impl_data_arithmetic, impl_data_type_ops, impl_try_from_vec},
4    *,
5};
6#[cfg(feature = "matrix3")]
7use bytemuck::cast;
8use bytemuck::cast_slice;
9use std::{
10    fmt::Display,
11    ops::{Add, Div, Mul, Sub},
12    str::FromStr,
13};
14use strum::IntoDiscriminant;
15
16/// A variant `enum` containing all supported data types.
17///
18/// [`Data`] can hold scalar values ([`Boolean`], [`Integer`], [`Real`],
19/// [`String`]), vector types ([`Vector2`], [`Vector3`], [`Color`],
20/// [`Matrix3`]), and collections of these types ([`BooleanVec`],
21/// [`IntegerVec`], etc.).
22#[derive(Debug, Clone, PartialEq, strum::AsRefStr, strum::EnumDiscriminants)]
23#[strum_discriminants(name(DataType))]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub enum Data {
26    /// A boolean value.
27    Boolean(Boolean),
28    /// A 64-bit signed integer.
29    Integer(Integer),
30    /// A 64-bit floating-point number.
31    Real(Real),
32    /// A UTF-8 string.
33    String(String),
34    /// A 4-component RGBA color.
35    Color(Color),
36    /// A 2D vector.
37    #[cfg(feature = "vector2")]
38    Vector2(Vector2),
39    /// A 3D vector.
40    #[cfg(feature = "vector3")]
41    Vector3(Vector3),
42    /// A 3×3 transformation matrix.
43    #[cfg(feature = "matrix3")]
44    Matrix3(Matrix3),
45    /// A 3D normal vector.
46    #[cfg(feature = "normal3")]
47    Normal3(Normal3),
48    /// A 3D point.
49    #[cfg(feature = "point3")]
50    Point3(Point3),
51    /// A 4×4 transformation matrix.
52    #[cfg(feature = "matrix4")]
53    Matrix4(Matrix4),
54    /// A vector of boolean values.
55    BooleanVec(BooleanVec),
56    /// A vector of integer values.
57    IntegerVec(IntegerVec),
58    /// A vector of real values.
59    RealVec(RealVec),
60    /// A vector of color values.
61    ColorVec(ColorVec),
62    /// A vector of string values.
63    StringVec(StringVec),
64    /// A vector of 2D vectors.
65    #[cfg(all(feature = "vector2", feature = "vec_variants"))]
66    Vector2Vec(Vector2Vec),
67    /// A vector of 3D vectors.
68    #[cfg(all(feature = "vector3", feature = "vec_variants"))]
69    Vector3Vec(Vector3Vec),
70    /// A vector of matrices.
71    #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
72    Matrix3Vec(Matrix3Vec),
73    /// A vector of 3D normals.
74    #[cfg(all(feature = "normal3", feature = "vec_variants"))]
75    Normal3Vec(Normal3Vec),
76    /// A vector of 3D points.
77    #[cfg(all(feature = "point3", feature = "vec_variants"))]
78    Point3Vec(Point3Vec),
79    /// A vector of 4×4 matrices.
80    #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
81    Matrix4Vec(Matrix4Vec),
82}
83
84impl_data_type_ops!(Data);
85
86impl Data {
87    /// Get the length of a vector value, or `1` for scalar values
88    #[allow(clippy::len_without_is_empty)]
89    pub fn len(&self) -> usize {
90        self.try_len().unwrap_or(1)
91    }
92
93    /// Get the length of a vector value, or None for scalar values
94    pub fn try_len(&self) -> Option<usize> {
95        match self {
96            Data::BooleanVec(v) => Some(v.0.len()),
97            Data::IntegerVec(v) => Some(v.0.len()),
98            Data::RealVec(v) => Some(v.0.len()),
99            Data::StringVec(v) => Some(v.0.len()),
100            Data::ColorVec(v) => Some(v.0.len()),
101            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
102            Data::Vector2Vec(v) => Some(v.0.len()),
103            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
104            Data::Vector3Vec(v) => Some(v.0.len()),
105            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
106            Data::Matrix3Vec(v) => Some(v.0.len()),
107            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
108            Data::Normal3Vec(v) => Some(v.0.len()),
109            #[cfg(all(feature = "point3", feature = "vec_variants"))]
110            Data::Point3Vec(v) => Some(v.0.len()),
111            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
112            Data::Matrix4Vec(v) => Some(v.0.len()),
113            _ => None,
114        }
115    }
116
117    /// If this is a vector value.
118    pub fn is_vec(&self) -> bool {
119        self.try_len().is_some()
120    }
121
122    #[named]
123    pub fn to_bool(&self) -> Result<bool> {
124        match self {
125            Data::Boolean(value) => Ok(value.0),
126            Data::Real(value) => Ok(value.0 != 0.0),
127            Data::Integer(value) => Ok(value.0 != 0),
128            Data::String(value) => Ok(value.0.parse::<bool>().unwrap_or(false)),
129            _ => Err(anyhow!(
130                "{}: called on '{:?}'",
131                function_name!(),
132                self.discriminant()
133            )),
134        }
135    }
136
137    pub fn to_f32(&self) -> Result<f32> {
138        match self {
139            Data::Boolean(value) => {
140                if value.0 {
141                    Ok(1.0)
142                } else {
143                    Ok(0.0)
144                }
145            }
146            Data::Real(value) => Ok(value.0 as _),
147            Data::Integer(value) => Ok(value.0 as _),
148            _ => Err(anyhow!(
149                "to_f32() called on incompatible data type: {:?}",
150                self.data_type()
151            )),
152        }
153    }
154
155    pub fn to_f64(&self) -> Result<f64> {
156        match self {
157            Data::Boolean(value) => {
158                if value.0 {
159                    Ok(1.0)
160                } else {
161                    Ok(0.0)
162                }
163            }
164            Data::Real(value) => Ok(value.0),
165            Data::Integer(value) => Ok(value.0 as _),
166            _ => Err(anyhow!(
167                "to_f64() called on incompatible data type: {:?}",
168                self.data_type()
169            )),
170        }
171    }
172
173    #[named]
174    pub fn to_i32(&self) -> Result<i32> {
175        match self {
176            Data::Boolean(value) => Ok(if value.0 { 1 } else { 0 }),
177            Data::Real(value) => Ok((value.0 + 0.5) as i32),
178            // FIXME: this may wrap around.
179            Data::Integer(value) => value
180                .0
181                .try_into()
182                .map_err(|e: std::num::TryFromIntError| anyhow!("Integer conversion error: {}", e)),
183            _ => Err(anyhow!(
184                "{}: called on incompatible data type '{:?}'",
185                function_name!(),
186                self.discriminant()
187            )),
188        }
189    }
190
191    #[named]
192    pub fn to_i64(&self) -> Result<i64> {
193        match self {
194            Data::Boolean(value) => {
195                if value.0 {
196                    Ok(1)
197                } else {
198                    Ok(0)
199                }
200            }
201            Data::Real(value) => Ok((value.0 + 0.5) as _),
202            Data::Integer(value) => Ok(value.0),
203            _ => Err(anyhow!(
204                "{}: called on incompatible data type '{:?}'",
205                function_name!(),
206                self.discriminant()
207            )),
208        }
209    }
210
211    #[named]
212    pub fn as_slice_f64(&self) -> Result<&[f64]> {
213        match self {
214            Data::RealVec(value) => Ok(value.0.as_slice()),
215            #[cfg(feature = "matrix4")]
216            Data::Matrix4(value) => Ok(value.0.as_slice()),
217            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
218            Data::Matrix4Vec(value) => {
219                // Convert Vec<nalgebra::Matrix4<f64>> to &[f64]
220                Ok(bytemuck::cast_slice(&value.0))
221            }
222            _ => Err(anyhow!(
223                "{}: called on incompatible data type '{:?}'",
224                function_name!(),
225                self.discriminant()
226            )),
227        }
228    }
229
230    #[named]
231    pub fn as_slice_f32(&self) -> Result<&[f32]> {
232        match self {
233            Data::Color(value) => Ok(value.0.as_slice()),
234            #[cfg(feature = "vector2")]
235            Data::Vector2(value) => Ok(value.0.as_slice()),
236            #[cfg(feature = "vector3")]
237            Data::Vector3(value) => Ok(value.0.as_slice()),
238            #[cfg(feature = "matrix3")]
239            Data::Matrix3(value) => Ok(value.0.as_slice()),
240            #[cfg(feature = "normal3")]
241            Data::Normal3(value) => Ok(value.0.as_slice()),
242            #[cfg(feature = "point3")]
243            Data::Point3(value) => Ok(value.0.coords.as_slice()),
244            Data::ColorVec(value) => Ok(cast_slice(value.0.as_slice())),
245            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
246            Data::Vector2Vec(value) => {
247                // Convert Vec<nalgebra::Vector2<f32>> to &[f32]
248                Ok(bytemuck::cast_slice(&value.0))
249            }
250            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
251            Data::Vector3Vec(value) => {
252                // Convert Vec<nalgebra::Vector3<f32>> to &[f32]
253                Ok(bytemuck::cast_slice(&value.0))
254            }
255            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
256            Data::Matrix3Vec(value) => {
257                // Convert Vec<nalgebra::Matrix3<f32>> to &[f32]
258                Ok(bytemuck::cast_slice(&value.0))
259            }
260            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
261            Data::Normal3Vec(value) => {
262                // Convert Vec<nalgebra::Point3<f32>> to &[f32]
263                Ok(bytemuck::cast_slice(&value.0))
264            }
265            #[cfg(all(feature = "point3", feature = "vec_variants"))]
266            Data::Point3Vec(value) => {
267                // Convert Vec<nalgebra::Point3<f32>> to &[f32]
268                Ok(bytemuck::cast_slice(&value.0))
269            }
270            _ => Err(anyhow!(
271                "{}: called on incompatible data type '{:?}'",
272                function_name!(),
273                self.discriminant()
274            )),
275        }
276    }
277
278    #[named]
279    pub fn as_slice_i64(&self) -> Result<&[i64]> {
280        match self {
281            Data::IntegerVec(value) => Ok(value.0.as_slice()),
282            _ => Err(anyhow!(
283                "{}: called on incompatible data type '{:?}'",
284                function_name!(),
285                self.discriminant()
286            )),
287        }
288    }
289
290    #[named]
291    pub fn as_vector2_ref(&self) -> Result<&[f32; 2]> {
292        match self {
293            #[cfg(feature = "vector2")]
294            Data::Vector2(value) => Ok(value.0.as_ref()),
295            _ => Err(anyhow!(
296                "{}: called on incompatible data type '{:?}'",
297                function_name!(),
298                self.discriminant()
299            )),
300        }
301    }
302
303    #[named]
304    pub fn as_vector3_ref(&self) -> Result<&[f32; 3]> {
305        match self {
306            #[cfg(feature = "vector3")]
307            Data::Vector3(value) => Ok(value.0.as_ref()),
308            _ => Err(anyhow!(
309                "{}: called on incompatible data type '{:?}'",
310                function_name!(),
311                self.discriminant()
312            )),
313        }
314    }
315
316    #[named]
317    pub fn as_matrix3_ref(&self) -> Result<&[f32; 9]> {
318        match self {
319            #[cfg(feature = "matrix3")]
320            Data::Matrix3(value) => {
321                // nalgebra Matrix3 stores data in column-major order, cast
322                // directly from Matrix3
323                Ok(bytemuck::cast_ref(&value.0))
324            }
325            _ => Err(anyhow!(
326                "{}: called on incompatible data type '{:?}'",
327                function_name!(),
328                self.discriminant()
329            )),
330        }
331    }
332
333    #[named]
334    pub fn as_color_ref(&self) -> Result<&[f32; 4]> {
335        match self {
336            Data::Color(value) => Ok(&value.0),
337            _ => Err(anyhow!(
338                "{}: called on incompatible data type '{:?}'",
339                function_name!(),
340                self.discriminant()
341            )),
342        }
343    }
344
345    #[named]
346    #[cfg(feature = "normal3")]
347    pub fn as_normal3_ref(&self) -> Result<&[f32; 3]> {
348        match self {
349            Data::Normal3(value) => Ok(value.0.as_ref()),
350            _ => Err(anyhow!(
351                "{}: called on incompatible data type '{:?}'",
352                function_name!(),
353                self.discriminant()
354            )),
355        }
356    }
357
358    #[named]
359    #[cfg(feature = "point3")]
360    pub fn as_point3_ref(&self) -> Result<&[f32; 3]> {
361        match self {
362            Data::Point3(value) => Ok(value.0.coords.as_ref()),
363            _ => Err(anyhow!(
364                "{}: called on incompatible data type '{:?}'",
365                function_name!(),
366                self.discriminant()
367            )),
368        }
369    }
370
371    #[named]
372    #[cfg(feature = "matrix4")]
373    pub fn as_matrix4_ref(&self) -> Result<&[f64; 16]> {
374        match self {
375            Data::Matrix4(value) => {
376                // nalgebra Matrix4 stores data in column-major order, cast
377                // directly from Matrix4
378                Ok(bytemuck::cast_ref(&value.0))
379            }
380            _ => Err(anyhow!(
381                "{}: called on incompatible data type '{:?}'",
382                function_name!(),
383                self.discriminant()
384            )),
385        }
386    }
387
388    #[named]
389    pub fn as_str(&self) -> Result<&str> {
390        match self {
391            Data::String(value) => Ok(value.0.as_str()),
392            _ => Err(anyhow!(
393                "{}: called on incompatible data type '{:?}'",
394                function_name!(),
395                self.discriminant()
396            )),
397        }
398    }
399
400    #[named]
401    pub fn as_slice_string(&self) -> Result<&[std::string::String]> {
402        match self {
403            Data::StringVec(value) => Ok(value.0.as_slice()),
404            _ => Err(anyhow!(
405                "{}: called on incompatible data type '{:?}'",
406                function_name!(),
407                self.discriminant()
408            )),
409        }
410    }
411}
412
413// Macro to implement From trait for primitive types
414macro_rules! impl_from_primitive {
415    ($from:ty, $variant:ident, $wrapper:ident) => {
416        impl From<$from> for Data {
417            fn from(v: $from) -> Self {
418                Data::$variant($wrapper(v as _))
419            }
420        }
421    };
422}
423
424// Implement From for all primitive types
425impl_from_primitive!(i64, Integer, Integer);
426impl_from_primitive!(i32, Integer, Integer);
427impl_from_primitive!(i16, Integer, Integer);
428impl_from_primitive!(i8, Integer, Integer);
429impl_from_primitive!(u32, Integer, Integer);
430impl_from_primitive!(u16, Integer, Integer);
431impl_from_primitive!(u8, Integer, Integer);
432
433impl_from_primitive!(f64, Real, Real);
434impl_from_primitive!(f32, Real, Real);
435
436impl_from_primitive!(bool, Boolean, Boolean);
437
438impl From<std::string::String> for Data {
439    fn from(v: std::string::String) -> Self {
440        Data::String(String(v))
441    }
442}
443
444impl From<&str> for Data {
445    fn from(v: &str) -> Self {
446        Data::String(String(v.into()))
447    }
448}
449
450// From implementations for arrays
451#[cfg(feature = "vector2")]
452impl From<[f32; 2]> for Data {
453    fn from(v: [f32; 2]) -> Self {
454        Data::Vector2(Vector2(v.into()))
455    }
456}
457
458#[cfg(feature = "vector3")]
459impl From<[f32; 3]> for Data {
460    fn from(v: [f32; 3]) -> Self {
461        Data::Vector3(Vector3(v.into()))
462    }
463}
464
465#[cfg(feature = "matrix3")]
466impl From<[[f32; 3]; 3]> for Data {
467    fn from(v: [[f32; 3]; 3]) -> Self {
468        let arr: [f32; 9] = cast(v);
469        Data::Matrix3(Matrix3(nalgebra::Matrix3::from_row_slice(&arr)))
470    }
471}
472
473#[cfg(feature = "matrix3")]
474impl From<[f32; 9]> for Data {
475    fn from(v: [f32; 9]) -> Self {
476        Data::Matrix3(Matrix3(nalgebra::Matrix3::from_row_slice(&v)))
477    }
478}
479
480impl From<[f32; 4]> for Data {
481    fn from(v: [f32; 4]) -> Self {
482        Data::Color(Color(v))
483    }
484}
485
486// From implementations for nalgebra types
487#[cfg(feature = "vector2")]
488impl From<nalgebra::Vector2<f32>> for Data {
489    fn from(v: nalgebra::Vector2<f32>) -> Self {
490        Data::Vector2(Vector2(v))
491    }
492}
493
494#[cfg(feature = "vector3")]
495impl From<nalgebra::Vector3<f32>> for Data {
496    fn from(v: nalgebra::Vector3<f32>) -> Self {
497        Data::Vector3(Vector3(v))
498    }
499}
500
501#[cfg(feature = "matrix3")]
502impl From<nalgebra::Matrix3<f32>> for Data {
503    fn from(v: nalgebra::Matrix3<f32>) -> Self {
504        Data::Matrix3(Matrix3(v))
505    }
506}
507
508// From implementations for Vec types
509impl TryFrom<Vec<i64>> for Data {
510    type Error = anyhow::Error;
511
512    fn try_from(v: Vec<i64>) -> Result<Self> {
513        Ok(Data::IntegerVec(IntegerVec::new(v)?))
514    }
515}
516
517impl TryFrom<Vec<f64>> for Data {
518    type Error = anyhow::Error;
519
520    fn try_from(v: Vec<f64>) -> Result<Self> {
521        Ok(Data::RealVec(RealVec::new(v)?))
522    }
523}
524
525impl TryFrom<Vec<bool>> for Data {
526    type Error = anyhow::Error;
527
528    fn try_from(v: Vec<bool>) -> Result<Self> {
529        Ok(Data::BooleanVec(BooleanVec::new(v)?))
530    }
531}
532
533impl TryFrom<Vec<&str>> for Data {
534    type Error = anyhow::Error;
535
536    fn try_from(v: Vec<&str>) -> Result<Self> {
537        let string_vec: Vec<std::string::String> = v.into_iter().map(|s| s.to_string()).collect();
538        Ok(Data::StringVec(StringVec::new(string_vec)?))
539    }
540}
541
542impl TryFrom<Vec<[f32; 4]>> for Data {
543    type Error = anyhow::Error;
544
545    fn try_from(v: Vec<[f32; 4]>) -> Result<Self> {
546        Ok(Data::ColorVec(ColorVec::new(v)?))
547    }
548}
549
550#[cfg(all(feature = "vector2", feature = "vec_variants"))]
551impl TryFrom<Vec<nalgebra::Vector2<f32>>> for Data {
552    type Error = anyhow::Error;
553
554    fn try_from(v: Vec<nalgebra::Vector2<f32>>) -> Result<Self> {
555        Ok(Data::Vector2Vec(Vector2Vec::new(v)?))
556    }
557}
558
559#[cfg(all(feature = "vector3", feature = "vec_variants"))]
560impl TryFrom<Vec<nalgebra::Vector3<f32>>> for Data {
561    type Error = anyhow::Error;
562
563    fn try_from(v: Vec<nalgebra::Vector3<f32>>) -> Result<Self> {
564        Ok(Data::Vector3Vec(Vector3Vec::new(v)?))
565    }
566}
567
568#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
569impl TryFrom<Vec<nalgebra::Matrix3<f32>>> for Data {
570    type Error = anyhow::Error;
571
572    fn try_from(v: Vec<nalgebra::Matrix3<f32>>) -> Result<Self> {
573        Ok(Data::Matrix3Vec(Matrix3Vec::new(v)?))
574    }
575}
576
577impl From<Vec<u32>> for Data {
578    fn from(v: Vec<u32>) -> Self {
579        let int_vec: Vec<i64> = v.into_iter().map(|x| x as i64).collect();
580        Data::IntegerVec(IntegerVec(int_vec))
581    }
582}
583
584impl From<Vec<f32>> for Data {
585    fn from(v: Vec<f32>) -> Self {
586        let real_vec: Vec<f64> = v.into_iter().map(|x| x as f64).collect();
587        Data::RealVec(RealVec(real_vec))
588    }
589}
590
591impl TryFrom<Vec<std::string::String>> for Data {
592    type Error = anyhow::Error;
593
594    fn try_from(v: Vec<std::string::String>) -> Result<Self> {
595        Ok(Data::StringVec(StringVec::new(v)?))
596    }
597}
598
599macro_rules! impl_try_from_value {
600    ($target:ty, $variant:ident) => {
601        impl TryFrom<Data> for $target {
602            type Error = anyhow::Error;
603
604            fn try_from(value: Data) -> Result<Self, Self::Error> {
605                match value {
606                    Data::$variant(v) => Ok(v.0),
607                    _ => Err(anyhow!(
608                        "Could not convert {} to {}",
609                        stringify!($variant),
610                        stringify!($target)
611                    )),
612                }
613            }
614        }
615
616        impl TryFrom<&Data> for $target {
617            type Error = anyhow::Error;
618
619            fn try_from(value: &Data) -> Result<Self, Self::Error> {
620                match value {
621                    Data::$variant(v) => Ok(v.0.clone()),
622                    _ => Err(anyhow!(
623                        "Could not convert &{} to {}",
624                        stringify!($variant),
625                        stringify!($target)
626                    )),
627                }
628            }
629        }
630    };
631}
632
633// Implement `TryFrom` for all types
634impl_try_from_value!(bool, Boolean);
635impl_try_from_value!(i64, Integer);
636impl_try_from_value!(f64, Real);
637impl_try_from_value!(std::string::String, String);
638impl_try_from_value!([f32; 4], Color);
639#[cfg(feature = "vector2")]
640impl_try_from_value!(nalgebra::Vector2<f32>, Vector2);
641#[cfg(feature = "vector3")]
642impl_try_from_value!(nalgebra::Vector3<f32>, Vector3);
643#[cfg(feature = "matrix3")]
644impl_try_from_value!(nalgebra::Matrix3<f32>, Matrix3);
645
646// TryFrom implementations for Vec types using macro
647impl_try_from_vec!(
648    bool, BooleanVec, "bool";
649    i64, IntegerVec, "i64";
650    f64, RealVec, "f64";
651    std::string::String, StringVec, "String";
652    [f32; 4], ColorVec, "[f32; 4]";
653);
654
655#[cfg(all(feature = "vector2", feature = "vec_variants"))]
656impl_try_from_vec!(
657    nalgebra::Vector2<f32>, Vector2Vec, "Vector2<f32>";
658);
659
660#[cfg(all(feature = "vector3", feature = "vec_variants"))]
661impl_try_from_vec!(
662    nalgebra::Vector3<f32>, Vector3Vec, "Vector3<f32>";
663);
664
665#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
666impl_try_from_vec!(
667    nalgebra::Matrix3<f32>, Matrix3Vec, "Matrix3<f32>";
668);
669
670// Custom Hash implementation
671impl Hash for Data {
672    fn hash<H: Hasher>(&self, state: &mut H) {
673        std::mem::discriminant(self).hash(state);
674        match self {
675            Data::Boolean(Boolean(b)) => b.hash(state),
676            Data::Integer(Integer(i)) => i.hash(state),
677            Data::Real(Real(f)) => f.to_bits().hash(state),
678            Data::String(String(s)) => s.hash(state),
679            Data::Color(Color(c)) => {
680                c.iter().for_each(|v| v.to_bits().hash(state));
681            }
682            #[cfg(feature = "vector2")]
683            Data::Vector2(Vector2(v)) => {
684                v.iter().for_each(|v| v.to_bits().hash(state));
685            }
686            #[cfg(feature = "vector3")]
687            Data::Vector3(Vector3(v)) => {
688                v.iter().for_each(|v| v.to_bits().hash(state));
689            }
690            #[cfg(feature = "matrix3")]
691            Data::Matrix3(Matrix3(m)) => {
692                m.iter().for_each(|v| v.to_bits().hash(state));
693            }
694            #[cfg(feature = "normal3")]
695            Data::Normal3(Normal3(v)) => {
696                v.iter().for_each(|v| v.to_bits().hash(state));
697            }
698            #[cfg(feature = "point3")]
699            Data::Point3(Point3(p)) => {
700                p.iter().for_each(|v| v.to_bits().hash(state));
701            }
702            #[cfg(feature = "matrix4")]
703            Data::Matrix4(Matrix4(m)) => {
704                m.iter().for_each(|v| v.to_bits().hash(state));
705            }
706            Data::BooleanVec(BooleanVec(v)) => v.hash(state),
707            Data::IntegerVec(IntegerVec(v)) => v.hash(state),
708            Data::RealVec(RealVec(v)) => {
709                v.len().hash(state);
710                v.iter().for_each(|v| v.to_bits().hash(state));
711            }
712            Data::StringVec(StringVec(v)) => v.hash(state),
713            Data::ColorVec(ColorVec(v)) => {
714                v.len().hash(state);
715                v.iter()
716                    .for_each(|c| c.iter().for_each(|v| v.to_bits().hash(state)));
717            }
718            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
719            Data::Vector2Vec(Vector2Vec(v)) => {
720                v.len().hash(state);
721                v.iter()
722                    .for_each(|v| v.iter().for_each(|v| v.to_bits().hash(state)));
723            }
724            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
725            Data::Vector3Vec(Vector3Vec(v)) => {
726                v.len().hash(state);
727                v.iter()
728                    .for_each(|v| v.iter().for_each(|v| v.to_bits().hash(state)));
729            }
730            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
731            Data::Matrix3Vec(Matrix3Vec(v)) => {
732                v.len().hash(state);
733                v.iter()
734                    .for_each(|m| m.iter().for_each(|v| v.to_bits().hash(state)));
735            }
736            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
737            Data::Normal3Vec(Normal3Vec(v)) => {
738                v.len().hash(state);
739                v.iter()
740                    .for_each(|v| v.iter().for_each(|v| v.to_bits().hash(state)));
741            }
742            #[cfg(all(feature = "point3", feature = "vec_variants"))]
743            Data::Point3Vec(Point3Vec(v)) => {
744                v.len().hash(state);
745                v.iter()
746                    .for_each(|p| p.iter().for_each(|v| v.to_bits().hash(state)));
747            }
748            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
749            Data::Matrix4Vec(Matrix4Vec(v)) => {
750                v.len().hash(state);
751                v.iter()
752                    .for_each(|m| m.iter().for_each(|v| v.to_bits().hash(state)));
753            }
754        }
755    }
756}
757
758impl Data {
759    /// Ensure a vector value has at least the specified length by padding with
760    /// defaults
761    pub fn pad_to_length(&mut self, target_len: usize) {
762        match self {
763            Data::BooleanVec(BooleanVec(v)) => v.resize(target_len, false),
764            Data::IntegerVec(IntegerVec(v)) => v.resize(target_len, 0),
765            Data::RealVec(RealVec(v)) => v.resize(target_len, 0.0),
766            Data::StringVec(StringVec(v)) => v.resize(target_len, std::string::String::new()),
767            Data::ColorVec(ColorVec(v)) => v.resize(target_len, [0.0, 0.0, 0.0, 1.0]),
768            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
769            Data::Vector2Vec(Vector2Vec(v)) => v.resize(target_len, nalgebra::Vector2::zeros()),
770            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
771            Data::Vector3Vec(Vector3Vec(v)) => v.resize(target_len, nalgebra::Vector3::zeros()),
772            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
773            Data::Matrix3Vec(Matrix3Vec(v)) => v.resize(target_len, nalgebra::Matrix3::zeros()),
774            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
775            Data::Normal3Vec(Normal3Vec(v)) => v.resize(target_len, nalgebra::Vector3::zeros()),
776            #[cfg(all(feature = "point3", feature = "vec_variants"))]
777            Data::Point3Vec(Point3Vec(v)) => v.resize(target_len, nalgebra::Point3::origin()),
778            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
779            Data::Matrix4Vec(Matrix4Vec(v)) => v.resize(target_len, nalgebra::Matrix4::zeros()),
780            _ => {} // Non-vector types are ignored
781        }
782    }
783
784    /// Try to convert this value to another type
785    pub fn try_convert(&self, to: DataType) -> Result<Data> {
786        match (self, to) {
787            // Same type - just clone
788            (v, target) if v.data_type() == target => Ok(v.clone()),
789
790            // To Integer conversions
791            (Data::Real(Real(f)), DataType::Integer) => Ok(Data::Integer(Integer(*f as i64))),
792            (Data::Boolean(Boolean(b)), DataType::Integer) => {
793                Ok(Data::Integer(Integer(if *b { 1 } else { 0 })))
794            }
795            (Data::String(String(s)), DataType::Integer) => s
796                .parse::<i64>()
797                .map(|i| Data::Integer(Integer(i)))
798                .map_err(|_| anyhow!("Cannot parse '{}' as Integer", s)),
799
800            // To Real conversions
801            (Data::Integer(Integer(i)), DataType::Real) => Ok(Data::Real(Real(*i as f64))),
802            (Data::Boolean(Boolean(b)), DataType::Real) => {
803                Ok(Data::Real(Real(if *b { 1.0 } else { 0.0 })))
804            }
805            (Data::String(String(s)), DataType::Real) => s
806                .parse::<f64>()
807                .map(|f| Data::Real(Real(f)))
808                .map_err(|_| anyhow!("Cannot parse '{}' as Real", s)),
809
810            // To Boolean conversions
811            (Data::Integer(Integer(i)), DataType::Boolean) => Ok(Data::Boolean(Boolean(*i != 0))),
812            (Data::Real(Real(f)), DataType::Boolean) => Ok(Data::Boolean(Boolean(*f != 0.0))),
813            (Data::String(String(s)), DataType::Boolean) => match s.to_lowercase().as_str() {
814                "true" | "yes" | "1" | "on" => Ok(Data::Boolean(Boolean(true))),
815                "false" | "no" | "0" | "off" | "" => Ok(Data::Boolean(Boolean(false))),
816                _ => Err(anyhow!("Cannot parse '{}' as Boolean", s)),
817            },
818
819            // To String conversions
820            (Data::Integer(Integer(i)), DataType::String) => {
821                Ok(Data::String(String(i.to_string())))
822            }
823            (Data::Real(Real(f)), DataType::String) => Ok(Data::String(String(f.to_string()))),
824            (Data::Boolean(Boolean(b)), DataType::String) => {
825                Ok(Data::String(String(b.to_string())))
826            }
827            #[cfg(feature = "vector2")]
828            (Data::Vector2(Vector2(v)), DataType::String) => {
829                Ok(Data::String(String(format!("[{}, {}]", v[0], v[1]))))
830            }
831            #[cfg(feature = "vector3")]
832            (Data::Vector3(Vector3(v)), DataType::String) => Ok(Data::String(String(format!(
833                "[{}, {}, {}]",
834                v[0], v[1], v[2]
835            )))),
836            (Data::Color(Color(c)), DataType::String) => Ok(Data::String(String(format!(
837                "[{}, {}, {}, {}]",
838                c[0], c[1], c[2], c[3]
839            )))),
840            #[cfg(feature = "matrix3")]
841            (Data::Matrix3(Matrix3(m)), DataType::String) => {
842                Ok(Data::String(String(format!("{m:?}"))))
843            }
844            #[cfg(feature = "normal3")]
845            (Data::Normal3(Normal3(v)), DataType::String) => Ok(Data::String(String(format!(
846                "[{}, {}, {}]",
847                v[0], v[1], v[2]
848            )))),
849            #[cfg(feature = "point3")]
850            (Data::Point3(Point3(p)), DataType::String) => {
851                Ok(Data::String(String(format!("[{}, {}, {}]", p.x, p.y, p.z))))
852            }
853            #[cfg(feature = "matrix4")]
854            (Data::Matrix4(Matrix4(m)), DataType::String) => {
855                Ok(Data::String(String(format!("{m:?}"))))
856            }
857
858            // To Vec2 conversions
859            #[cfg(feature = "vector2")]
860            (Data::Integer(Integer(i)), DataType::Vector2) => {
861                let v = *i as f32;
862                Ok(Data::Vector2(Vector2(nalgebra::Vector2::new(v, v))))
863            }
864            #[cfg(feature = "vector2")]
865            (Data::Real(Real(f)), DataType::Vector2) => {
866                let v = *f as f32;
867                Ok(Data::Vector2(Vector2(nalgebra::Vector2::new(v, v))))
868            }
869            #[cfg(feature = "vector2")]
870            (Data::RealVec(RealVec(vec)), DataType::Vector2) if vec.len() >= 2 => {
871                let v: Vec<f32> = vec.iter().take(2).map(|&x| x as f32).collect();
872                Ok(Data::Vector2(Vector2(nalgebra::Vector2::from_vec(v))))
873            }
874            #[cfg(feature = "vector2")]
875            (Data::IntegerVec(IntegerVec(vec)), DataType::Vector2) if vec.len() >= 2 => {
876                let v: Vec<f32> = vec.iter().take(2).map(|&x| x as f32).collect();
877                Ok(Data::Vector2(Vector2(nalgebra::Vector2::from_vec(v))))
878            }
879            #[cfg(feature = "vector2")]
880            (Data::String(String(s)), DataType::Vector2) => {
881                parse_to_array::<f32, 2>(s).map(|v| Data::Vector2(Vector2(v.into())))
882            }
883
884            // To Vec3 conversions
885            #[cfg(feature = "vector3")]
886            (Data::Integer(Integer(i)), DataType::Vector3) => {
887                let v = *i as f32;
888                Ok(Data::Vector3(Vector3(nalgebra::Vector3::new(v, v, v))))
889            }
890            #[cfg(feature = "vector3")]
891            (Data::Real(Real(f)), DataType::Vector3) => {
892                let v = *f as f32;
893                Ok(Data::Vector3(Vector3(nalgebra::Vector3::new(v, v, v))))
894            }
895            #[cfg(all(feature = "vector2", feature = "vector3"))]
896            (Data::Vector2(Vector2(v)), DataType::Vector3) => Ok(Data::Vector3(Vector3(
897                nalgebra::Vector3::new(v.x, v.y, 0.0),
898            ))),
899            #[cfg(feature = "vector3")]
900            (Data::RealVec(RealVec(vec)), DataType::Vector3) if vec.len() >= 3 => {
901                let v: Vec<f32> = vec.iter().take(3).map(|&x| x as f32).collect();
902                Ok(Data::Vector3(Vector3(nalgebra::Vector3::from_vec(v))))
903            }
904            #[cfg(feature = "vector3")]
905            (Data::IntegerVec(IntegerVec(vec)), DataType::Vector3) if vec.len() >= 3 => {
906                let v: Vec<f32> = vec.iter().take(3).map(|&x| x as f32).collect();
907                Ok(Data::Vector3(Vector3(nalgebra::Vector3::from_vec(v))))
908            }
909            #[cfg(feature = "vector3")]
910            (Data::ColorVec(ColorVec(vec)), DataType::Vector3) if !vec.is_empty() => {
911                let c = &vec[0];
912                Ok(Data::Vector3(Vector3(nalgebra::Vector3::new(
913                    c[0], c[1], c[2],
914                ))))
915            }
916            #[cfg(feature = "vector3")]
917            (Data::String(String(s)), DataType::Vector3) => {
918                parse_to_array::<f32, 3>(s).map(|v| Data::Vector3(Vector3(v.into())))
919            }
920
921            // To Color conversions
922            (Data::Real(Real(f)), DataType::Color) => {
923                let f = *f as f32;
924                Ok(Data::Color(Color([f, f, f, 1.0])))
925            }
926            (Data::RealVec(RealVec(vec)), DataType::Color) if vec.len() >= 3 => {
927                let mut color = [0.0f32; 4];
928                vec.iter()
929                    .take(4)
930                    .enumerate()
931                    .for_each(|(i, &v)| color[i] = v as f32);
932                if vec.len() < 4 {
933                    color[3] = 1.0;
934                }
935                Ok(Data::Color(Color(color)))
936            }
937            (Data::IntegerVec(IntegerVec(vec)), DataType::Color) if vec.len() >= 3 => {
938                let mut color = [0.0f32; 4];
939                vec.iter()
940                    .take(4)
941                    .enumerate()
942                    .for_each(|(i, &v)| color[i] = v as f32);
943                if vec.len() < 4 {
944                    color[3] = 1.0;
945                }
946                Ok(Data::Color(Color(color)))
947            }
948            #[cfg(feature = "vector3")]
949            (Data::Vector3(Vector3(v)), DataType::Color) => {
950                Ok(Data::Color(Color([v.x, v.y, v.z, 1.0])))
951            }
952            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
953            (Data::Vector3Vec(Vector3Vec(vec)), DataType::Color) if !vec.is_empty() => {
954                Ok(Data::Color(Color([vec[0].x, vec[0].y, vec[0].z, 1.0])))
955            }
956            #[cfg(feature = "vector2")]
957            (Data::Vector2(Vector2(v)), DataType::Color) => {
958                Ok(Data::Color(Color([v.x, v.y, 0.0, 1.0])))
959            }
960            #[cfg(feature = "point3")]
961            (Data::Point3(Point3(p)), DataType::Color) => {
962                Ok(Data::Color(Color([p.x, p.y, p.z, 1.0])))
963            }
964            #[cfg(feature = "normal3")]
965            (Data::Normal3(Normal3(v)), DataType::Color) => {
966                Ok(Data::Color(Color([v.x, v.y, v.z, 1.0])))
967            }
968            (Data::String(String(s)), DataType::Color) => parse_color_from_string(s)
969                .map(|c| Data::Color(Color(c)))
970                .ok_or_else(|| anyhow!("Cannot parse '{}' as Color", s)),
971
972            // To Mat3 conversions
973            #[cfg(feature = "matrix3")]
974            (Data::Integer(Integer(i)), DataType::Matrix3) => {
975                let v = *i as f32;
976                Ok(Data::Matrix3(Matrix3(nalgebra::Matrix3::new(
977                    v, 0.0, 0.0, 0.0, v, 0.0, 0.0, 0.0, 1.0,
978                ))))
979            }
980            #[cfg(feature = "matrix3")]
981            (Data::Real(Real(f)), DataType::Matrix3) => {
982                let v = *f as f32;
983                Ok(Data::Matrix3(Matrix3(nalgebra::Matrix3::new(
984                    v, 0.0, 0.0, 0.0, v, 0.0, 0.0, 0.0, 1.0,
985                ))))
986            }
987            #[cfg(feature = "matrix3")]
988            (Data::RealVec(RealVec(vec)), DataType::Matrix3) if vec.len() >= 9 => {
989                // AIDEV-NOTE: Using iterator for efficient conversion.
990                let m: Vec<f32> = vec.iter().take(9).map(|&x| x as f32).collect();
991                Ok(Data::Matrix3(Matrix3(nalgebra::Matrix3::from_row_slice(
992                    &m,
993                ))))
994            }
995            #[cfg(feature = "matrix3")]
996            (Data::IntegerVec(IntegerVec(vec)), DataType::Matrix3) if vec.len() >= 9 => {
997                let m: Vec<f32> = vec.iter().take(9).map(|&x| x as f32).collect();
998                Ok(Data::Matrix3(Matrix3(nalgebra::Matrix3::from_row_slice(
999                    &m,
1000                ))))
1001            }
1002            #[cfg(all(feature = "vector3", feature = "matrix3"))]
1003            (Data::Vector3(Vector3(v)), DataType::Matrix3) => Ok(Data::Matrix3(Matrix3(
1004                nalgebra::Matrix3::new(v.x, 0.0, 0.0, 0.0, v.y, 0.0, 0.0, 0.0, v.z),
1005            ))),
1006            #[cfg(all(feature = "vector3", feature = "matrix3", feature = "vec_variants"))]
1007            (Data::Vector3Vec(Vector3Vec(vec)), DataType::Matrix3) if vec.len() >= 3 => {
1008                // Use 3 Vector3s as columns of the matrix.
1009                let cols: Vec<f32> = vec.iter().take(3).flat_map(|v| [v.x, v.y, v.z]).collect();
1010                Ok(Data::Matrix3(Matrix3(
1011                    nalgebra::Matrix3::from_column_slice(&cols),
1012                )))
1013            }
1014            #[cfg(feature = "matrix3")]
1015            (Data::ColorVec(ColorVec(vec)), DataType::Matrix3) if vec.len() >= 3 => {
1016                // Use RGB components of 3 colors as rows.
1017                let rows: Vec<f32> = vec
1018                    .iter()
1019                    .take(3)
1020                    .flat_map(|c| c[0..3].iter().copied())
1021                    .collect();
1022                Ok(Data::Matrix3(Matrix3(nalgebra::Matrix3::from_row_slice(
1023                    &rows,
1024                ))))
1025            }
1026            #[cfg(feature = "matrix3")]
1027            (Data::String(String(s)), DataType::Matrix3) => {
1028                // Try to parse as a single value first for diagonal matrix
1029                if let Ok(single_val) = s.trim().parse::<f32>() {
1030                    Ok(Data::Matrix3(Matrix3(
1031                        nalgebra::Matrix3::from_diagonal_element(single_val),
1032                    )))
1033                } else {
1034                    // Parse as 9 separate values
1035                    parse_to_array::<f32, 9>(s)
1036                        .map(|m| Data::Matrix3(Matrix3(nalgebra::Matrix3::from_row_slice(&m))))
1037                }
1038            }
1039
1040            // To Normal3 conversions
1041            #[cfg(feature = "normal3")]
1042            (Data::Integer(Integer(i)), DataType::Normal3) => {
1043                let v = *i as f32;
1044                Ok(Data::Normal3(Normal3(nalgebra::Vector3::new(v, v, v))))
1045            }
1046            #[cfg(feature = "normal3")]
1047            (Data::Real(Real(f)), DataType::Normal3) => {
1048                let v = *f as f32;
1049                Ok(Data::Normal3(Normal3(nalgebra::Vector3::new(v, v, v))))
1050            }
1051            #[cfg(all(feature = "vector3", feature = "normal3"))]
1052            (Data::Vector3(Vector3(v)), DataType::Normal3) => {
1053                Ok(Data::Normal3(Normal3(v.normalize())))
1054            }
1055            #[cfg(feature = "normal3")]
1056            (Data::String(String(s)), DataType::Normal3) => parse_to_array::<f32, 3>(s)
1057                .map(|v| Data::Normal3(Normal3(nalgebra::Vector3::from(v).normalize()))),
1058
1059            // To Point3 conversions
1060            #[cfg(feature = "point3")]
1061            (Data::Integer(Integer(i)), DataType::Point3) => {
1062                let v = *i as f32;
1063                Ok(Data::Point3(Point3(nalgebra::Point3::new(v, v, v))))
1064            }
1065            #[cfg(feature = "point3")]
1066            (Data::Real(Real(f)), DataType::Point3) => {
1067                let v = *f as f32;
1068                Ok(Data::Point3(Point3(nalgebra::Point3::new(v, v, v))))
1069            }
1070            #[cfg(all(feature = "vector3", feature = "point3"))]
1071            (Data::Vector3(Vector3(v)), DataType::Point3) => {
1072                Ok(Data::Point3(Point3(nalgebra::Point3::new(v.x, v.y, v.z))))
1073            }
1074            #[cfg(feature = "point3")]
1075            (Data::String(String(s)), DataType::Point3) => {
1076                parse_to_array::<f32, 3>(s).map(|v| Data::Point3(Point3(nalgebra::Point3::from(v))))
1077            }
1078
1079            // To Matrix4 conversions
1080            #[cfg(feature = "matrix4")]
1081            (Data::Integer(Integer(i)), DataType::Matrix4) => {
1082                let v = *i as f64;
1083                Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::new(
1084                    v, 0.0, 0.0, 0.0, 0.0, v, 0.0, 0.0, 0.0, 0.0, v, 0.0, 0.0, 0.0, 0.0, 1.0,
1085                ))))
1086            }
1087            #[cfg(feature = "matrix4")]
1088            (Data::Real(Real(f)), DataType::Matrix4) => {
1089                let v = *f;
1090                Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::new(
1091                    v, 0.0, 0.0, 0.0, 0.0, v, 0.0, 0.0, 0.0, 0.0, v, 0.0, 0.0, 0.0, 0.0, 1.0,
1092                ))))
1093            }
1094            #[cfg(feature = "matrix4")]
1095            (Data::RealVec(RealVec(vec)), DataType::Matrix4) if vec.len() >= 16 => {
1096                // AIDEV-NOTE: Direct copy when types match, using bytemuck for exact size.
1097                if vec.len() == 16 {
1098                    let arr: &[f64; 16] = vec
1099                        .as_slice()
1100                        .try_into()
1101                        .map_err(|_| anyhow!("Failed to convert slice to array"))?;
1102                    Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::from_row_slice(
1103                        arr,
1104                    ))))
1105                } else {
1106                    let m: Vec<f64> = vec.iter().take(16).copied().collect();
1107                    Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::from_row_slice(
1108                        &m,
1109                    ))))
1110                }
1111            }
1112            #[cfg(feature = "matrix4")]
1113            (Data::IntegerVec(IntegerVec(vec)), DataType::Matrix4) if vec.len() >= 16 => {
1114                let m: Vec<f64> = vec.iter().take(16).map(|&x| x as f64).collect();
1115                Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::from_row_slice(
1116                    &m,
1117                ))))
1118            }
1119            #[cfg(all(feature = "matrix3", feature = "matrix4"))]
1120            (Data::Matrix3(Matrix3(m)), DataType::Matrix4) => {
1121                Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::new(
1122                    m.m11 as f64,
1123                    m.m12 as f64,
1124                    m.m13 as f64,
1125                    0.0,
1126                    m.m21 as f64,
1127                    m.m22 as f64,
1128                    m.m23 as f64,
1129                    0.0,
1130                    m.m31 as f64,
1131                    m.m32 as f64,
1132                    m.m33 as f64,
1133                    0.0,
1134                    0.0,
1135                    0.0,
1136                    0.0,
1137                    1.0,
1138                ))))
1139            }
1140            #[cfg(all(feature = "matrix3", feature = "matrix4", feature = "vec_variants"))]
1141            (Data::Matrix3Vec(Matrix3Vec(vec)), DataType::Matrix4) if !vec.is_empty() => {
1142                let m = &vec[0];
1143                Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::new(
1144                    m.m11 as f64,
1145                    m.m12 as f64,
1146                    m.m13 as f64,
1147                    0.0,
1148                    m.m21 as f64,
1149                    m.m22 as f64,
1150                    m.m23 as f64,
1151                    0.0,
1152                    m.m31 as f64,
1153                    m.m32 as f64,
1154                    m.m33 as f64,
1155                    0.0,
1156                    0.0,
1157                    0.0,
1158                    0.0,
1159                    1.0,
1160                ))))
1161            }
1162            #[cfg(feature = "matrix4")]
1163            (Data::ColorVec(ColorVec(vec)), DataType::Matrix4) if vec.len() >= 4 => {
1164                // Use RGBA components of 4 colors as rows.
1165                let rows: Vec<f64> = vec
1166                    .iter()
1167                    .take(4)
1168                    .flat_map(|c| c.iter().map(|&x| x as f64))
1169                    .collect();
1170                Ok(Data::Matrix4(Matrix4(nalgebra::Matrix4::from_row_slice(
1171                    &rows,
1172                ))))
1173            }
1174            #[cfg(feature = "matrix4")]
1175            (Data::String(String(s)), DataType::Matrix4) => {
1176                // Try to parse as a single value first for diagonal matrix
1177                if let Ok(single_val) = s.trim().parse::<f64>() {
1178                    Ok(Data::Matrix4(Matrix4(
1179                        nalgebra::Matrix4::from_diagonal_element(single_val),
1180                    )))
1181                } else {
1182                    // Parse as 16 separate values
1183                    parse_to_array::<f64, 16>(s)
1184                        .map(|m| Data::Matrix4(Matrix4(nalgebra::Matrix4::from_row_slice(&m))))
1185                }
1186            }
1187
1188            // Vec conversions from scalars and other types
1189            // To RealVec conversions
1190            (Data::Integer(Integer(i)), DataType::RealVec) => {
1191                Ok(Data::RealVec(RealVec(vec![*i as f64])))
1192            }
1193            (Data::Real(Real(f)), DataType::RealVec) => Ok(Data::RealVec(RealVec(vec![*f]))),
1194            #[cfg(feature = "vector2")]
1195            (Data::Vector2(Vector2(v)), DataType::RealVec) => Ok(Data::RealVec(RealVec(
1196                v.iter().map(|&x| x as f64).collect(),
1197            ))),
1198            #[cfg(feature = "vector3")]
1199            (Data::Vector3(Vector3(v)), DataType::RealVec) => Ok(Data::RealVec(RealVec(
1200                v.iter().map(|&x| x as f64).collect(),
1201            ))),
1202            (Data::Color(Color(c)), DataType::RealVec) => Ok(Data::RealVec(RealVec(
1203                c.iter().map(|&x| x as f64).collect(),
1204            ))),
1205            #[cfg(feature = "matrix3")]
1206            (Data::Matrix3(Matrix3(m)), DataType::RealVec) => Ok(Data::RealVec(RealVec(
1207                m.iter().map(|&x| x as f64).collect(),
1208            ))),
1209            #[cfg(feature = "matrix4")]
1210            (Data::Matrix4(Matrix4(m)), DataType::RealVec) => {
1211                Ok(Data::RealVec(RealVec(m.iter().copied().collect())))
1212            }
1213            #[cfg(feature = "normal3")]
1214            (Data::Normal3(Normal3(v)), DataType::RealVec) => Ok(Data::RealVec(RealVec(
1215                v.iter().map(|&x| x as f64).collect(),
1216            ))),
1217            #[cfg(feature = "point3")]
1218            (Data::Point3(Point3(p)), DataType::RealVec) => Ok(Data::RealVec(RealVec(vec![
1219                p.x as f64, p.y as f64, p.z as f64,
1220            ]))),
1221
1222            // To IntegerVec conversions
1223            (Data::Boolean(Boolean(b)), DataType::IntegerVec) => {
1224                Ok(Data::IntegerVec(IntegerVec(vec![if *b { 1 } else { 0 }])))
1225            }
1226            (Data::Integer(Integer(i)), DataType::IntegerVec) => {
1227                Ok(Data::IntegerVec(IntegerVec(vec![*i])))
1228            }
1229            (Data::Real(Real(f)), DataType::IntegerVec) => {
1230                Ok(Data::IntegerVec(IntegerVec(vec![*f as i64])))
1231            }
1232            #[cfg(feature = "vector2")]
1233            (Data::Vector2(Vector2(v)), DataType::IntegerVec) => Ok(Data::IntegerVec(IntegerVec(
1234                v.iter().map(|&x| x as i64).collect(),
1235            ))),
1236            #[cfg(feature = "vector3")]
1237            (Data::Vector3(Vector3(v)), DataType::IntegerVec) => Ok(Data::IntegerVec(IntegerVec(
1238                v.iter().map(|&x| x as i64).collect(),
1239            ))),
1240            (Data::Color(Color(c)), DataType::IntegerVec) => Ok(Data::IntegerVec(IntegerVec(
1241                c.iter().map(|&x| (x * 255.0) as i64).collect(),
1242            ))),
1243            #[cfg(feature = "matrix3")]
1244            (Data::Matrix3(Matrix3(m)), DataType::IntegerVec) => Ok(Data::IntegerVec(IntegerVec(
1245                m.iter().map(|&x| x as i64).collect(),
1246            ))),
1247            #[cfg(feature = "matrix4")]
1248            (Data::Matrix4(Matrix4(m)), DataType::IntegerVec) => Ok(Data::IntegerVec(IntegerVec(
1249                m.iter().map(|&x| x as i64).collect(),
1250            ))),
1251
1252            // To ColorVec conversions
1253            (Data::Color(Color(c)), DataType::ColorVec) => Ok(Data::ColorVec(ColorVec(vec![*c]))),
1254            #[cfg(feature = "vector3")]
1255            (Data::Vector3(Vector3(v)), DataType::ColorVec) => {
1256                Ok(Data::ColorVec(ColorVec(vec![[v.x, v.y, v.z, 1.0]])))
1257            }
1258            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
1259            (Data::Vector3Vec(Vector3Vec(vec)), DataType::ColorVec) => {
1260                let colors = vec.iter().map(|v| [v.x, v.y, v.z, 1.0]).collect();
1261                Ok(Data::ColorVec(ColorVec(colors)))
1262            }
1263            #[cfg(feature = "matrix3")]
1264            (Data::Matrix3(Matrix3(m)), DataType::ColorVec) => {
1265                // Convert each row to a color
1266                let colors = (0..3)
1267                    .map(|i| {
1268                        let row = m.row(i);
1269                        [row[0], row[1], row[2], 1.0]
1270                    })
1271                    .collect();
1272                Ok(Data::ColorVec(ColorVec(colors)))
1273            }
1274
1275            // To Vector2Vec conversions
1276            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
1277            (Data::Vector2(Vector2(v)), DataType::Vector2Vec) => {
1278                Ok(Data::Vector2Vec(Vector2Vec(vec![*v])))
1279            }
1280            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
1281            (Data::RealVec(RealVec(vec)), DataType::Vector2Vec)
1282                if vec.len() >= 2 && vec.len() % 2 == 0 =>
1283            {
1284                let vectors = vec
1285                    .chunks_exact(2)
1286                    .map(|chunk| nalgebra::Vector2::new(chunk[0] as f32, chunk[1] as f32))
1287                    .collect();
1288                Ok(Data::Vector2Vec(Vector2Vec(vectors)))
1289            }
1290
1291            // To Vector3Vec conversions
1292            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
1293            (Data::Vector3(Vector3(v)), DataType::Vector3Vec) => {
1294                Ok(Data::Vector3Vec(Vector3Vec(vec![*v])))
1295            }
1296            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
1297            (Data::RealVec(RealVec(vec)), DataType::Vector3Vec)
1298                if vec.len() >= 3 && vec.len() % 3 == 0 =>
1299            {
1300                let vectors = vec
1301                    .chunks_exact(3)
1302                    .map(|chunk| {
1303                        nalgebra::Vector3::new(chunk[0] as f32, chunk[1] as f32, chunk[2] as f32)
1304                    })
1305                    .collect();
1306                Ok(Data::Vector3Vec(Vector3Vec(vectors)))
1307            }
1308            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
1309            (Data::IntegerVec(IntegerVec(vec)), DataType::Vector3Vec)
1310                if vec.len() >= 3 && vec.len() % 3 == 0 =>
1311            {
1312                let vectors = vec
1313                    .chunks_exact(3)
1314                    .map(|chunk| {
1315                        nalgebra::Vector3::new(chunk[0] as f32, chunk[1] as f32, chunk[2] as f32)
1316                    })
1317                    .collect();
1318                Ok(Data::Vector3Vec(Vector3Vec(vectors)))
1319            }
1320            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
1321            (Data::ColorVec(ColorVec(vec)), DataType::Vector3Vec) => {
1322                let vectors = vec
1323                    .iter()
1324                    .map(|c| nalgebra::Vector3::new(c[0], c[1], c[2]))
1325                    .collect();
1326                Ok(Data::Vector3Vec(Vector3Vec(vectors)))
1327            }
1328
1329            // To Matrix3Vec conversions
1330            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1331            (Data::Matrix3(Matrix3(m)), DataType::Matrix3Vec) => {
1332                Ok(Data::Matrix3Vec(Matrix3Vec(vec![*m])))
1333            }
1334            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1335            (Data::RealVec(RealVec(vec)), DataType::Matrix3Vec)
1336                if vec.len() >= 9 && vec.len() % 9 == 0 =>
1337            {
1338                let matrices = vec
1339                    .chunks_exact(9)
1340                    .map(|chunk| {
1341                        let m: Vec<f32> = chunk.iter().map(|&x| x as f32).collect();
1342                        nalgebra::Matrix3::from_row_slice(&m)
1343                    })
1344                    .collect();
1345                Ok(Data::Matrix3Vec(Matrix3Vec(matrices)))
1346            }
1347
1348            // To Matrix4Vec conversions
1349            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1350            (Data::Matrix4(Matrix4(m)), DataType::Matrix4Vec) => {
1351                Ok(Data::Matrix4Vec(Matrix4Vec(vec![*m])))
1352            }
1353            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1354            (Data::RealVec(RealVec(vec)), DataType::Matrix4Vec)
1355                if vec.len() >= 16 && vec.len() % 16 == 0 =>
1356            {
1357                let matrices = vec
1358                    .chunks_exact(16)
1359                    .map(nalgebra::Matrix4::from_row_slice)
1360                    .collect();
1361                Ok(Data::Matrix4Vec(Matrix4Vec(matrices)))
1362            }
1363
1364            // Vec to Vec conversions
1365            #[cfg(feature = "vec_variants")]
1366            (Data::RealVec(RealVec(vec)), DataType::IntegerVec) => {
1367                // AIDEV-NOTE: Converting RealVec to IntegerVec by rounding each element.
1368                Ok(Data::IntegerVec(IntegerVec(
1369                    vec.iter().map(|&f| f.round() as i64).collect(),
1370                )))
1371            }
1372            #[cfg(feature = "vec_variants")]
1373            (Data::IntegerVec(IntegerVec(vec)), DataType::RealVec) => {
1374                // AIDEV-NOTE: Converting IntegerVec to RealVec by casting each element.
1375                Ok(Data::RealVec(RealVec(
1376                    vec.iter().map(|&i| i as f64).collect(),
1377                )))
1378            }
1379            #[cfg(feature = "vec_variants")]
1380            (Data::BooleanVec(BooleanVec(vec)), DataType::IntegerVec) => {
1381                // AIDEV-NOTE: Converting BooleanVec to IntegerVec (true -> 1, false -> 0).
1382                Ok(Data::IntegerVec(IntegerVec(
1383                    vec.iter().map(|&b| if b { 1 } else { 0 }).collect(),
1384                )))
1385            }
1386            #[cfg(feature = "vec_variants")]
1387            (Data::IntegerVec(IntegerVec(vec)), DataType::BooleanVec) => {
1388                // AIDEV-NOTE: Converting IntegerVec to BooleanVec (0 -> false, non-0 -> true).
1389                Ok(Data::BooleanVec(BooleanVec(
1390                    vec.iter().map(|&i| i != 0).collect(),
1391                )))
1392            }
1393            #[cfg(feature = "vec_variants")]
1394            (Data::BooleanVec(BooleanVec(vec)), DataType::RealVec) => {
1395                // AIDEV-NOTE: Converting BooleanVec to RealVec (true -> 1.0, false -> 0.0).
1396                Ok(Data::RealVec(RealVec(
1397                    vec.iter().map(|&b| if b { 1.0 } else { 0.0 }).collect(),
1398                )))
1399            }
1400            #[cfg(feature = "vec_variants")]
1401            (Data::RealVec(RealVec(vec)), DataType::BooleanVec) => {
1402                // AIDEV-NOTE: Converting RealVec to BooleanVec (0.0 -> false, non-0.0 -> true).
1403                Ok(Data::BooleanVec(BooleanVec(
1404                    vec.iter().map(|&f| f != 0.0).collect(),
1405                )))
1406            }
1407
1408            // Unsupported conversions
1409            _ => Err(anyhow!("Cannot convert {:?} to {:?}", self.data_type(), to)),
1410        }
1411    }
1412}
1413
1414fn parse_color_from_string(s: &str) -> Option<[f32; 4]> {
1415    let s = s.trim();
1416
1417    // Try hex format first (#RRGGBB or #RRGGBBAA)
1418    if s.starts_with('#') {
1419        let hex = s.trim_start_matches('#');
1420        if (hex.len() == 6 || hex.len() == 8)
1421            && let Ok(val) = u32::from_str_radix(hex, 16)
1422        {
1423            let r = ((val >> 16) & 0xFF) as f32 / 255.0;
1424            let g = ((val >> 8) & 0xFF) as f32 / 255.0;
1425            let b = (val & 0xFF) as f32 / 255.0;
1426            let a = if hex.len() == 8 {
1427                ((val >> 24) & 0xFF) as f32 / 255.0
1428            } else {
1429                1.0
1430            };
1431            Some([r, g, b, a])
1432        } else {
1433            None
1434        }
1435    } else {
1436        // Try array format
1437        let s = s.trim_start_matches('[').trim_end_matches(']');
1438        let parts: Vec<&str> = s
1439            .split([',', ' '])
1440            .map(|p| p.trim())
1441            .filter(|p| !p.is_empty())
1442            .collect();
1443
1444        match parts.len() {
1445            4 => {
1446                if let (Ok(r), Ok(g), Ok(b), Ok(a)) = (
1447                    parts[0].parse::<f32>(),
1448                    parts[1].parse::<f32>(),
1449                    parts[2].parse::<f32>(),
1450                    parts[3].parse::<f32>(),
1451                ) {
1452                    Some([r, g, b, a])
1453                } else {
1454                    None
1455                }
1456            }
1457            3 => {
1458                if let (Ok(r), Ok(g), Ok(b)) = (
1459                    parts[0].parse::<f32>(),
1460                    parts[1].parse::<f32>(),
1461                    parts[2].parse::<f32>(),
1462                ) {
1463                    Some([r, g, b, 1.0])
1464                } else {
1465                    None
1466                }
1467            }
1468            1 => {
1469                // Single value - grayscale
1470                if let Ok(v) = parts[0].parse::<f32>() {
1471                    Some([v, v, v, 1.0])
1472                } else {
1473                    None
1474                }
1475            }
1476            _ => None,
1477        }
1478    }
1479}
1480
1481/// Parse a string into an array of `N` elements.
1482///
1483/// Missing elements are filled with `T::default()`.
1484///
1485/// Returns an error if the string can't be parsed to an array of N elements.
1486fn parse_to_array<T, const N: usize>(input: &str) -> Result<[T; N]>
1487where
1488    T: FromStr + Default + Debug,
1489    <T as FromStr>::Err: Display,
1490{
1491    // Strip brackets first
1492    let cleaned_input = input.trim().trim_start_matches('[').trim_end_matches(']');
1493
1494    let mut result = cleaned_input
1495        .split(&[',', ' '][..])
1496        .map(|s| s.trim())
1497        .filter(|&s| !s.is_empty())
1498        .take(N)
1499        .map(|s| {
1500            s.parse::<T>().map_err(|e| {
1501                anyhow!(
1502                    "Can't parse string `{s}` in `{input}` to `{}`: {e}",
1503                    std::any::type_name::<T>()
1504                )
1505            })
1506        })
1507        .collect::<Result<SmallVec<[T; N]>, _>>()?;
1508
1509    if result.len() < N {
1510        result.extend((0..N - result.len()).map(|_| T::default()));
1511    }
1512
1513    // This cannot Err
1514    Ok(result.into_inner().unwrap())
1515}
1516
1517// Arithmetic operations for Data enum - generated by macros
1518impl_data_arithmetic!(binary Add, add, "add");
1519impl_data_arithmetic!(binary Sub, sub, "subtract");
1520impl_data_arithmetic!(scalar f32);
1521impl_data_arithmetic!(scalar f64);
1522impl_data_arithmetic!(div f32);
1523impl_data_arithmetic!(div f64);
1524
1525// Manual Eq implementation for Data
1526// This is safe because we handle floating point comparison deterministically
1527impl Eq for Data {}