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