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