1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use super::Scalar;
use crate::bindings::{Primitive, PrimitiveMatrices, Vector};

/// The name of a coordinate space.
///
/// The unit is used to give vector types a "tag" so they can be distinguished
/// at compile time.
///
/// The unit also determines which type is used as the scalar for that
/// coordinate space. This is in contrast to a crate like
/// [euclid](https://docs.rs/euclid/latest/euclid), where the unit and the
/// scalar are separate type parameters to each vector type.
///
/// Note that primitive scalars (`f32`, `f64`, `i32`, and `u32`) also implement
/// `Unit`. This allows them to function as the "untyped" vector variants.
///
/// #### Example
/// ```rust
/// # use glamour::prelude::*;
/// struct MyTag;
///
/// impl Unit for MyTag {
///     // All types that have `MyTag` as the unit will internally be based
///     // on `f32`.
///     type Scalar = f32;
/// }
///
/// // This will be `glam::Vec2` internally, and can be constructed directly
/// // with `f32` literals.
/// let v: Vector2<MyTag> = Vector2 { x: 1.0, y: 2.0 };
/// assert_eq!(v[0], v.x);
/// ```
pub trait Unit: 'static {
    /// The type of scalar in this space. This can be any type that implements
    /// `Scalar`, such as the primitives `i32`, `u32`, `f32`, or `f64`, but also
    /// custom scalar types that implement [`Scalar`].
    type Scalar: Scalar;

    /// Human-readable name of this coordinate space, used in debugging.
    #[must_use]
    fn name() -> Option<&'static str> {
        None
    }
}

impl Unit for f32 {
    type Scalar = f32;
    fn name() -> Option<&'static str> {
        Some("f32")
    }
}

impl Unit for f64 {
    type Scalar = f64;
    fn name() -> Option<&'static str> {
        Some("f64")
    }
}

impl Unit for i32 {
    type Scalar = i32;
    fn name() -> Option<&'static str> {
        Some("i32")
    }
}

impl Unit for u32 {
    type Scalar = u32;
    fn name() -> Option<&'static str> {
        Some("u32")
    }
}

/// Shorthand to go from a `Unit` type to its associated primitives (through the
/// scalar).
pub trait UnitTypes: Unit<Scalar = Self::UnitScalar> {
    /// `Self::Scalar` needed to define trait bounds on the associated type.
    type UnitScalar: Scalar<Primitive = Self::Primitive>;
    /// Shorthand for `<Self::Scalar as Scalar>::Primitive`.
    type Primitive: Primitive<Vec2 = Self::Vec2, Vec3 = Self::Vec3, Vec4 = Self::Vec4>;

    /// Fundamental 2D vector type.
    type Vec2: Vector<2, Scalar = Self::Primitive, Mask = glam::BVec2>;
    /// Fundamental 2D vector type.
    type Vec3: Vector<3, Scalar = Self::Primitive, Mask = glam::BVec3A>;
    /// Fundamental 2D vector type.
    type Vec4: Vector<4, Scalar = Self::Primitive, Mask = glam::BVec4A>;
}

impl<T> UnitTypes for T
where
    T: Unit,
{
    type UnitScalar = T::Scalar;
    type Primitive = <T::Scalar as Scalar>::Primitive;
    type Vec2 = <Self::Primitive as Primitive>::Vec2;
    type Vec3 = <Self::Primitive as Primitive>::Vec3;
    type Vec4 = <Self::Primitive as Primitive>::Vec4;
}

/// Shorthand to go from a `Unit` to its corresponding `Matrix` implementations
/// (through `Scalar::Primitive`).
pub trait UnitMatrices:
    UnitTypes<
    Scalar = Self::UnitMatrixScalar,
    UnitScalar = Self::UnitMatrixScalar,
    Primitive = Self::UnitMatrixPrimitive,
>
{
    /// Same as `Unit::Scalar`.
    type UnitMatrixScalar: Scalar<Primitive = Self::UnitMatrixPrimitive>;
    /// Same as `UnitTypes::Primitive` and `Unit::Scalar::Primitive`.
    type UnitMatrixPrimitive: Primitive<Vec2 = Self::Vec2, Vec3 = Self::Vec3, Vec4 = Self::Vec4>
        + PrimitiveMatrices<Mat2 = Self::Mat2, Mat3 = Self::Mat3, Mat4 = Self::Mat4>;
    /// Either [`glam::Mat2`] or [`glam::DMat2`].
    type Mat2: crate::bindings::Matrix2<
        Scalar = Self::Primitive,
        Vec2 = Self::Vec2,
        Vec3 = Self::Vec3,
        Vec4 = Self::Vec4,
    >;
    /// Either [`glam::Mat3`] or [`glam::DMat3`].
    type Mat3: crate::bindings::Matrix3<
        Scalar = Self::Primitive,
        Vec2 = Self::Vec2,
        Vec3 = Self::Vec3,
        Vec4 = Self::Vec4,
    >;
    /// Either [`glam::Mat4`] or [`glam::DMat4`].
    type Mat4: crate::bindings::Matrix4<
        Scalar = Self::Primitive,
        Vec2 = Self::Vec2,
        Vec3 = Self::Vec3,
        Vec4 = Self::Vec4,
    >;
}

impl<T> UnitMatrices for T
where
    T: UnitTypes,
    T::Primitive: PrimitiveMatrices,
{
    type UnitMatrixScalar = Self::UnitScalar;
    type UnitMatrixPrimitive = T::Primitive;
    type Mat2 = <T::Primitive as PrimitiveMatrices>::Mat2;
    type Mat3 = <T::Primitive as PrimitiveMatrices>::Mat3;
    type Mat4 = <T::Primitive as PrimitiveMatrices>::Mat4;
}