1use core::num::Wrapping;
2use core::ops::Add;
3use num_traits::{
4 AsPrimitive, Bounded, ConstZero, FromPrimitive, Num, One, Signed, ToPrimitive, Zero,
5};
6
7#[cfg(not(feature = "std"))]
8#[allow(unused_imports)]
9use num_traits::float::FloatCore; use crate::{Accu, AsFloat, Q, Shift};
12
13impl<T: Zero, A, const F: i8> Zero for Q<T, A, F>
14where
15 Self: Add<Output = Self>,
16{
17 fn zero() -> Self {
18 Self::new(T::zero())
19 }
20
21 fn is_zero(&self) -> bool {
22 self.inner.is_zero()
23 }
24}
25
26impl<T: ConstZero, A, const F: i8> ConstZero for Q<T, A, F> {
27 const ZERO: Self = Self::new(T::ZERO);
28}
29
30macro_rules! impl_as_float {
31 ($ty:ident) => {
32 impl<T, A, const F: i8> AsPrimitive<Q<T, A, F>> for $ty
33 where
34 $ty: AsPrimitive<T>,
35 T: 'static + Copy,
36 A: 'static,
37 {
38 #[inline]
39 fn as_(self) -> Q<T, A, F> {
40 Q::new(
41 (self * const { 1.0 / Q::<T, A, F>::DELTA as $ty })
42 .round()
43 .as_(),
44 )
45 }
46 }
47
48 impl<T, A, const F: i8> AsPrimitive<$ty> for Q<T, A, F>
49 where
50 T: AsPrimitive<$ty>,
51 A: 'static,
52 {
53 #[inline]
54 fn as_(self) -> $ty {
55 self.inner.as_() * Self::DELTA as $ty
56 }
57 }
58 };
59}
60
61impl_as_float!(f32);
62impl_as_float!(f64);
63
64impl<T, A, const F: i8> AsPrimitive<Self> for Q<T, A, F>
65where
66 Self: Copy + 'static,
67{
68 #[inline]
69 fn as_(self) -> Self {
70 self
71 }
72}
73
74macro_rules! impl_accu_as_primitive {
75 ($($t:ty => $a:ty),* $(,)?) => {
76 $(
77 impl<const F: i8> AsPrimitive<$t> for Q<$a, $t, F> {
78 #[inline]
79 fn as_(self) -> $t {
80 self.quantize()
81 }
82 }
83 )*
84 };
85}
86
87impl_accu_as_primitive!(
88 i8 => i16,
89 i16 => i32,
90 i32 => i64,
91 i64 => i128,
92 u8 => u16,
93 u16 => u32,
94 u32 => u64,
95 u64 => u128,
96 Wrapping<i8> => Wrapping<i16>,
97 Wrapping<i16> => Wrapping<i32>,
98 Wrapping<i32> => Wrapping<i64>,
99 Wrapping<i64> => Wrapping<i128>,
100 Wrapping<u8> => Wrapping<u16>,
101 Wrapping<u16> => Wrapping<u32>,
102 Wrapping<u32> => Wrapping<u64>,
103 Wrapping<u64> => Wrapping<u128>,
104);
105
106impl<T: Bounded, A, const F: i8> Bounded for Q<T, A, F> {
107 #[inline]
108 fn min_value() -> Self {
109 Self::new(T::min_value())
110 }
111
112 #[inline]
113 fn max_value() -> Self {
114 Self::new(T::max_value())
115 }
116}
117
118impl<T, A, const F: i8> Num for Q<T, A, F>
119where
120 T: Num + Shift + Accu<A> + Copy + core::ops::Div<T, Output = T>,
121 A: Shift + Copy + core::ops::Div<A, Output = A>,
122 Self: One + Zero,
123{
124 type FromStrRadixErr = T::FromStrRadixErr;
125
126 #[inline]
127 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
128 T::from_str_radix(str, radix).map(Self::from_int)
129 }
130}
131
132impl<T: Shift + ToPrimitive + AsFloat, A, const F: i8> ToPrimitive for Q<T, A, F> {
133 #[inline]
134 fn to_i64(&self) -> Option<i64> {
135 self.trunc().to_i64()
136 }
137
138 #[inline]
139 fn to_i128(&self) -> Option<i128> {
140 self.trunc().to_i128()
141 }
142
143 #[inline]
144 fn to_u64(&self) -> Option<u64> {
145 self.trunc().to_u64()
146 }
147
148 #[inline]
149 fn to_u128(&self) -> Option<u128> {
150 self.trunc().to_u128()
151 }
152
153 #[inline]
154 fn to_f32(&self) -> Option<f32> {
155 Some((*self).as_f32())
156 }
157
158 #[inline]
159 fn to_f64(&self) -> Option<f64> {
160 Some((*self).as_f64())
161 }
162}
163
164impl<T, A, const F: i8> FromPrimitive for Q<T, A, F>
165where
166 T: 'static + Copy + FromPrimitive + Shift,
167 A: 'static,
168 f32: AsPrimitive<Q<T, A, F>>,
169 f64: AsPrimitive<Q<T, A, F>>,
170 Self: Copy + 'static,
171{
172 #[inline]
173 fn from_i64(n: i64) -> Option<Self> {
174 T::from_i64(n).map(Self::from_int)
175 }
176
177 #[inline]
178 fn from_i128(n: i128) -> Option<Self> {
179 T::from_i128(n).map(Self::from_int)
180 }
181
182 #[inline]
183 fn from_u64(n: u64) -> Option<Self> {
184 T::from_u64(n).map(Self::from_int)
185 }
186
187 #[inline]
188 fn from_u128(n: u128) -> Option<Self> {
189 T::from_u128(n).map(Self::from_int)
190 }
191
192 #[inline]
193 fn from_f32(n: f32) -> Option<Self> {
194 Some(Self::from_f32(n))
195 }
196
197 #[inline]
198 fn from_f64(n: f64) -> Option<Self> {
199 Some(Self::from_f64(n))
200 }
201}
202
203macro_rules! impl_signed_q {
204 ($($ty:ty),* $(,)?) => {
205 $(
206 impl<A, const F: i8> Signed for Q<$ty, A, F>
207 where
208 Self: Num + core::ops::Neg<Output = Self>,
209 {
210 #[inline]
211 fn abs(&self) -> Self {
212 Self::new(self.inner.abs())
213 }
214
215 #[inline]
216 fn abs_sub(&self, other: &Self) -> Self {
217 Self::new(self.inner.abs_sub(&other.inner))
218 }
219
220 #[inline]
221 fn signum(&self) -> Self {
222 match Signed::signum(&self.inner) {
223 1 => Self::one(),
224 -1 => -Self::one(),
225 _ => Self::zero(),
226 }
227 }
228
229 #[inline]
230 fn is_positive(&self) -> bool {
231 self.inner > 0
232 }
233
234 #[inline]
235 fn is_negative(&self) -> bool {
236 self.inner < 0
237 }
238 }
239
240 impl<A, const F: i8> Signed for Q<Wrapping<$ty>, A, F>
241 where
242 Self: Num + core::ops::Neg<Output = Self>,
243 {
244 #[inline]
245 fn abs(&self) -> Self {
246 Self::new(Wrapping(self.inner.0.abs()))
247 }
248
249 #[inline]
250 fn abs_sub(&self, other: &Self) -> Self {
251 Self::new(self.inner.abs_sub(&other.inner))
252 }
253
254 #[inline]
255 fn signum(&self) -> Self {
256 match Signed::signum(&self.inner) {
257 Wrapping(1) => Self::one(),
258 Wrapping(-1) => -Self::one(),
259 Wrapping(_) => Self::zero(),
260 }
261 }
262
263 #[inline]
264 fn is_positive(&self) -> bool {
265 self.inner.0.is_positive()
266 }
267
268 #[inline]
269 fn is_negative(&self) -> bool {
270 self.inner.0.is_negative()
271 }
272 }
273 )*
274 };
275}
276
277impl_signed_q!(i8, i16, i32, i64);