Skip to main content

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