Skip to main content

token_value_map/
data_types.rs

1use crate::math::*;
2use crate::{DataTypeOps, Error, Result, *};
3use std::{
4    fmt::Debug,
5    hash::{Hash, Hasher},
6    ops::{Add, Div, Mul, Sub},
7};
8
9// Macro to implement DataTypeOps for each variant
10macro_rules! impl_data_ops {
11    ($type:ty, $name:expr, $data_type:expr) => {
12        impl DataTypeOps for $type {
13            fn type_name(&self) -> &'static str {
14                $name
15            }
16
17            fn data_type(&self) -> DataType {
18                $data_type
19            }
20        }
21    };
22}
23
24// AIDEV-NOTE: Macro to reduce duplication for nalgebra-based types.
25// Implements Add, Sub, Mul<f32>, and Mul<f64> for wrapper types.
26macro_rules! impl_nalgebra_arithmetic {
27    // For f32-based types
28    ($type:ty) => {
29        impl Add for $type {
30            type Output = $type;
31
32            fn add(self, other: $type) -> $type {
33                Self(self.0 + other.0)
34            }
35        }
36
37        impl Sub for $type {
38            type Output = $type;
39
40            fn sub(self, other: $type) -> $type {
41                Self(self.0 - other.0)
42            }
43        }
44
45        impl Mul<f32> for $type {
46            type Output = $type;
47
48            fn mul(self, scalar: f32) -> $type {
49                Self(self.0 * scalar)
50            }
51        }
52
53        impl Mul<f64> for $type {
54            type Output = $type;
55
56            fn mul(self, scalar: f64) -> $type {
57                Self(self.0 * scalar as f32)
58            }
59        }
60    };
61
62    // For f64-based types
63    ($type:ty, f64) => {
64        impl Add for $type {
65            type Output = $type;
66
67            fn add(self, other: $type) -> $type {
68                Self(self.0 + other.0)
69            }
70        }
71
72        impl Sub for $type {
73            type Output = $type;
74
75            fn sub(self, other: $type) -> $type {
76                Self(self.0 - other.0)
77            }
78        }
79
80        impl Mul<f32> for $type {
81            type Output = $type;
82
83            fn mul(self, scalar: f32) -> $type {
84                Self(self.0 * scalar as f64)
85            }
86        }
87
88        impl Mul<f64> for $type {
89            type Output = $type;
90
91            fn mul(self, scalar: f64) -> $type {
92                Self(self.0 * scalar)
93            }
94        }
95    };
96}
97
98/// A boolean value wrapper.
99#[derive(Clone, Debug, PartialEq, Eq, Hash)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[cfg_attr(feature = "facet", derive(Facet))]
102#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
103pub struct Boolean(pub bool);
104
105impl From<Data> for Boolean {
106    fn from(data: Data) -> Self {
107        match data {
108            Data::Boolean(b) => b,
109            Data::Real(r) => Boolean(r.0 != 0.0),
110            Data::Integer(i) => Boolean(i.0 != 0),
111            Data::String(s) => Boolean(s.0.parse::<bool>().unwrap_or(false)),
112            _ => panic!("Cannot convert {data:?} to Boolean"),
113        }
114    }
115}
116
117/// A 64-bit signed integer wrapper.
118#[derive(Clone, Debug, PartialEq, Eq, Hash)]
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
120#[cfg_attr(feature = "facet", derive(Facet))]
121#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
122pub struct Integer(pub i64);
123
124impl From<Data> for Integer {
125    fn from(data: Data) -> Self {
126        match data {
127            Data::Boolean(b) => Integer(if b.0 { 1 } else { 0 }),
128            Data::Real(r) => Integer(r.0 as i64),
129            Data::Integer(i) => i,
130            Data::String(s) => Integer(s.0.parse::<i64>().unwrap_or(0)),
131            _ => panic!("Cannot convert {data:?} to Integer"),
132        }
133    }
134}
135
136/// A 64-bit floating-point number wrapper.
137#[derive(Clone, Debug, PartialEq)]
138#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
139#[cfg_attr(feature = "facet", derive(Facet))]
140#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
141pub struct Real(pub f64);
142
143impl Eq for Real {}
144
145impl From<Data> for Real {
146    fn from(data: Data) -> Self {
147        match data {
148            Data::Boolean(b) => Real(if b.0 { 1.0 } else { 0.0 }),
149            Data::Real(r) => r,
150            Data::Integer(i) => Real(i.0 as f64),
151            Data::String(s) => Real(s.0.parse::<f64>().unwrap_or(0.0)),
152            _ => panic!("Cannot convert {data:?} to Real"),
153        }
154    }
155}
156
157impl From<f64> for Real {
158    fn from(value: f64) -> Self {
159        Real(value)
160    }
161}
162
163impl From<f32> for Real {
164    fn from(value: f32) -> Self {
165        Real(value as f64)
166    }
167}
168
169/// A UTF-8 string wrapper.
170#[derive(Clone, Debug, PartialEq, Eq, Hash)]
171#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
172#[cfg_attr(feature = "facet", derive(Facet))]
173#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
174pub struct String(pub std::string::String);
175
176impl From<Data> for String {
177    fn from(data: Data) -> Self {
178        match data {
179            Data::Boolean(b) => String(b.0.to_string()),
180            Data::Real(r) => String(r.0.to_string()),
181            Data::Integer(i) => String(i.0.to_string()),
182            Data::String(s) => s,
183            Data::Color(c) => String(format!("{c:?}")),
184            #[cfg(feature = "vector2")]
185            Data::Vector2(v) => String(format!("{v:?}")),
186            #[cfg(feature = "vector3")]
187            Data::Vector3(v) => String(format!("{v:?}")),
188            #[cfg(feature = "matrix3")]
189            Data::Matrix3(m) => String(format!("{m:?}")),
190            #[cfg(feature = "normal3")]
191            Data::Normal3(n) => String(format!("{n:?}")),
192            #[cfg(feature = "point3")]
193            Data::Point3(p) => String(format!("{p:?}")),
194            #[cfg(feature = "matrix4")]
195            Data::Matrix4(m) => String(format!("{m:?}")),
196            Data::BooleanVec(v) => String(format!("{v:?}")),
197            Data::RealVec(v) => String(format!("{v:?}")),
198            Data::IntegerVec(v) => String(format!("{v:?}")),
199            Data::StringVec(v) => String(format!("{v:?}")),
200            Data::ColorVec(v) => String(format!("{v:?}")),
201            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
202            Data::Vector2Vec(v) => String(format!("{v:?}")),
203            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
204            Data::Vector3Vec(v) => String(format!("{v:?}")),
205            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
206            Data::Matrix3Vec(v) => String(format!("{v:?}")),
207            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
208            Data::Normal3Vec(v) => String(format!("{v:?}")),
209            #[cfg(all(feature = "point3", feature = "vec_variants"))]
210            Data::Point3Vec(v) => String(format!("{v:?}")),
211            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
212            Data::Matrix4Vec(v) => String(format!("{v:?}")),
213            #[cfg(feature = "curves")]
214            Data::RealCurve(c) => String(format!("{c:?}")),
215            #[cfg(feature = "curves")]
216            Data::ColorCurve(c) => String(format!("{c:?}")),
217        }
218    }
219}
220
221/// A 4-component RGBA color value.
222///
223/// AIDEV-NOTE: Color uses `[f32; 4]` directly -- it's a domain concept (RGBA),
224/// not a math-library type. Both glam and nalgebra lack a canonical "Color".
225#[derive(Clone, Copy, Debug, PartialEq)]
226#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
227#[cfg_attr(feature = "facet", derive(Facet))]
228#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
229#[repr(transparent)]
230pub struct Color(pub [f32; 4]);
231
232impl Eq for Color {}
233
234impl From<[f32; 4]> for Color {
235    #[inline(always)]
236    fn from(array: [f32; 4]) -> Self {
237        Color(array)
238    }
239}
240
241impl From<Color> for [f32; 4] {
242    #[inline(always)]
243    fn from(color: Color) -> Self {
244        color.0
245    }
246}
247
248impl Color {
249    /// Create a new color from RGBA components.
250    #[inline(always)]
251    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
252        Color([r, g, b, a])
253    }
254
255    /// Get RGBA components as array.
256    #[inline(always)]
257    pub fn to_array(&self) -> [f32; 4] {
258        self.0
259    }
260}
261
262impl From<Data> for Color {
263    fn from(data: Data) -> Self {
264        match data {
265            Data::Boolean(b) => Color::from([b.0.into(), b.0.into(), b.0.into(), 1.0]),
266            Data::Real(r) => Color::from([r.0 as _, r.0 as _, r.0 as _, 1.0]),
267            Data::Integer(i) => Color::from([i.0 as _, i.0 as _, i.0 as _, 1.0]),
268            Data::String(s) => Color::from([s.0.parse::<f32>().unwrap_or(0.0); 4]),
269            Data::Color(c) => c,
270            #[cfg(feature = "vector2")]
271            Data::Vector2(v) => Color::from([v.0.x, v.0.y, 0.0, 1.0]),
272            #[cfg(feature = "vector3")]
273            Data::Vector3(v) => Color::from([v.0.x, v.0.y, v.0.z, 1.0]),
274            Data::BooleanVec(v) => Color::from([v.0[0].into(), v.0[1].into(), v.0[2].into(), 1.0]),
275            Data::RealVec(v) => Color::from([v.0[0] as _, v.0[1] as _, v.0[2] as _, 1.0]),
276            Data::IntegerVec(v) => Color::from([v.0[0] as _, v.0[1] as _, v.0[2] as _, 1.0]),
277            Data::StringVec(v) => Color::from([v.0[0].parse::<f32>().unwrap_or(0.0); 4]),
278            Data::ColorVec(v) => Color::from([v.0[0][0], v.0[0][1], v.0[0][2], v.0[0][3]]),
279            _ => panic!("Cannot convert {data:?} to Color"),
280        }
281    }
282}
283
284/// A 2D vector.
285#[cfg(feature = "vector2")]
286#[derive(Clone, Debug, PartialEq)]
287#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
288#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
289pub struct Vector2(pub Vec2Impl);
290
291#[cfg(feature = "vector2")]
292impl Eq for Vector2 {}
293
294/// A 3D vector.
295#[cfg(feature = "vector3")]
296#[derive(Clone, Debug, PartialEq)]
297#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
298#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
299pub struct Vector3(pub Vec3Impl);
300
301#[cfg(feature = "vector3")]
302impl Eq for Vector3 {}
303
304/// A 3×3 transformation matrix.
305#[cfg(feature = "matrix3")]
306#[derive(Clone, Debug, PartialEq)]
307#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
308#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
309pub struct Matrix3(pub Mat3Impl);
310
311#[cfg(feature = "matrix3")]
312impl Eq for Matrix3 {}
313
314#[cfg(feature = "matrix3")]
315impl From<Vec<f32>> for Matrix3 {
316    fn from(vec: Vec<f32>) -> Self {
317        assert_eq!(vec.len(), 9, "Matrix3 requires exactly 9 elements");
318        Matrix3(mat3_from_row_slice(&vec))
319    }
320}
321
322#[cfg(feature = "matrix3")]
323impl From<Vec<f64>> for Matrix3 {
324    fn from(vec: Vec<f64>) -> Self {
325        assert_eq!(vec.len(), 9, "Matrix3 requires exactly 9 elements");
326        let vec_f32: Vec<f32> = vec.into_iter().map(|v| v as f32).collect();
327        Matrix3(mat3_from_row_slice(&vec_f32))
328    }
329}
330
331#[cfg(feature = "matrix3")]
332impl From<[f32; 9]> for Matrix3 {
333    fn from(arr: [f32; 9]) -> Self {
334        Matrix3(mat3_from_row_slice(&arr))
335    }
336}
337
338/// A 3D normal vector.
339///
340/// AIDEV-NOTE: Inner type is `Vec3Impl` for both backends. Normalization
341/// is the caller's responsibility -- typically done at construction time.
342#[cfg(feature = "normal3")]
343#[derive(Clone, Debug, PartialEq)]
344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
345#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
346#[repr(transparent)]
347pub struct Normal3(pub Vec3Impl);
348
349#[cfg(feature = "normal3")]
350impl Eq for Normal3 {}
351
352/// A 3D point.
353#[cfg(feature = "point3")]
354#[derive(Clone, Debug, PartialEq)]
355#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
356#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
357pub struct Point3(pub Point3Impl);
358
359#[cfg(feature = "point3")]
360impl Eq for Point3 {}
361
362/// A 4×4 transformation matrix.
363#[cfg(feature = "matrix4")]
364#[derive(Clone, Debug, PartialEq)]
365#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
366#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
367pub struct Matrix4(pub Mat4Impl);
368
369#[cfg(feature = "matrix4")]
370impl Eq for Matrix4 {}
371
372/// A vector of integer values.
373#[derive(Clone, Debug, PartialEq, Eq, Hash)]
374#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
375#[cfg_attr(feature = "facet", derive(Facet))]
376#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
377pub struct IntegerVec(pub Vec<i64>);
378
379impl IntegerVec {
380    pub fn new(vec: Vec<i64>) -> Result<Self> {
381        if vec.is_empty() {
382            return Err(Error::EmptyVec {
383                type_name: "IntegerVec",
384            });
385        }
386        Ok(IntegerVec(vec))
387    }
388}
389
390impl From<Vec<i64>> for IntegerVec {
391    fn from(vec: Vec<i64>) -> Self {
392        IntegerVec(vec)
393    }
394}
395
396impl From<Vec<i32>> for IntegerVec {
397    fn from(vec: Vec<i32>) -> Self {
398        IntegerVec(vec.into_iter().map(|v| v as i64).collect())
399    }
400}
401
402/// A vector of real values.
403#[derive(Clone, Debug, PartialEq)]
404#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
405#[cfg_attr(feature = "facet", derive(Facet))]
406#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
407pub struct RealVec(pub Vec<f64>);
408
409impl RealVec {
410    pub fn new(vec: Vec<f64>) -> Result<Self> {
411        if vec.is_empty() {
412            return Err(Error::EmptyVec {
413                type_name: "RealVec",
414            });
415        }
416        Ok(RealVec(vec))
417    }
418}
419
420impl From<Vec<f64>> for RealVec {
421    fn from(vec: Vec<f64>) -> Self {
422        RealVec(vec)
423    }
424}
425
426impl From<Vec<f32>> for RealVec {
427    fn from(vec: Vec<f32>) -> Self {
428        RealVec(vec.into_iter().map(|v| v as f64).collect())
429    }
430}
431
432impl Eq for RealVec {}
433
434/// A vector of boolean values.
435#[derive(Clone, Debug, PartialEq, Eq, Hash)]
436#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
437#[cfg_attr(feature = "facet", derive(Facet))]
438#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
439pub struct BooleanVec(pub Vec<bool>);
440
441impl BooleanVec {
442    pub fn new(vec: Vec<bool>) -> Result<Self> {
443        if vec.is_empty() {
444            return Err(Error::EmptyVec {
445                type_name: "BooleanVec",
446            });
447        }
448        Ok(BooleanVec(vec))
449    }
450}
451
452/// A vector of string values.
453#[derive(Clone, Debug, PartialEq, Eq, Hash)]
454#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
455#[cfg_attr(feature = "facet", derive(Facet))]
456#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
457pub struct StringVec(pub Vec<std::string::String>);
458
459impl StringVec {
460    pub fn new(vec: Vec<std::string::String>) -> Result<Self> {
461        if vec.is_empty() {
462            return Err(Error::EmptyVec {
463                type_name: "StringVec",
464            });
465        }
466        Ok(StringVec(vec))
467    }
468}
469
470/// A vector of color values.
471#[derive(Clone, Debug, PartialEq)]
472#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
473#[cfg_attr(feature = "facet", derive(Facet))]
474#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
475pub struct ColorVec(pub Vec<[f32; 4]>);
476
477impl ColorVec {
478    pub fn new(vec: Vec<[f32; 4]>) -> Result<Self> {
479        if vec.is_empty() {
480            return Err(Error::EmptyVec {
481                type_name: "ColorVec",
482            });
483        }
484        Ok(ColorVec(vec))
485    }
486}
487
488impl Eq for ColorVec {}
489
490/// A real-valued curve mapping Position → Real.
491///
492/// Used for falloff curves and other 1D parameter mappings.
493#[cfg(feature = "curves")]
494#[derive(Clone, Debug, PartialEq, Hash)]
495#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
496#[cfg_attr(feature = "facet", derive(Facet))]
497#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
498pub struct RealCurve(pub KeyDataMap<Position, Real>);
499
500#[cfg(feature = "curves")]
501impl Eq for RealCurve {}
502
503#[cfg(feature = "curves")]
504impl RealCurve {
505    /// Create a linear ramp from 0 to 1.
506    pub fn linear() -> Self {
507        RealCurve(KeyDataMap::from(std::collections::BTreeMap::from([
508            (Position(0.0), Real(0.0)),
509            (Position(1.0), Real(1.0)),
510        ])))
511    }
512
513    /// Create a constant curve.
514    pub fn constant(v: f64) -> Self {
515        RealCurve(KeyDataMap::from(std::collections::BTreeMap::from([(
516            Position(0.0),
517            Real(v),
518        )])))
519    }
520
521    /// Evaluate the curve at a normalized position.
522    pub fn evaluate(&self, position: f32) -> f64 {
523        self.0.interpolate(Position(position)).0
524    }
525}
526
527/// A color-valued curve mapping Position → Color.
528///
529/// Used for multi-stop color gradients.
530#[cfg(feature = "curves")]
531#[derive(Clone, Debug, PartialEq, Hash)]
532#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
533#[cfg_attr(feature = "facet", derive(Facet))]
534#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
535pub struct ColorCurve(pub KeyDataMap<Position, Color>);
536
537#[cfg(feature = "curves")]
538impl Eq for ColorCurve {}
539
540#[cfg(feature = "curves")]
541impl ColorCurve {
542    /// Create a black-to-white gradient.
543    pub fn black_to_white() -> Self {
544        ColorCurve(KeyDataMap::from(std::collections::BTreeMap::from([
545            (Position(0.0), Color([0.0, 0.0, 0.0, 1.0])),
546            (Position(1.0), Color([1.0, 1.0, 1.0, 1.0])),
547        ])))
548    }
549
550    /// Evaluate the curve at a normalized position.
551    pub fn evaluate(&self, position: f32) -> [f32; 4] {
552        self.0.interpolate(Position(position)).0
553    }
554}
555
556/// A vector of 2D vectors.
557#[cfg(all(feature = "vector2", feature = "vec_variants"))]
558#[derive(Clone, Debug, PartialEq)]
559#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
560#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
561pub struct Vector2Vec(pub Vec<Vec2Impl>);
562
563#[cfg(all(feature = "vector2", feature = "vec_variants"))]
564impl Vector2Vec {
565    pub fn new(vec: Vec<Vec2Impl>) -> Result<Self> {
566        if vec.is_empty() {
567            return Err(Error::EmptyVec {
568                type_name: "Vector2Vec",
569            });
570        }
571        Ok(Vector2Vec(vec))
572    }
573}
574
575#[cfg(all(feature = "vector2", feature = "vec_variants"))]
576impl Eq for Vector2Vec {}
577
578/// A vector of 3D vectors.
579#[cfg(all(feature = "vector3", feature = "vec_variants"))]
580#[derive(Clone, Debug, PartialEq)]
581#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
582#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
583pub struct Vector3Vec(pub Vec<Vec3Impl>);
584
585#[cfg(all(feature = "vector3", feature = "vec_variants"))]
586impl Vector3Vec {
587    pub fn new(vec: Vec<Vec3Impl>) -> Result<Self> {
588        if vec.is_empty() {
589            return Err(Error::EmptyVec {
590                type_name: "Vector3Vec",
591            });
592        }
593        Ok(Vector3Vec(vec))
594    }
595}
596
597#[cfg(all(feature = "vector3", feature = "vec_variants"))]
598impl Eq for Vector3Vec {}
599
600/// A vector of transformation matrices.
601#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
602#[derive(Clone, Debug, PartialEq)]
603#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
604#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
605pub struct Matrix3Vec(pub Vec<Mat3Impl>);
606
607#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
608impl Matrix3Vec {
609    pub fn new(vec: Vec<Mat3Impl>) -> Result<Self> {
610        if vec.is_empty() {
611            return Err(Error::EmptyVec {
612                type_name: "Matrix3Vec",
613            });
614        }
615        Ok(Matrix3Vec(vec))
616    }
617}
618
619#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
620impl Eq for Matrix3Vec {}
621
622/// A vector of 3D normals.
623#[cfg(all(feature = "normal3", feature = "vec_variants"))]
624#[derive(Clone, Debug, PartialEq)]
625#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
626#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
627pub struct Normal3Vec(pub Vec<Vec3Impl>);
628
629#[cfg(all(feature = "normal3", feature = "vec_variants"))]
630impl Normal3Vec {
631    pub fn new(vec: Vec<Vec3Impl>) -> Result<Self> {
632        if vec.is_empty() {
633            return Err(Error::EmptyVec {
634                type_name: "Normal3Vec",
635            });
636        }
637        Ok(Normal3Vec(vec))
638    }
639}
640
641#[cfg(all(feature = "normal3", feature = "vec_variants"))]
642impl Eq for Normal3Vec {}
643
644/// A vector of 3D points.
645#[cfg(all(feature = "point3", feature = "vec_variants"))]
646#[derive(Clone, Debug, PartialEq)]
647#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
648#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
649pub struct Point3Vec(pub Vec<Point3Impl>);
650
651#[cfg(all(feature = "point3", feature = "vec_variants"))]
652impl Point3Vec {
653    pub fn new(vec: Vec<Point3Impl>) -> Result<Self> {
654        if vec.is_empty() {
655            return Err(Error::EmptyVec {
656                type_name: "Point3Vec",
657            });
658        }
659        Ok(Point3Vec(vec))
660    }
661}
662
663#[cfg(all(feature = "point3", feature = "vec_variants"))]
664impl Eq for Point3Vec {}
665
666/// A vector of 4×4 transformation matrices.
667#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
668#[derive(Clone, Debug, PartialEq)]
669#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
670#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
671pub struct Matrix4Vec(pub Vec<Mat4Impl>);
672
673#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
674impl Matrix4Vec {
675    pub fn new(vec: Vec<Mat4Impl>) -> Result<Self> {
676        if vec.is_empty() {
677            return Err(Error::EmptyVec {
678                type_name: "Matrix4Vec",
679            });
680        }
681        Ok(Matrix4Vec(vec))
682    }
683}
684
685#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
686impl Eq for Matrix4Vec {}
687
688// Arithmetic operations for new types
689#[cfg(feature = "normal3")]
690impl_nalgebra_arithmetic!(Normal3);
691
692#[cfg(feature = "point3")]
693impl Add for Point3 {
694    type Output = Point3;
695
696    fn add(self, other: Point3) -> Point3 {
697        Point3(Point3Impl::new(
698            self.0.x + other.0.x,
699            self.0.y + other.0.y,
700            self.0.z + other.0.z,
701        ))
702    }
703}
704
705#[cfg(feature = "point3")]
706impl Sub for Point3 {
707    type Output = Point3;
708
709    fn sub(self, other: Point3) -> Point3 {
710        Point3(Point3Impl::new(
711            self.0.x - other.0.x,
712            self.0.y - other.0.y,
713            self.0.z - other.0.z,
714        ))
715    }
716}
717
718#[cfg(feature = "point3")]
719impl Mul<f32> for Point3 {
720    type Output = Point3;
721
722    fn mul(self, scalar: f32) -> Point3 {
723        Point3(Point3Impl::new(
724            self.0.x * scalar,
725            self.0.y * scalar,
726            self.0.z * scalar,
727        ))
728    }
729}
730
731#[cfg(feature = "point3")]
732impl Mul<f64> for Point3 {
733    type Output = Point3;
734
735    fn mul(self, scalar: f64) -> Point3 {
736        let s = scalar as f32;
737        Point3(Point3Impl::new(self.0.x * s, self.0.y * s, self.0.z * s))
738    }
739}
740
741// Matrix4 arithmetic operations.
742// AIDEV-NOTE: Manual impls using math utility functions because ultraviolet's
743// DMat4 lacks Sub.
744#[cfg(feature = "matrix4")]
745impl Add for Matrix4 {
746    type Output = Matrix4;
747    fn add(self, other: Matrix4) -> Matrix4 {
748        Matrix4(self.0 + other.0)
749    }
750}
751
752#[cfg(feature = "matrix4")]
753impl Sub for Matrix4 {
754    type Output = Matrix4;
755    fn sub(self, other: Matrix4) -> Matrix4 {
756        Matrix4(mat4_sub(self.0, other.0))
757    }
758}
759
760#[cfg(feature = "matrix4")]
761impl Mul<f32> for Matrix4 {
762    type Output = Matrix4;
763    fn mul(self, scalar: f32) -> Matrix4 {
764        Matrix4(self.0 * scalar as f64)
765    }
766}
767
768#[cfg(feature = "matrix4")]
769impl Mul<f64> for Matrix4 {
770    type Output = Matrix4;
771    fn mul(self, scalar: f64) -> Matrix4 {
772        Matrix4(self.0 * scalar)
773    }
774}
775
776// Arithmetic trait implementations for interpolation
777impl Add for Real {
778    type Output = Real;
779
780    fn add(self, other: Real) -> Real {
781        Real(self.0 + other.0)
782    }
783}
784
785impl Sub for Real {
786    type Output = Real;
787
788    fn sub(self, other: Real) -> Real {
789        Real(self.0 - other.0)
790    }
791}
792
793impl Mul<f32> for Real {
794    type Output = Real;
795
796    fn mul(self, scalar: f32) -> Real {
797        Real(self.0 * scalar as f64)
798    }
799}
800
801impl Mul<f64> for Real {
802    type Output = Real;
803
804    fn mul(self, scalar: f64) -> Real {
805        Real(self.0 * scalar)
806    }
807}
808
809impl Add for Integer {
810    type Output = Integer;
811
812    fn add(self, other: Integer) -> Integer {
813        Integer(self.0 + other.0)
814    }
815}
816
817impl Sub for Integer {
818    type Output = Integer;
819
820    fn sub(self, other: Integer) -> Integer {
821        Integer(self.0 - other.0)
822    }
823}
824
825impl Mul<f32> for Integer {
826    type Output = Integer;
827
828    fn mul(self, scalar: f32) -> Integer {
829        Integer((self.0 as f64 * scalar as f64) as i64)
830    }
831}
832
833impl Mul<f64> for Integer {
834    type Output = Integer;
835
836    fn mul(self, scalar: f64) -> Integer {
837        Integer((self.0 as f64 * scalar) as i64)
838    }
839}
840
841// Boolean arithmetic operations (treat as 0.0 and 1.0)
842impl Add for Boolean {
843    type Output = Boolean;
844
845    fn add(self, other: Boolean) -> Boolean {
846        Boolean(self.0 || other.0)
847    }
848}
849
850impl Sub for Boolean {
851    type Output = Boolean;
852
853    fn sub(self, other: Boolean) -> Boolean {
854        Boolean(self.0 && !other.0)
855    }
856}
857
858impl Mul<f32> for Boolean {
859    type Output = Boolean;
860
861    fn mul(self, _scalar: f32) -> Boolean {
862        self
863    }
864}
865
866impl Mul<f64> for Boolean {
867    type Output = Boolean;
868
869    fn mul(self, _scalar: f64) -> Boolean {
870        self
871    }
872}
873
874// String arithmetic operations (concatenation for add, identity for others)
875impl Add for String {
876    type Output = String;
877
878    fn add(self, _other: String) -> String {
879        self
880    }
881}
882
883impl Sub for String {
884    type Output = String;
885
886    fn sub(self, _other: String) -> String {
887        self
888    }
889}
890
891impl Mul<f32> for String {
892    type Output = String;
893
894    fn mul(self, _scalar: f32) -> String {
895        self
896    }
897}
898
899impl Mul<f64> for String {
900    type Output = String;
901
902    fn mul(self, _scalar: f64) -> String {
903        self
904    }
905}
906
907// BooleanVec arithmetic operations
908impl Add for BooleanVec {
909    type Output = BooleanVec;
910
911    fn add(self, other: BooleanVec) -> BooleanVec {
912        if self.0.len() != other.0.len() {
913            panic!("Vector lengths must match for addition");
914        }
915        BooleanVec(
916            self.0
917                .into_iter()
918                .zip(other.0)
919                .map(|(a, b)| a || b)
920                .collect(),
921        )
922    }
923}
924
925impl Sub for BooleanVec {
926    type Output = BooleanVec;
927
928    fn sub(self, other: BooleanVec) -> BooleanVec {
929        if self.0.len() != other.0.len() {
930            panic!("Vector lengths must match for subtraction");
931        }
932        BooleanVec(
933            self.0
934                .into_iter()
935                .zip(other.0)
936                .map(|(a, b)| a && !b)
937                .collect(),
938        )
939    }
940}
941
942impl Mul<f32> for BooleanVec {
943    type Output = BooleanVec;
944
945    fn mul(self, _scalar: f32) -> BooleanVec {
946        self
947    }
948}
949
950impl Mul<f64> for BooleanVec {
951    type Output = BooleanVec;
952
953    fn mul(self, _scalar: f64) -> BooleanVec {
954        self
955    }
956}
957
958// StringVec arithmetic operations
959impl Add for StringVec {
960    type Output = StringVec;
961
962    fn add(self, other: StringVec) -> StringVec {
963        if self.0.len() != other.0.len() {
964            panic!("Vector lengths must match for addition");
965        }
966        StringVec(
967            self.0
968                .into_iter()
969                .zip(other.0)
970                .map(|(a, b)| format!("{a}{b}"))
971                .collect(),
972        )
973    }
974}
975
976impl Sub for StringVec {
977    type Output = StringVec;
978
979    fn sub(self, _other: StringVec) -> StringVec {
980        self
981    }
982}
983
984impl Mul<f32> for StringVec {
985    type Output = StringVec;
986
987    fn mul(self, _scalar: f32) -> StringVec {
988        self
989    }
990}
991
992impl Mul<f64> for StringVec {
993    type Output = StringVec;
994
995    fn mul(self, _scalar: f64) -> StringVec {
996        self
997    }
998}
999
1000// Color arithmetic operations on [f32; 4].
1001impl Add for Color {
1002    type Output = Color;
1003
1004    #[inline(always)]
1005    fn add(self, other: Color) -> Color {
1006        Color([
1007            self.0[0] + other.0[0],
1008            self.0[1] + other.0[1],
1009            self.0[2] + other.0[2],
1010            self.0[3] + other.0[3],
1011        ])
1012    }
1013}
1014
1015impl Sub for Color {
1016    type Output = Color;
1017
1018    #[inline(always)]
1019    fn sub(self, other: Color) -> Color {
1020        Color([
1021            self.0[0] - other.0[0],
1022            self.0[1] - other.0[1],
1023            self.0[2] - other.0[2],
1024            self.0[3] - other.0[3],
1025        ])
1026    }
1027}
1028
1029impl Mul<f32> for Color {
1030    type Output = Color;
1031
1032    #[inline(always)]
1033    fn mul(self, s: f32) -> Color {
1034        Color([self.0[0] * s, self.0[1] * s, self.0[2] * s, self.0[3] * s])
1035    }
1036}
1037
1038impl Div<f32> for Color {
1039    type Output = Color;
1040
1041    #[inline(always)]
1042    fn div(self, s: f32) -> Color {
1043        Color([self.0[0] / s, self.0[1] / s, self.0[2] / s, self.0[3] / s])
1044    }
1045}
1046
1047impl Mul<f64> for Color {
1048    type Output = Color;
1049
1050    #[inline(always)]
1051    fn mul(self, scalar: f64) -> Color {
1052        self * (scalar as f32)
1053    }
1054}
1055
1056impl Div<f64> for Color {
1057    type Output = Color;
1058
1059    #[inline(always)]
1060    fn div(self, scalar: f64) -> Color {
1061        self / (scalar as f32)
1062    }
1063}
1064
1065// Vector2 arithmetic operations
1066#[cfg(feature = "vector2")]
1067impl_nalgebra_arithmetic!(Vector2);
1068
1069// Vector3 arithmetic operations
1070#[cfg(feature = "vector3")]
1071impl_nalgebra_arithmetic!(Vector3);
1072
1073// Matrix3 arithmetic operations.
1074// AIDEV-NOTE: Manual impls using math utility functions because ultraviolet's
1075// Mat3 lacks Sub and Div<f32>.
1076#[cfg(feature = "matrix3")]
1077impl Add for Matrix3 {
1078    type Output = Matrix3;
1079    fn add(self, other: Matrix3) -> Matrix3 {
1080        Matrix3(self.0 + other.0)
1081    }
1082}
1083
1084#[cfg(feature = "matrix3")]
1085impl Sub for Matrix3 {
1086    type Output = Matrix3;
1087    fn sub(self, other: Matrix3) -> Matrix3 {
1088        Matrix3(mat3_sub(self.0, other.0))
1089    }
1090}
1091
1092#[cfg(feature = "matrix3")]
1093impl Mul<f32> for Matrix3 {
1094    type Output = Matrix3;
1095    fn mul(self, scalar: f32) -> Matrix3 {
1096        Matrix3(self.0 * scalar)
1097    }
1098}
1099
1100#[cfg(feature = "matrix3")]
1101impl Mul<f64> for Matrix3 {
1102    type Output = Matrix3;
1103    fn mul(self, scalar: f64) -> Matrix3 {
1104        Matrix3(self.0 * scalar as f32)
1105    }
1106}
1107
1108// Matrix3 multiplication (matrix * matrix)
1109#[cfg(feature = "matrix3")]
1110impl Mul for Matrix3 {
1111    type Output = Matrix3;
1112
1113    fn mul(self, other: Matrix3) -> Matrix3 {
1114        Matrix3(self.0 * other.0)
1115    }
1116}
1117
1118#[cfg(feature = "matrix3")]
1119impl Mul<&Matrix3> for Matrix3 {
1120    type Output = Matrix3;
1121
1122    fn mul(self, other: &Matrix3) -> Matrix3 {
1123        Matrix3(self.0 * other.0)
1124    }
1125}
1126
1127#[cfg(feature = "matrix3")]
1128impl Mul<Matrix3> for &Matrix3 {
1129    type Output = Matrix3;
1130
1131    fn mul(self, other: Matrix3) -> Matrix3 {
1132        Matrix3(self.0 * other.0)
1133    }
1134}
1135
1136#[cfg(feature = "matrix3")]
1137impl Mul<&Matrix3> for &Matrix3 {
1138    type Output = Matrix3;
1139
1140    fn mul(self, other: &Matrix3) -> Matrix3 {
1141        Matrix3(self.0 * other.0)
1142    }
1143}
1144
1145// Vector types arithmetic operations
1146impl Add for RealVec {
1147    type Output = RealVec;
1148
1149    fn add(self, other: RealVec) -> RealVec {
1150        if self.0.len() != other.0.len() {
1151            panic!("Vector lengths must match for addition");
1152        }
1153        RealVec(
1154            self.0
1155                .into_iter()
1156                .zip(other.0)
1157                .map(|(a, b)| a + b)
1158                .collect(),
1159        )
1160    }
1161}
1162
1163impl Sub for RealVec {
1164    type Output = RealVec;
1165
1166    fn sub(self, other: RealVec) -> RealVec {
1167        if self.0.len() != other.0.len() {
1168            panic!("Vector lengths must match for subtraction");
1169        }
1170        RealVec(
1171            self.0
1172                .into_iter()
1173                .zip(other.0)
1174                .map(|(a, b)| a - b)
1175                .collect(),
1176        )
1177    }
1178}
1179
1180impl Mul<f32> for RealVec {
1181    type Output = RealVec;
1182
1183    fn mul(self, scalar: f32) -> RealVec {
1184        RealVec(self.0.into_iter().map(|x| x * scalar as f64).collect())
1185    }
1186}
1187
1188impl Mul<f64> for RealVec {
1189    type Output = RealVec;
1190
1191    fn mul(self, scalar: f64) -> RealVec {
1192        RealVec(self.0.into_iter().map(|x| x * scalar).collect())
1193    }
1194}
1195
1196impl Add for IntegerVec {
1197    type Output = IntegerVec;
1198
1199    fn add(self, other: IntegerVec) -> IntegerVec {
1200        if self.0.len() != other.0.len() {
1201            panic!("Vector lengths must match for addition");
1202        }
1203        IntegerVec(
1204            self.0
1205                .into_iter()
1206                .zip(other.0)
1207                .map(|(a, b)| a + b)
1208                .collect(),
1209        )
1210    }
1211}
1212
1213impl Sub for IntegerVec {
1214    type Output = IntegerVec;
1215
1216    fn sub(self, other: IntegerVec) -> IntegerVec {
1217        if self.0.len() != other.0.len() {
1218            panic!("Vector lengths must match for subtraction");
1219        }
1220        IntegerVec(
1221            self.0
1222                .into_iter()
1223                .zip(other.0)
1224                .map(|(a, b)| a - b)
1225                .collect(),
1226        )
1227    }
1228}
1229
1230impl Mul<f32> for IntegerVec {
1231    type Output = IntegerVec;
1232
1233    fn mul(self, scalar: f32) -> IntegerVec {
1234        IntegerVec(
1235            self.0
1236                .into_iter()
1237                .map(|x| (x as f64 * scalar as f64) as i64)
1238                .collect(),
1239        )
1240    }
1241}
1242
1243impl Mul<f64> for IntegerVec {
1244    type Output = IntegerVec;
1245
1246    fn mul(self, scalar: f64) -> IntegerVec {
1247        IntegerVec(
1248            self.0
1249                .into_iter()
1250                .map(|x| (x as f64 * scalar) as i64)
1251                .collect(),
1252        )
1253    }
1254}
1255
1256impl Add for ColorVec {
1257    type Output = ColorVec;
1258
1259    fn add(self, other: ColorVec) -> ColorVec {
1260        if self.0.len() != other.0.len() {
1261            panic!("Vector lengths must match for addition");
1262        }
1263        ColorVec(
1264            self.0
1265                .into_iter()
1266                .zip(other.0)
1267                .map(|(a, b)| [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]])
1268                .collect(),
1269        )
1270    }
1271}
1272
1273impl Sub for ColorVec {
1274    type Output = ColorVec;
1275
1276    fn sub(self, other: ColorVec) -> ColorVec {
1277        if self.0.len() != other.0.len() {
1278            panic!("Vector lengths must match for subtraction");
1279        }
1280        ColorVec(
1281            self.0
1282                .into_iter()
1283                .zip(other.0)
1284                .map(|(a, b)| [a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]])
1285                .collect(),
1286        )
1287    }
1288}
1289
1290impl Mul<f32> for ColorVec {
1291    type Output = ColorVec;
1292
1293    fn mul(self, scalar: f32) -> ColorVec {
1294        ColorVec(
1295            self.0
1296                .into_iter()
1297                .map(|color| {
1298                    [
1299                        color[0] * scalar,
1300                        color[1] * scalar,
1301                        color[2] * scalar,
1302                        color[3] * scalar,
1303                    ]
1304                })
1305                .collect(),
1306        )
1307    }
1308}
1309
1310impl Mul<f64> for ColorVec {
1311    type Output = ColorVec;
1312
1313    fn mul(self, scalar: f64) -> ColorVec {
1314        let scalar = scalar as f32;
1315        ColorVec(
1316            self.0
1317                .into_iter()
1318                .map(|color| {
1319                    [
1320                        color[0] * scalar,
1321                        color[1] * scalar,
1322                        color[2] * scalar,
1323                        color[3] * scalar,
1324                    ]
1325                })
1326                .collect(),
1327        )
1328    }
1329}
1330
1331#[cfg(all(feature = "vector2", feature = "vec_variants"))]
1332impl Add for Vector2Vec {
1333    type Output = Vector2Vec;
1334
1335    fn add(self, other: Vector2Vec) -> Vector2Vec {
1336        if self.0.len() != other.0.len() {
1337            panic!("Vector lengths must match for addition");
1338        }
1339        Vector2Vec(
1340            self.0
1341                .into_iter()
1342                .zip(other.0)
1343                .map(|(a, b)| a + b)
1344                .collect(),
1345        )
1346    }
1347}
1348
1349#[cfg(all(feature = "vector2", feature = "vec_variants"))]
1350impl Sub for Vector2Vec {
1351    type Output = Vector2Vec;
1352
1353    fn sub(self, other: Vector2Vec) -> Vector2Vec {
1354        if self.0.len() != other.0.len() {
1355            panic!("Vector lengths must match for subtraction");
1356        }
1357        Vector2Vec(
1358            self.0
1359                .into_iter()
1360                .zip(other.0)
1361                .map(|(a, b)| a - b)
1362                .collect(),
1363        )
1364    }
1365}
1366
1367#[cfg(all(feature = "vector2", feature = "vec_variants"))]
1368impl Mul<f32> for Vector2Vec {
1369    type Output = Vector2Vec;
1370
1371    fn mul(self, scalar: f32) -> Vector2Vec {
1372        Vector2Vec(self.0.into_iter().map(|vec| vec * scalar).collect())
1373    }
1374}
1375
1376#[cfg(all(feature = "vector2", feature = "vec_variants"))]
1377impl Mul<f64> for Vector2Vec {
1378    type Output = Vector2Vec;
1379
1380    fn mul(self, scalar: f64) -> Vector2Vec {
1381        let scalar = scalar as f32;
1382        Vector2Vec(self.0.into_iter().map(|vec| vec * scalar).collect())
1383    }
1384}
1385
1386#[cfg(all(feature = "vector3", feature = "vec_variants"))]
1387impl Add for Vector3Vec {
1388    type Output = Vector3Vec;
1389
1390    fn add(self, other: Vector3Vec) -> Vector3Vec {
1391        if self.0.len() != other.0.len() {
1392            panic!("Vector lengths must match for addition");
1393        }
1394        Vector3Vec(
1395            self.0
1396                .into_iter()
1397                .zip(other.0)
1398                .map(|(a, b)| a + b)
1399                .collect(),
1400        )
1401    }
1402}
1403
1404#[cfg(all(feature = "vector3", feature = "vec_variants"))]
1405impl Sub for Vector3Vec {
1406    type Output = Vector3Vec;
1407
1408    fn sub(self, other: Vector3Vec) -> Vector3Vec {
1409        if self.0.len() != other.0.len() {
1410            panic!("Vector lengths must match for subtraction");
1411        }
1412        Vector3Vec(
1413            self.0
1414                .into_iter()
1415                .zip(other.0)
1416                .map(|(a, b)| a - b)
1417                .collect(),
1418        )
1419    }
1420}
1421
1422#[cfg(all(feature = "vector3", feature = "vec_variants"))]
1423impl Mul<f32> for Vector3Vec {
1424    type Output = Vector3Vec;
1425
1426    fn mul(self, scalar: f32) -> Vector3Vec {
1427        Vector3Vec(self.0.into_iter().map(|vec| vec * scalar).collect())
1428    }
1429}
1430
1431#[cfg(all(feature = "vector3", feature = "vec_variants"))]
1432impl Mul<f64> for Vector3Vec {
1433    type Output = Vector3Vec;
1434
1435    fn mul(self, scalar: f64) -> Vector3Vec {
1436        let scalar = scalar as f32;
1437        Vector3Vec(self.0.into_iter().map(|vec| vec * scalar).collect())
1438    }
1439}
1440
1441#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1442impl Add for Matrix3Vec {
1443    type Output = Matrix3Vec;
1444
1445    fn add(mut self, other: Matrix3Vec) -> Matrix3Vec {
1446        if self.0.len() != other.0.len() {
1447            panic!("Vector lengths must match for addition");
1448        }
1449        self.0.iter_mut().zip(other.0).for_each(|(a, b)| *a += b);
1450        self
1451    }
1452}
1453
1454#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1455impl Sub for Matrix3Vec {
1456    type Output = Matrix3Vec;
1457
1458    fn sub(mut self, other: Matrix3Vec) -> Matrix3Vec {
1459        if self.0.len() != other.0.len() {
1460            panic!("Vector lengths must match for subtraction");
1461        }
1462        self.0
1463            .iter_mut()
1464            .zip(other.0)
1465            .for_each(|(a, b)| *a = mat3_sub(*a, b));
1466        self
1467    }
1468}
1469
1470#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1471impl Mul<f32> for Matrix3Vec {
1472    type Output = Matrix3Vec;
1473
1474    #[allow(clippy::assign_op_pattern)]
1475    fn mul(mut self, scalar: f32) -> Matrix3Vec {
1476        // AIDEV-NOTE: no MulAssign on ultraviolet Mat3.
1477        self.0.iter_mut().for_each(|mat| *mat = *mat * scalar);
1478        self
1479    }
1480}
1481
1482#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1483impl Mul<f64> for Matrix3Vec {
1484    type Output = Matrix3Vec;
1485
1486    #[allow(clippy::assign_op_pattern)]
1487    fn mul(mut self, scalar: f64) -> Matrix3Vec {
1488        let scalar = scalar as f32;
1489        self.0.iter_mut().for_each(|mat| *mat = *mat * scalar);
1490        self
1491    }
1492}
1493
1494// Normal3Vec arithmetic operations
1495#[cfg(all(feature = "normal3", feature = "vec_variants"))]
1496impl Add for Normal3Vec {
1497    type Output = Normal3Vec;
1498
1499    fn add(self, other: Normal3Vec) -> Self::Output {
1500        Normal3Vec(
1501            self.0
1502                .into_iter()
1503                .zip(other.0)
1504                .map(|(a, b)| a + b)
1505                .collect(),
1506        )
1507    }
1508}
1509
1510#[cfg(all(feature = "normal3", feature = "vec_variants"))]
1511impl Sub for Normal3Vec {
1512    type Output = Normal3Vec;
1513
1514    fn sub(self, other: Normal3Vec) -> Self::Output {
1515        Normal3Vec(
1516            self.0
1517                .into_iter()
1518                .zip(other.0)
1519                .map(|(a, b)| a - b)
1520                .collect(),
1521        )
1522    }
1523}
1524
1525#[cfg(all(feature = "normal3", feature = "vec_variants"))]
1526impl Mul<f32> for Normal3Vec {
1527    type Output = Normal3Vec;
1528
1529    fn mul(self, scalar: f32) -> Self::Output {
1530        Normal3Vec(self.0.into_iter().map(|v| v * scalar).collect())
1531    }
1532}
1533
1534#[cfg(all(feature = "normal3", feature = "vec_variants"))]
1535impl Mul<f64> for Normal3Vec {
1536    type Output = Normal3Vec;
1537
1538    fn mul(self, scalar: f64) -> Self::Output {
1539        Normal3Vec(self.0.into_iter().map(|v| v * scalar as f32).collect())
1540    }
1541}
1542
1543// Point3Vec arithmetic operations.
1544#[cfg(all(feature = "point3", feature = "vec_variants"))]
1545impl Add for Point3Vec {
1546    type Output = Point3Vec;
1547
1548    fn add(self, other: Point3Vec) -> Self::Output {
1549        Point3Vec(
1550            self.0
1551                .into_iter()
1552                .zip(other.0)
1553                .map(|(a, b)| Point3Impl::new(a.x + b.x, a.y + b.y, a.z + b.z))
1554                .collect(),
1555        )
1556    }
1557}
1558
1559#[cfg(all(feature = "point3", feature = "vec_variants"))]
1560impl Sub for Point3Vec {
1561    type Output = Point3Vec;
1562
1563    fn sub(self, other: Point3Vec) -> Self::Output {
1564        Point3Vec(
1565            self.0
1566                .into_iter()
1567                .zip(other.0)
1568                .map(|(a, b)| Point3Impl::new(a.x - b.x, a.y - b.y, a.z - b.z))
1569                .collect(),
1570        )
1571    }
1572}
1573
1574#[cfg(all(feature = "point3", feature = "vec_variants"))]
1575impl Mul<f32> for Point3Vec {
1576    type Output = Point3Vec;
1577
1578    fn mul(self, s: f32) -> Self::Output {
1579        Point3Vec(
1580            self.0
1581                .into_iter()
1582                .map(|p| Point3Impl::new(p.x * s, p.y * s, p.z * s))
1583                .collect(),
1584        )
1585    }
1586}
1587
1588#[cfg(all(feature = "point3", feature = "vec_variants"))]
1589impl Mul<f64> for Point3Vec {
1590    type Output = Point3Vec;
1591
1592    fn mul(self, scalar: f64) -> Self::Output {
1593        let s = scalar as f32;
1594        Point3Vec(
1595            self.0
1596                .into_iter()
1597                .map(|p| Point3Impl::new(p.x * s, p.y * s, p.z * s))
1598                .collect(),
1599        )
1600    }
1601}
1602
1603// Matrix4Vec arithmetic operations
1604#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1605impl Add for Matrix4Vec {
1606    type Output = Matrix4Vec;
1607
1608    fn add(mut self, other: Matrix4Vec) -> Self::Output {
1609        self.0.iter_mut().zip(other.0).for_each(|(a, b)| *a += b);
1610        self
1611    }
1612}
1613
1614#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1615impl Sub for Matrix4Vec {
1616    type Output = Matrix4Vec;
1617
1618    fn sub(mut self, other: Matrix4Vec) -> Self::Output {
1619        self.0
1620            .iter_mut()
1621            .zip(other.0)
1622            .for_each(|(a, b)| *a = mat4_sub(*a, b));
1623        self
1624    }
1625}
1626
1627#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1628impl Mul<f32> for Matrix4Vec {
1629    type Output = Matrix4Vec;
1630
1631    #[allow(clippy::assign_op_pattern)]
1632    fn mul(mut self, scalar: f32) -> Self::Output {
1633        // AIDEV-NOTE: no MulAssign on ultraviolet DMat4.
1634        let scalar = scalar as f64;
1635        self.0.iter_mut().for_each(|v| *v = *v * scalar);
1636        self
1637    }
1638}
1639
1640#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1641impl Mul<f64> for Matrix4Vec {
1642    type Output = Matrix4Vec;
1643
1644    #[allow(clippy::assign_op_pattern)]
1645    fn mul(mut self, scalar: f64) -> Self::Output {
1646        self.0.iter_mut().for_each(|v| *v = *v * scalar);
1647        self
1648    }
1649}
1650
1651// Division implementations for f32
1652#[cfg(feature = "normal3")]
1653impl Div<f32> for Normal3 {
1654    type Output = Normal3;
1655
1656    fn div(self, scalar: f32) -> Normal3 {
1657        Normal3(self.0 / scalar)
1658    }
1659}
1660
1661#[cfg(feature = "point3")]
1662impl Div<f32> for Point3 {
1663    type Output = Point3;
1664
1665    fn div(self, s: f32) -> Point3 {
1666        Point3(Point3Impl::new(self.0.x / s, self.0.y / s, self.0.z / s))
1667    }
1668}
1669
1670#[cfg(feature = "matrix4")]
1671#[allow(clippy::suspicious_arithmetic_impl)]
1672impl Div<f32> for Matrix4 {
1673    type Output = Matrix4;
1674
1675    fn div(self, scalar: f32) -> Matrix4 {
1676        // AIDEV-NOTE: ultraviolet DMat4 lacks Div<f64>.
1677        #[cfg(not(feature = "ultraviolet"))]
1678        {
1679            Matrix4(self.0 / scalar as f64)
1680        }
1681        #[cfg(feature = "ultraviolet")]
1682        {
1683            self * (1.0 / scalar as f64)
1684        }
1685    }
1686}
1687
1688impl Div<f32> for Real {
1689    type Output = Real;
1690
1691    fn div(self, scalar: f32) -> Real {
1692        Real(self.0 / scalar as f64)
1693    }
1694}
1695
1696impl Div<f32> for Integer {
1697    type Output = Integer;
1698
1699    fn div(self, scalar: f32) -> Integer {
1700        Integer((self.0 as f64 / scalar as f64) as i64)
1701    }
1702}
1703
1704impl Div<f32> for Boolean {
1705    type Output = Boolean;
1706
1707    fn div(self, _scalar: f32) -> Boolean {
1708        self
1709    }
1710}
1711
1712impl Div<f32> for String {
1713    type Output = String;
1714
1715    fn div(self, _scalar: f32) -> String {
1716        self
1717    }
1718}
1719
1720impl Div<f32> for BooleanVec {
1721    type Output = BooleanVec;
1722
1723    fn div(self, _scalar: f32) -> BooleanVec {
1724        self
1725    }
1726}
1727
1728impl Div<f32> for StringVec {
1729    type Output = StringVec;
1730
1731    fn div(self, _scalar: f32) -> StringVec {
1732        self
1733    }
1734}
1735
1736#[cfg(feature = "vector2")]
1737impl Div<f32> for Vector2 {
1738    type Output = Vector2;
1739
1740    fn div(self, scalar: f32) -> Vector2 {
1741        Vector2(self.0 / scalar)
1742    }
1743}
1744
1745#[cfg(feature = "vector3")]
1746impl Div<f32> for Vector3 {
1747    type Output = Vector3;
1748
1749    fn div(self, scalar: f32) -> Vector3 {
1750        Vector3(self.0 / scalar)
1751    }
1752}
1753
1754#[cfg(feature = "matrix3")]
1755#[allow(clippy::suspicious_arithmetic_impl)]
1756impl Div<f32> for Matrix3 {
1757    type Output = Matrix3;
1758
1759    fn div(self, scalar: f32) -> Matrix3 {
1760        // AIDEV-NOTE: ultraviolet Mat3 lacks Div<f32>.
1761        #[cfg(not(feature = "ultraviolet"))]
1762        {
1763            Matrix3(self.0 / scalar)
1764        }
1765        #[cfg(feature = "ultraviolet")]
1766        {
1767            self * (1.0 / scalar)
1768        }
1769    }
1770}
1771
1772impl Div<f32> for RealVec {
1773    type Output = RealVec;
1774
1775    fn div(self, scalar: f32) -> RealVec {
1776        RealVec(self.0.into_iter().map(|x| x / scalar as f64).collect())
1777    }
1778}
1779
1780impl Div<f32> for IntegerVec {
1781    type Output = IntegerVec;
1782
1783    fn div(self, scalar: f32) -> IntegerVec {
1784        IntegerVec(
1785            self.0
1786                .into_iter()
1787                .map(|x| (x as f64 / scalar as f64) as i64)
1788                .collect(),
1789        )
1790    }
1791}
1792
1793impl Div<f32> for ColorVec {
1794    type Output = ColorVec;
1795
1796    fn div(self, scalar: f32) -> ColorVec {
1797        ColorVec(
1798            self.0
1799                .into_iter()
1800                .map(|color| {
1801                    [
1802                        color[0] / scalar,
1803                        color[1] / scalar,
1804                        color[2] / scalar,
1805                        color[3] / scalar,
1806                    ]
1807                })
1808                .collect(),
1809        )
1810    }
1811}
1812
1813#[cfg(all(feature = "vector2", feature = "vec_variants"))]
1814impl Div<f32> for Vector2Vec {
1815    type Output = Vector2Vec;
1816
1817    fn div(self, scalar: f32) -> Vector2Vec {
1818        Vector2Vec(self.0.into_iter().map(|vec| vec / scalar).collect())
1819    }
1820}
1821
1822#[cfg(all(feature = "vector3", feature = "vec_variants"))]
1823impl Div<f32> for Vector3Vec {
1824    type Output = Vector3Vec;
1825
1826    fn div(self, scalar: f32) -> Vector3Vec {
1827        Vector3Vec(self.0.into_iter().map(|vec| vec / scalar).collect())
1828    }
1829}
1830
1831#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1832#[allow(clippy::suspicious_arithmetic_impl)]
1833impl Div<f32> for Matrix3Vec {
1834    type Output = Matrix3Vec;
1835
1836    fn div(mut self, scalar: f32) -> Matrix3Vec {
1837        #[cfg(not(feature = "ultraviolet"))]
1838        self.0.iter_mut().for_each(|mat| *mat /= scalar);
1839        #[cfg(feature = "ultraviolet")]
1840        {
1841            let recip = 1.0 / scalar;
1842            self.0.iter_mut().for_each(|mat| *mat = *mat * recip);
1843        }
1844        self
1845    }
1846}
1847
1848#[cfg(all(feature = "normal3", feature = "vec_variants"))]
1849impl Div<f32> for Normal3Vec {
1850    type Output = Normal3Vec;
1851
1852    fn div(self, scalar: f32) -> Self::Output {
1853        Normal3Vec(self.0.into_iter().map(|v| v / scalar).collect())
1854    }
1855}
1856
1857#[cfg(all(feature = "point3", feature = "vec_variants"))]
1858impl Div<f32> for Point3Vec {
1859    type Output = Point3Vec;
1860
1861    fn div(self, s: f32) -> Self::Output {
1862        Point3Vec(
1863            self.0
1864                .into_iter()
1865                .map(|p| Point3Impl::new(p.x / s, p.y / s, p.z / s))
1866                .collect(),
1867        )
1868    }
1869}
1870
1871#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1872#[allow(clippy::suspicious_arithmetic_impl)]
1873impl Div<f32> for Matrix4Vec {
1874    type Output = Matrix4Vec;
1875
1876    fn div(mut self, scalar: f32) -> Self::Output {
1877        let scalar = scalar as f64;
1878        #[cfg(not(feature = "ultraviolet"))]
1879        self.0.iter_mut().for_each(|v| *v /= scalar);
1880        #[cfg(feature = "ultraviolet")]
1881        {
1882            let recip = 1.0 / scalar;
1883            self.0.iter_mut().for_each(|v| *v = *v * recip);
1884        }
1885        self
1886    }
1887}
1888
1889// Division implementations for f64
1890#[cfg(feature = "normal3")]
1891impl Div<f64> for Normal3 {
1892    type Output = Normal3;
1893
1894    fn div(self, scalar: f64) -> Normal3 {
1895        Normal3(self.0 / scalar as f32)
1896    }
1897}
1898
1899#[cfg(feature = "point3")]
1900impl Div<f64> for Point3 {
1901    type Output = Point3;
1902
1903    fn div(self, scalar: f64) -> Point3 {
1904        let s = scalar as f32;
1905        Point3(Point3Impl::new(self.0.x / s, self.0.y / s, self.0.z / s))
1906    }
1907}
1908
1909#[cfg(feature = "matrix4")]
1910#[allow(clippy::suspicious_arithmetic_impl)]
1911impl Div<f64> for Matrix4 {
1912    type Output = Matrix4;
1913
1914    fn div(self, scalar: f64) -> Matrix4 {
1915        #[cfg(not(feature = "ultraviolet"))]
1916        {
1917            Matrix4(self.0 / scalar)
1918        }
1919        #[cfg(feature = "ultraviolet")]
1920        {
1921            self * (1.0 / scalar)
1922        }
1923    }
1924}
1925
1926impl Div<f64> for Real {
1927    type Output = Real;
1928
1929    fn div(self, scalar: f64) -> Real {
1930        Real(self.0 / scalar)
1931    }
1932}
1933
1934impl Div<f64> for Integer {
1935    type Output = Integer;
1936
1937    fn div(self, scalar: f64) -> Integer {
1938        Integer((self.0 as f64 / scalar) as i64)
1939    }
1940}
1941
1942impl Div<f64> for Boolean {
1943    type Output = Boolean;
1944
1945    fn div(self, _scalar: f64) -> Boolean {
1946        self
1947    }
1948}
1949
1950impl Div<f64> for String {
1951    type Output = String;
1952
1953    fn div(self, _scalar: f64) -> String {
1954        self
1955    }
1956}
1957
1958impl Div<f64> for BooleanVec {
1959    type Output = BooleanVec;
1960
1961    fn div(self, _scalar: f64) -> BooleanVec {
1962        self
1963    }
1964}
1965
1966impl Div<f64> for StringVec {
1967    type Output = StringVec;
1968
1969    fn div(self, _scalar: f64) -> StringVec {
1970        self
1971    }
1972}
1973
1974#[cfg(feature = "vector2")]
1975impl Div<f64> for Vector2 {
1976    type Output = Vector2;
1977
1978    fn div(self, scalar: f64) -> Vector2 {
1979        Vector2(self.0 / scalar as f32)
1980    }
1981}
1982
1983#[cfg(feature = "vector3")]
1984impl Div<f64> for Vector3 {
1985    type Output = Vector3;
1986
1987    fn div(self, scalar: f64) -> Vector3 {
1988        Vector3(self.0 / scalar as f32)
1989    }
1990}
1991
1992#[cfg(feature = "matrix3")]
1993#[allow(clippy::suspicious_arithmetic_impl)]
1994impl Div<f64> for Matrix3 {
1995    type Output = Matrix3;
1996
1997    fn div(self, scalar: f64) -> Matrix3 {
1998        #[cfg(not(feature = "ultraviolet"))]
1999        {
2000            Matrix3(self.0 / scalar as f32)
2001        }
2002        #[cfg(feature = "ultraviolet")]
2003        {
2004            self * (1.0 / scalar as f32)
2005        }
2006    }
2007}
2008
2009impl Div<f64> for RealVec {
2010    type Output = RealVec;
2011
2012    fn div(self, scalar: f64) -> RealVec {
2013        RealVec(self.0.into_iter().map(|x| x / scalar).collect())
2014    }
2015}
2016
2017impl Div<f64> for IntegerVec {
2018    type Output = IntegerVec;
2019
2020    fn div(self, scalar: f64) -> IntegerVec {
2021        IntegerVec(
2022            self.0
2023                .into_iter()
2024                .map(|x| (x as f64 / scalar) as i64)
2025                .collect(),
2026        )
2027    }
2028}
2029
2030impl Div<f64> for ColorVec {
2031    type Output = ColorVec;
2032
2033    fn div(self, scalar: f64) -> ColorVec {
2034        let scalar = scalar as f32;
2035        ColorVec(
2036            self.0
2037                .into_iter()
2038                .map(|color| {
2039                    [
2040                        color[0] / scalar,
2041                        color[1] / scalar,
2042                        color[2] / scalar,
2043                        color[3] / scalar,
2044                    ]
2045                })
2046                .collect(),
2047        )
2048    }
2049}
2050
2051#[cfg(all(feature = "vector2", feature = "vec_variants"))]
2052impl Div<f64> for Vector2Vec {
2053    type Output = Vector2Vec;
2054
2055    fn div(self, scalar: f64) -> Vector2Vec {
2056        let scalar = scalar as f32;
2057        Vector2Vec(self.0.into_iter().map(|vec| vec / scalar).collect())
2058    }
2059}
2060
2061#[cfg(all(feature = "vector3", feature = "vec_variants"))]
2062impl Div<f64> for Vector3Vec {
2063    type Output = Vector3Vec;
2064
2065    fn div(self, scalar: f64) -> Vector3Vec {
2066        let scalar = scalar as f32;
2067        Vector3Vec(self.0.into_iter().map(|vec| vec / scalar).collect())
2068    }
2069}
2070
2071#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
2072#[allow(clippy::suspicious_arithmetic_impl)]
2073impl Div<f64> for Matrix3Vec {
2074    type Output = Matrix3Vec;
2075
2076    fn div(mut self, scalar: f64) -> Matrix3Vec {
2077        let scalar = scalar as f32;
2078        #[cfg(not(feature = "ultraviolet"))]
2079        self.0.iter_mut().for_each(|mat| *mat /= scalar);
2080        #[cfg(feature = "ultraviolet")]
2081        {
2082            let recip = 1.0 / scalar;
2083            self.0.iter_mut().for_each(|mat| *mat = *mat * recip);
2084        }
2085        self
2086    }
2087}
2088
2089#[cfg(all(feature = "normal3", feature = "vec_variants"))]
2090impl Div<f64> for Normal3Vec {
2091    type Output = Normal3Vec;
2092
2093    fn div(self, scalar: f64) -> Self::Output {
2094        Normal3Vec(self.0.into_iter().map(|v| v / scalar as f32).collect())
2095    }
2096}
2097
2098#[cfg(all(feature = "point3", feature = "vec_variants"))]
2099impl Div<f64> for Point3Vec {
2100    type Output = Point3Vec;
2101
2102    fn div(self, scalar: f64) -> Self::Output {
2103        let s = scalar as f32;
2104        Point3Vec(
2105            self.0
2106                .into_iter()
2107                .map(|p| Point3Impl::new(p.x / s, p.y / s, p.z / s))
2108                .collect(),
2109        )
2110    }
2111}
2112
2113#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
2114#[allow(clippy::suspicious_arithmetic_impl)]
2115impl Div<f64> for Matrix4Vec {
2116    type Output = Matrix4Vec;
2117
2118    fn div(mut self, scalar: f64) -> Self::Output {
2119        #[cfg(not(feature = "ultraviolet"))]
2120        self.0.iter_mut().for_each(|v| *v /= scalar);
2121        #[cfg(feature = "ultraviolet")]
2122        {
2123            let recip = 1.0 / scalar;
2124            self.0.iter_mut().for_each(|v| *v = *v * recip);
2125        }
2126        self
2127    }
2128}
2129
2130// Hash implementations for floating point types
2131// Using bit representation for deterministic hashing
2132
2133impl Hash for Real {
2134    fn hash<H: Hasher>(&self, state: &mut H) {
2135        // Normalize -0.0 to 0.0 for consistent hashing
2136        // Check if the value is zero (either -0.0 or 0.0) and normalize to 0.0
2137        let normalized = if self.0 == 0.0 { 0.0_f64 } else { self.0 };
2138        normalized.to_bits().hash(state);
2139    }
2140}
2141
2142impl Hash for Color {
2143    fn hash<H: Hasher>(&self, state: &mut H) {
2144        for &component in &self.0 {
2145            // Normalize -0.0 to 0.0 for consistent hashing.
2146            let normalized = if component == 0.0 { 0.0_f32 } else { component };
2147            normalized.to_bits().hash(state);
2148        }
2149    }
2150}
2151
2152#[cfg(feature = "vector2")]
2153impl Hash for Vector2 {
2154    fn hash<H: Hasher>(&self, state: &mut H) {
2155        // Normalize -0.0 to 0.0 for consistent hashing
2156        let x = if self.0.x == 0.0 { 0.0_f32 } else { self.0.x };
2157        let y = if self.0.y == 0.0 { 0.0_f32 } else { self.0.y };
2158        x.to_bits().hash(state);
2159        y.to_bits().hash(state);
2160    }
2161}
2162
2163#[cfg(feature = "vector3")]
2164impl Hash for Vector3 {
2165    fn hash<H: Hasher>(&self, state: &mut H) {
2166        // Normalize -0.0 to 0.0 for consistent hashing
2167        let x = if self.0.x == 0.0 { 0.0_f32 } else { self.0.x };
2168        let y = if self.0.y == 0.0 { 0.0_f32 } else { self.0.y };
2169        let z = if self.0.z == 0.0 { 0.0_f32 } else { self.0.z };
2170        x.to_bits().hash(state);
2171        y.to_bits().hash(state);
2172        z.to_bits().hash(state);
2173    }
2174}
2175
2176#[cfg(feature = "matrix3")]
2177impl Hash for Matrix3 {
2178    fn hash<H: Hasher>(&self, state: &mut H) {
2179        for &element in mat3_iter(&self.0) {
2180            // Normalize -0.0 to 0.0 for consistent hashing.
2181            let normalized = if element == 0.0 { 0.0_f32 } else { element };
2182            normalized.to_bits().hash(state);
2183        }
2184    }
2185}
2186
2187impl Hash for RealVec {
2188    fn hash<H: Hasher>(&self, state: &mut H) {
2189        self.0.len().hash(state);
2190        for &element in &self.0 {
2191            // Normalize -0.0 to 0.0 for consistent hashing
2192            let normalized = if element == 0.0 { 0.0_f64 } else { element };
2193            normalized.to_bits().hash(state);
2194        }
2195    }
2196}
2197
2198impl Hash for ColorVec {
2199    fn hash<H: Hasher>(&self, state: &mut H) {
2200        self.0.len().hash(state);
2201        for color in &self.0 {
2202            for &component in color {
2203                // Normalize -0.0 to 0.0 for consistent hashing
2204                let normalized = if component == 0.0 { 0.0_f32 } else { component };
2205                normalized.to_bits().hash(state);
2206            }
2207        }
2208    }
2209}
2210
2211#[cfg(all(feature = "vector2", feature = "vec_variants"))]
2212impl Hash for Vector2Vec {
2213    fn hash<H: Hasher>(&self, state: &mut H) {
2214        self.0.len().hash(state);
2215        for vector in &self.0 {
2216            // Normalize -0.0 to 0.0 for consistent hashing
2217            let x = if vector.x == 0.0 { 0.0_f32 } else { vector.x };
2218            let y = if vector.y == 0.0 { 0.0_f32 } else { vector.y };
2219            x.to_bits().hash(state);
2220            y.to_bits().hash(state);
2221        }
2222    }
2223}
2224
2225#[cfg(all(feature = "vector3", feature = "vec_variants"))]
2226impl Hash for Vector3Vec {
2227    fn hash<H: Hasher>(&self, state: &mut H) {
2228        self.0.len().hash(state);
2229        for vector in &self.0 {
2230            // Normalize -0.0 to 0.0 for consistent hashing
2231            let x = if vector.x == 0.0 { 0.0_f32 } else { vector.x };
2232            let y = if vector.y == 0.0 { 0.0_f32 } else { vector.y };
2233            let z = if vector.z == 0.0 { 0.0_f32 } else { vector.z };
2234            x.to_bits().hash(state);
2235            y.to_bits().hash(state);
2236            z.to_bits().hash(state);
2237        }
2238    }
2239}
2240
2241#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
2242impl Hash for Matrix3Vec {
2243    fn hash<H: Hasher>(&self, state: &mut H) {
2244        self.0.len().hash(state);
2245        for matrix in &self.0 {
2246            for &element in mat3_iter(matrix) {
2247                // Normalize -0.0 to 0.0 for consistent hashing.
2248                let normalized = if element == 0.0 { 0.0_f32 } else { element };
2249                normalized.to_bits().hash(state);
2250            }
2251        }
2252    }
2253}
2254
2255// Hash implementations for new types
2256#[cfg(feature = "normal3")]
2257impl Hash for Normal3 {
2258    fn hash<H: Hasher>(&self, state: &mut H) {
2259        // Normalize -0.0 to 0.0 for consistent hashing
2260        let x = if self.0.x == 0.0 { 0.0_f32 } else { self.0.x };
2261        let y = if self.0.y == 0.0 { 0.0_f32 } else { self.0.y };
2262        let z = if self.0.z == 0.0 { 0.0_f32 } else { self.0.z };
2263        x.to_bits().hash(state);
2264        y.to_bits().hash(state);
2265        z.to_bits().hash(state);
2266    }
2267}
2268
2269#[cfg(feature = "point3")]
2270impl Hash for Point3 {
2271    fn hash<H: Hasher>(&self, state: &mut H) {
2272        // Normalize -0.0 to 0.0 for consistent hashing
2273        let x = if self.0.x == 0.0 { 0.0_f32 } else { self.0.x };
2274        let y = if self.0.y == 0.0 { 0.0_f32 } else { self.0.y };
2275        let z = if self.0.z == 0.0 { 0.0_f32 } else { self.0.z };
2276        x.to_bits().hash(state);
2277        y.to_bits().hash(state);
2278        z.to_bits().hash(state);
2279    }
2280}
2281
2282#[cfg(feature = "matrix4")]
2283impl Hash for Matrix4 {
2284    fn hash<H: Hasher>(&self, state: &mut H) {
2285        for &element in mat4_iter(&self.0) {
2286            // Normalize -0.0 to 0.0 for consistent hashing.
2287            let normalized = if element == 0.0 { 0.0_f64 } else { element };
2288            normalized.to_bits().hash(state);
2289        }
2290    }
2291}
2292
2293#[cfg(all(feature = "normal3", feature = "vec_variants"))]
2294impl Hash for Normal3Vec {
2295    fn hash<H: Hasher>(&self, state: &mut H) {
2296        self.0.len().hash(state);
2297        for vector in &self.0 {
2298            // Normalize -0.0 to 0.0 for consistent hashing
2299            let x = if vector.x == 0.0 { 0.0_f32 } else { vector.x };
2300            let y = if vector.y == 0.0 { 0.0_f32 } else { vector.y };
2301            let z = if vector.z == 0.0 { 0.0_f32 } else { vector.z };
2302            x.to_bits().hash(state);
2303            y.to_bits().hash(state);
2304            z.to_bits().hash(state);
2305        }
2306    }
2307}
2308
2309#[cfg(all(feature = "point3", feature = "vec_variants"))]
2310impl Hash for Point3Vec {
2311    fn hash<H: Hasher>(&self, state: &mut H) {
2312        self.0.len().hash(state);
2313        for point in &self.0 {
2314            // Normalize -0.0 to 0.0 for consistent hashing
2315            let x = if point.x == 0.0 { 0.0_f32 } else { point.x };
2316            let y = if point.y == 0.0 { 0.0_f32 } else { point.y };
2317            let z = if point.z == 0.0 { 0.0_f32 } else { point.z };
2318            x.to_bits().hash(state);
2319            y.to_bits().hash(state);
2320            z.to_bits().hash(state);
2321        }
2322    }
2323}
2324
2325#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
2326impl Hash for Matrix4Vec {
2327    fn hash<H: Hasher>(&self, state: &mut H) {
2328        self.0.len().hash(state);
2329        for matrix in &self.0 {
2330            for &element in mat4_iter(matrix) {
2331                // Normalize -0.0 to 0.0 for consistent hashing.
2332                let normalized = if element == 0.0 { 0.0_f64 } else { element };
2333                normalized.to_bits().hash(state);
2334            }
2335        }
2336    }
2337}
2338
2339// Implement DataTypeOps for all types
2340impl_data_ops!(Integer, "integer", DataType::Integer);
2341impl_data_ops!(Real, "real", DataType::Real);
2342impl_data_ops!(Boolean, "boolean", DataType::Boolean);
2343impl_data_ops!(String, "string", DataType::String);
2344impl_data_ops!(Color, "color", DataType::Color);
2345#[cfg(feature = "vector2")]
2346impl_data_ops!(Vector2, "vec2", DataType::Vector2);
2347#[cfg(feature = "vector3")]
2348impl_data_ops!(Vector3, "vec3", DataType::Vector3);
2349#[cfg(feature = "matrix3")]
2350impl_data_ops!(Matrix3, "mat3", DataType::Matrix3);
2351
2352impl_data_ops!(IntegerVec, "integer_vec", DataType::IntegerVec);
2353impl_data_ops!(RealVec, "real_vec", DataType::RealVec);
2354impl_data_ops!(BooleanVec, "boolean_vec", DataType::BooleanVec);
2355impl_data_ops!(StringVec, "string_vec", DataType::StringVec);
2356impl_data_ops!(ColorVec, "color_vec", DataType::ColorVec);
2357#[cfg(feature = "curves")]
2358impl_data_ops!(RealCurve, "real_curve", DataType::RealCurve);
2359#[cfg(feature = "curves")]
2360impl_data_ops!(ColorCurve, "color_curve", DataType::ColorCurve);
2361
2362#[cfg(all(feature = "vector2", feature = "vec_variants"))]
2363impl_data_ops!(Vector2Vec, "vec2_vec", DataType::Vector2Vec);
2364#[cfg(all(feature = "vector3", feature = "vec_variants"))]
2365impl_data_ops!(Vector3Vec, "vec3_vec", DataType::Vector3Vec);
2366#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
2367impl_data_ops!(Matrix3Vec, "mat3_vec", DataType::Matrix3Vec);
2368
2369// New data type implementations
2370#[cfg(feature = "normal3")]
2371impl_data_ops!(Normal3, "normal3", DataType::Normal3);
2372#[cfg(feature = "point3")]
2373impl_data_ops!(Point3, "point3", DataType::Point3);
2374#[cfg(feature = "matrix4")]
2375impl_data_ops!(Matrix4, "matrix4", DataType::Matrix4);
2376
2377#[cfg(all(feature = "normal3", feature = "vec_variants"))]
2378impl_data_ops!(Normal3Vec, "normal3_vec", DataType::Normal3Vec);
2379#[cfg(all(feature = "point3", feature = "vec_variants"))]
2380impl_data_ops!(Point3Vec, "point3_vec", DataType::Point3Vec);
2381#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
2382impl_data_ops!(Matrix4Vec, "matrix4_vec", DataType::Matrix4Vec);
2383
2384// Macro to implement TryFrom<Value> and TryFrom<&Value> for data types using
2385// try_convert
2386macro_rules! impl_try_from_value {
2387    ($type:ty, $data_type:expr, $variant:ident) => {
2388        impl TryFrom<Value> for $type {
2389            type Error = Error;
2390
2391            fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
2392                match value {
2393                    Value::Uniform(data) => {
2394                        let converted = data.try_convert($data_type)?;
2395                        match converted {
2396                            Data::$variant(v) => Ok(v),
2397                            _ => unreachable!(
2398                                "try_convert should return {} type",
2399                                stringify!($variant)
2400                            ),
2401                        }
2402                    }
2403                    Value::Animated(_) => Err(Error::AnimatedExtraction {
2404                        type_name: stringify!($type),
2405                    }),
2406                }
2407            }
2408        }
2409
2410        impl TryFrom<&Value> for $type {
2411            type Error = Error;
2412
2413            fn try_from(value: &Value) -> std::result::Result<Self, Self::Error> {
2414                match value {
2415                    Value::Uniform(data) => {
2416                        let converted = data.try_convert($data_type)?;
2417                        match converted {
2418                            Data::$variant(v) => Ok(v),
2419                            _ => unreachable!(
2420                                "try_convert should return {} type",
2421                                stringify!($variant)
2422                            ),
2423                        }
2424                    }
2425                    Value::Animated(_) => Err(Error::AnimatedExtraction {
2426                        type_name: stringify!($type),
2427                    }),
2428                }
2429            }
2430        }
2431    };
2432}
2433
2434// Apply the macro to all data types
2435impl_try_from_value!(Boolean, DataType::Boolean, Boolean);
2436impl_try_from_value!(Integer, DataType::Integer, Integer);
2437impl_try_from_value!(Real, DataType::Real, Real);
2438impl_try_from_value!(String, DataType::String, String);
2439impl_try_from_value!(Color, DataType::Color, Color);
2440#[cfg(feature = "vector2")]
2441impl_try_from_value!(Vector2, DataType::Vector2, Vector2);
2442#[cfg(feature = "vector3")]
2443impl_try_from_value!(Vector3, DataType::Vector3, Vector3);
2444#[cfg(feature = "matrix3")]
2445impl_try_from_value!(Matrix3, DataType::Matrix3, Matrix3);
2446impl_try_from_value!(BooleanVec, DataType::BooleanVec, BooleanVec);
2447impl_try_from_value!(IntegerVec, DataType::IntegerVec, IntegerVec);
2448impl_try_from_value!(RealVec, DataType::RealVec, RealVec);
2449impl_try_from_value!(StringVec, DataType::StringVec, StringVec);
2450impl_try_from_value!(ColorVec, DataType::ColorVec, ColorVec);
2451#[cfg(all(feature = "vector2", feature = "vec_variants"))]
2452impl_try_from_value!(Vector2Vec, DataType::Vector2Vec, Vector2Vec);
2453#[cfg(all(feature = "vector3", feature = "vec_variants"))]
2454impl_try_from_value!(Vector3Vec, DataType::Vector3Vec, Vector3Vec);
2455#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
2456impl_try_from_value!(Matrix3Vec, DataType::Matrix3Vec, Matrix3Vec);
2457
2458// New type TryFrom implementations
2459#[cfg(feature = "normal3")]
2460impl_try_from_value!(Normal3, DataType::Normal3, Normal3);
2461#[cfg(feature = "point3")]
2462impl_try_from_value!(Point3, DataType::Point3, Point3);
2463#[cfg(feature = "matrix4")]
2464impl_try_from_value!(Matrix4, DataType::Matrix4, Matrix4);
2465
2466#[cfg(all(feature = "normal3", feature = "vec_variants"))]
2467impl_try_from_value!(Normal3Vec, DataType::Normal3Vec, Normal3Vec);
2468#[cfg(all(feature = "point3", feature = "vec_variants"))]
2469impl_try_from_value!(Point3Vec, DataType::Point3Vec, Point3Vec);
2470#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
2471impl_try_from_value!(Matrix4Vec, DataType::Matrix4Vec, Matrix4Vec);
2472#[cfg(feature = "curves")]
2473impl_try_from_value!(RealCurve, DataType::RealCurve, RealCurve);
2474#[cfg(feature = "curves")]
2475impl_try_from_value!(ColorCurve, DataType::ColorCurve, ColorCurve);