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