make ulp testing code more generic
[vector-math.git] / src / prim.rs
1 use crate::{
2 f16::F16,
3 traits::{ConvertFrom, ConvertTo},
4 };
5 use core::{fmt, hash, ops};
6
7 mod sealed {
8 use crate::f16::F16;
9
10 pub trait Sealed {}
11 impl Sealed for F16 {}
12 impl Sealed for f32 {}
13 impl Sealed for f64 {}
14 impl Sealed for u8 {}
15 impl Sealed for u16 {}
16 impl Sealed for u32 {}
17 impl Sealed for u64 {}
18 impl Sealed for i8 {}
19 impl Sealed for i16 {}
20 impl Sealed for i32 {}
21 impl Sealed for i64 {}
22 }
23
24 pub trait PrimBase:
25 sealed::Sealed
26 + Copy
27 + 'static
28 + Send
29 + Sync
30 + PartialOrd
31 + fmt::Debug
32 + fmt::Display
33 + ops::Add<Output = Self>
34 + ops::Sub<Output = Self>
35 + ops::Mul<Output = Self>
36 + ops::Div<Output = Self>
37 + ops::Rem<Output = Self>
38 + ops::AddAssign
39 + ops::SubAssign
40 + ops::MulAssign
41 + ops::DivAssign
42 + ops::RemAssign
43 + ConvertFrom<i8>
44 + ConvertFrom<u8>
45 + ConvertFrom<i16>
46 + ConvertFrom<u16>
47 + ConvertFrom<F16>
48 + ConvertFrom<i32>
49 + ConvertFrom<u32>
50 + ConvertFrom<f32>
51 + ConvertFrom<i64>
52 + ConvertFrom<u64>
53 + ConvertFrom<f64>
54 + ConvertTo<i8>
55 + ConvertTo<u8>
56 + ConvertTo<i16>
57 + ConvertTo<u16>
58 + ConvertTo<F16>
59 + ConvertTo<i32>
60 + ConvertTo<u32>
61 + ConvertTo<f32>
62 + ConvertTo<i64>
63 + ConvertTo<u64>
64 + ConvertTo<f64>
65 {
66 }
67
68 pub trait PrimInt:
69 PrimBase
70 + Ord
71 + hash::Hash
72 + fmt::Binary
73 + fmt::LowerHex
74 + fmt::Octal
75 + fmt::UpperHex
76 + ops::BitAnd<Output = Self>
77 + ops::BitOr<Output = Self>
78 + ops::BitXor<Output = Self>
79 + ops::Shl<Output = Self>
80 + ops::Shr<Output = Self>
81 + ops::Not<Output = Self>
82 + ops::BitAndAssign
83 + ops::BitOrAssign
84 + ops::BitXorAssign
85 + ops::ShlAssign
86 + ops::ShrAssign
87 {
88 }
89
90 pub trait PrimUInt: PrimInt + ConvertFrom<Self::SignedType> {
91 type SignedType: PrimSInt<UnsignedType = Self> + ConvertFrom<Self>;
92 }
93
94 pub trait PrimSInt: PrimInt + ops::Neg<Output = Self> + ConvertFrom<Self::UnsignedType> {
95 type UnsignedType: PrimUInt<SignedType = Self> + ConvertFrom<Self>;
96 }
97
98 macro_rules! impl_int {
99 ($uint:ident, $sint:ident) => {
100 impl PrimBase for $uint {}
101 impl PrimBase for $sint {}
102 impl PrimInt for $uint {}
103 impl PrimInt for $sint {}
104 impl PrimUInt for $uint {
105 type SignedType = $sint;
106 }
107 impl PrimSInt for $sint {
108 type UnsignedType = $uint;
109 }
110 };
111 }
112
113 impl_int!(u8, i8);
114 impl_int!(u16, i16);
115 impl_int!(u32, i32);
116 impl_int!(u64, i64);
117
118 pub trait PrimFloat:
119 PrimBase + ops::Neg<Output = Self> + ConvertFrom<Self::BitsType> + ConvertFrom<Self::SignedBitsType>
120 {
121 type BitsType: PrimUInt<SignedType = Self::SignedBitsType> + ConvertFrom<Self>;
122 type SignedBitsType: PrimSInt<UnsignedType = Self::BitsType> + ConvertFrom<Self>;
123 const EXPONENT_BIAS_UNSIGNED: Self::BitsType;
124 const EXPONENT_BIAS_SIGNED: Self::SignedBitsType;
125 const SIGN_FIELD_WIDTH: Self::BitsType;
126 const EXPONENT_FIELD_WIDTH: Self::BitsType;
127 const MANTISSA_FIELD_WIDTH: Self::BitsType;
128 const SIGN_FIELD_SHIFT: Self::BitsType;
129 const EXPONENT_FIELD_SHIFT: Self::BitsType;
130 const MANTISSA_FIELD_SHIFT: Self::BitsType;
131 const SIGN_FIELD_MASK: Self::BitsType;
132 const EXPONENT_FIELD_MASK: Self::BitsType;
133 const MANTISSA_FIELD_MASK: Self::BitsType;
134 const IMPLICIT_MANTISSA_BIT: Self::BitsType;
135 const ZERO_SUBNORMAL_EXPONENT: Self::BitsType;
136 const NAN_INFINITY_EXPONENT: Self::BitsType;
137 const INFINITY_BITS: Self::BitsType;
138 const NAN_BITS: Self::BitsType;
139 fn is_nan(self) -> bool;
140 fn from_bits(bits: Self::BitsType) -> Self;
141 fn to_bits(self) -> Self::BitsType;
142 }
143
144 macro_rules! impl_float {
145 (
146 impl PrimFloat for $float:ident {
147 type BitsType = $bits_type:ident;
148 type SignedBitsType = $signed_bits_type:ident;
149 const EXPONENT_FIELD_WIDTH: u32 = $exponent_field_width:literal;
150 const MANTISSA_FIELD_WIDTH: u32 = $mantissa_field_width:literal;
151 }
152 ) => {
153 impl PrimBase for $float {}
154
155 impl PrimFloat for $float {
156 type BitsType = $bits_type;
157 type SignedBitsType = $signed_bits_type;
158 const EXPONENT_BIAS_UNSIGNED: Self::BitsType =
159 (1 << (Self::EXPONENT_FIELD_WIDTH - 1)) - 1;
160 const EXPONENT_BIAS_SIGNED: Self::SignedBitsType = Self::EXPONENT_BIAS_UNSIGNED as _;
161 const SIGN_FIELD_WIDTH: Self::BitsType = 1;
162 const EXPONENT_FIELD_WIDTH: Self::BitsType = $exponent_field_width;
163 const MANTISSA_FIELD_WIDTH: Self::BitsType = $mantissa_field_width;
164 const SIGN_FIELD_SHIFT: Self::BitsType =
165 Self::EXPONENT_FIELD_SHIFT + Self::EXPONENT_FIELD_WIDTH;
166 const EXPONENT_FIELD_SHIFT: Self::BitsType = Self::MANTISSA_FIELD_WIDTH;
167 const MANTISSA_FIELD_SHIFT: Self::BitsType = 0;
168 const SIGN_FIELD_MASK: Self::BitsType = 1 << Self::SIGN_FIELD_SHIFT;
169 const EXPONENT_FIELD_MASK: Self::BitsType =
170 ((1 << Self::EXPONENT_FIELD_WIDTH) - 1) << Self::EXPONENT_FIELD_SHIFT;
171 const MANTISSA_FIELD_MASK: Self::BitsType = (1 << Self::MANTISSA_FIELD_WIDTH) - 1;
172 const IMPLICIT_MANTISSA_BIT: Self::BitsType = 1 << Self::MANTISSA_FIELD_WIDTH;
173 const ZERO_SUBNORMAL_EXPONENT: Self::BitsType = 0;
174 const NAN_INFINITY_EXPONENT: Self::BitsType = (1 << Self::EXPONENT_FIELD_WIDTH) - 1;
175 const INFINITY_BITS: Self::BitsType =
176 Self::NAN_INFINITY_EXPONENT << Self::EXPONENT_FIELD_SHIFT;
177 const NAN_BITS: Self::BitsType =
178 Self::INFINITY_BITS | (1 << (Self::MANTISSA_FIELD_WIDTH - 1));
179 fn is_nan(self) -> bool {
180 $float::is_nan(self)
181 }
182 fn from_bits(bits: Self::BitsType) -> Self {
183 $float::from_bits(bits)
184 }
185 fn to_bits(self) -> Self::BitsType {
186 self.to_bits()
187 }
188 }
189 };
190 }
191
192 impl_float! {
193 impl PrimFloat for F16 {
194 type BitsType = u16;
195 type SignedBitsType = i16;
196 const EXPONENT_FIELD_WIDTH: u32 = 5;
197 const MANTISSA_FIELD_WIDTH: u32 = 10;
198 }
199 }
200
201 impl_float! {
202 impl PrimFloat for f32 {
203 type BitsType = u32;
204 type SignedBitsType = i32;
205 const EXPONENT_FIELD_WIDTH: u32 = 8;
206 const MANTISSA_FIELD_WIDTH: u32 = 23;
207 }
208 }
209
210 impl_float! {
211 impl PrimFloat for f64 {
212 type BitsType = u64;
213 type SignedBitsType = i64;
214 const EXPONENT_FIELD_WIDTH: u32 = 11;
215 const MANTISSA_FIELD_WIDTH: u32 = 52;
216 }
217 }