Skip to main content

optic_render/asset/attr/
typ.rs

1use optic_core::ATTRType;
2
3/// Trait for types that can be used as vertex or instance attribute data.
4///
5/// Implemented for `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `f32`, `f64` and
6/// their fixed-size arrays `[T; 2]`, `[T; 3]`, `[T; 4]`.
7///
8/// # Constants
9///
10/// * [`DataType::ATTR_FORMAT`] — the GL attribute type enum
11/// * [`DataType::BYTE_COUNT`] — size of one scalar element in bytes
12/// * [`DataType::ELEM_COUNT`] — number of scalar elements (1 for scalars, N for arrays)
13///
14/// # Example
15///
16/// ```
17/// use optic_render::asset::attr::DataType;
18///
19/// assert_eq!(<f32 as DataType>::BYTE_COUNT, 4);
20/// assert_eq!(<[f32; 3] as DataType>::ELEM_COUNT, 3);
21/// ```
22pub trait DataType {
23    const ATTR_FORMAT: ATTRType;
24    const BYTE_COUNT: usize;
25    const ELEM_COUNT: usize;
26    fn u8ify(&self) -> Vec<u8>;
27}
28
29macro_rules! u8ify_impl {
30    ([$t:ty; $s:literal]) => {
31        fn u8ify(&self) -> Vec<u8> {
32            let mut vec = Vec::new();
33            for elem in self.iter() {
34                vec.extend_from_slice(&elem.to_ne_bytes());
35            }
36            vec
37        }
38    };
39    ($t:ty) => {
40        fn u8ify(&self) -> Vec<u8> {
41            self.to_ne_bytes().to_vec()
42        }
43    };
44}
45
46macro_rules! datatype {
47    ($type:ty, $attr_format:expr, $byte_count:expr) => {
48        impl DataType for $type {
49            const ATTR_FORMAT: ATTRType = $attr_format;
50            const BYTE_COUNT: usize = $byte_count;
51            const ELEM_COUNT: usize = 1;
52            u8ify_impl!($type);
53        }
54
55        impl DataType for [$type; 2] {
56            const ATTR_FORMAT: ATTRType = $attr_format;
57            const BYTE_COUNT: usize = $byte_count;
58            const ELEM_COUNT: usize = 2;
59            u8ify_impl!([$type; 2]);
60        }
61
62        impl DataType for [$type; 3] {
63            const ATTR_FORMAT: ATTRType = $attr_format;
64            const BYTE_COUNT: usize = $byte_count;
65            const ELEM_COUNT: usize = 3;
66            u8ify_impl!([$type; 3]);
67        }
68
69        impl DataType for [$type; 4] {
70            const ATTR_FORMAT: ATTRType = $attr_format;
71            const BYTE_COUNT: usize = $byte_count;
72            const ELEM_COUNT: usize = 4;
73            u8ify_impl!([$type; 4]);
74        }
75    };
76}
77
78datatype!(i8, ATTRType::I8, 1);
79datatype!(u8, ATTRType::U8, 1);
80datatype!(i16, ATTRType::I16, 2);
81datatype!(u16, ATTRType::U16, 2);
82datatype!(i32, ATTRType::I32, 4);
83datatype!(u32, ATTRType::U32, 4);
84datatype!(f32, ATTRType::F32, 4);
85datatype!(f64, ATTRType::F64, 8);
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn f32_scalar_u8ify() {
93        let v: f32 = 1.0;
94        let bytes = v.u8ify();
95        assert_eq!(bytes.len(), 4);
96    }
97
98    #[test]
99    fn f32_array2_u8ify() {
100        let v: [f32; 2] = [1.0, 2.0];
101        let bytes = v.u8ify();
102        assert_eq!(bytes.len(), 8);
103    }
104
105    #[test]
106    fn f32_array3_u8ify() {
107        let v: [f32; 3] = [1.0, 2.0, 3.0];
108        let bytes = v.u8ify();
109        assert_eq!(bytes.len(), 12);
110    }
111
112    #[test]
113    fn f32_array4_u8ify() {
114        let v: [f32; 4] = [1.0, 2.0, 3.0, 4.0];
115        let bytes = v.u8ify();
116        assert_eq!(bytes.len(), 16);
117    }
118
119    #[test]
120    fn u32_scalar_u8ify() {
121        let v: u32 = 0x12345678;
122        let bytes = v.u8ify();
123        assert_eq!(bytes.len(), 4);
124    }
125
126    #[test]
127    fn u32_array2_u8ify() {
128        let v: [u32; 2] = [1, 2];
129        let bytes = v.u8ify();
130        assert_eq!(bytes.len(), 8);
131    }
132
133    #[test]
134    fn u8_scalar_u8ify() {
135        let v: u8 = 255;
136        let bytes = v.u8ify();
137        assert_eq!(bytes.len(), 1);
138    }
139
140    #[test]
141    fn i32_scalar_u8ify() {
142        let v: i32 = -42;
143        let bytes = v.u8ify();
144        assert_eq!(bytes.len(), 4);
145    }
146
147    #[test]
148    fn f64_scalar_u8ify() {
149        let v: f64 = 3.14159;
150        let bytes = v.u8ify();
151        assert_eq!(bytes.len(), 8);
152    }
153
154    #[test]
155    fn const_byte_count() {
156        assert_eq!(<u8 as DataType>::BYTE_COUNT, 1);
157        assert_eq!(<i8 as DataType>::BYTE_COUNT, 1);
158        assert_eq!(<u16 as DataType>::BYTE_COUNT, 2);
159        assert_eq!(<i16 as DataType>::BYTE_COUNT, 2);
160        assert_eq!(<u32 as DataType>::BYTE_COUNT, 4);
161        assert_eq!(<i32 as DataType>::BYTE_COUNT, 4);
162        assert_eq!(<f32 as DataType>::BYTE_COUNT, 4);
163        assert_eq!(<f64 as DataType>::BYTE_COUNT, 8);
164    }
165
166    #[test]
167    fn const_elem_count() {
168        assert_eq!(<[f32; 3] as DataType>::ELEM_COUNT, 3);
169        assert_eq!(<[f32; 2] as DataType>::ELEM_COUNT, 2);
170        assert_eq!(<[f32; 4] as DataType>::ELEM_COUNT, 4);
171        assert_eq!(<u32 as DataType>::ELEM_COUNT, 1);
172    }
173}