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
132#[inline]
135fn checked_scale<T: Shift + PartialEq>(value: T, shift: i8) -> Option<T> {
136 assert!(shift > i8::MIN, "shift must not be i8::MIN");
137 let scaled = value.shs(shift);
138 (shift <= 0 || scaled.shs(-shift) == value).then_some(scaled)
139}
140
141impl<T: Copy + ToPrimitive + AsFloat, A, const F: i8> ToPrimitive for Q<T, A, F> {
142 #[inline]
143 fn to_i64(&self) -> Option<i64> {
144 self.to_i128()?.to_i64()
145 }
146
147 #[inline]
148 fn to_i128(&self) -> Option<i128> {
149 checked_scale(self.inner.to_i128()?, const { -F })
150 }
151
152 #[inline]
153 fn to_u64(&self) -> Option<u64> {
154 self.to_u128()?.to_u64()
155 }
156
157 #[inline]
158 fn to_u128(&self) -> Option<u128> {
159 checked_scale(self.inner.to_u128()?, const { -F })
160 }
161
162 #[inline]
163 fn to_f32(&self) -> Option<f32> {
164 Some((*self).as_f32())
165 }
166
167 #[inline]
168 fn to_f64(&self) -> Option<f64> {
169 Some((*self).as_f64())
170 }
171}
172
173impl<T, A, const F: i8> FromPrimitive for Q<T, A, F>
174where
175 T: FromPrimitive,
176{
177 #[inline]
178 fn from_i64(n: i64) -> Option<Self> {
179 Self::from_i128(n as i128)
180 }
181
182 #[inline]
183 fn from_i128(n: i128) -> Option<Self> {
184 T::from_i128(checked_scale(n, F)?).map(Self::new)
185 }
186
187 #[inline]
188 fn from_u64(n: u64) -> Option<Self> {
189 Self::from_u128(n as u128)
190 }
191
192 #[inline]
193 fn from_u128(n: u128) -> Option<Self> {
194 T::from_u128(checked_scale(n, F)?).map(Self::new)
195 }
196
197 #[inline]
198 fn from_f32(n: f32) -> Option<Self> {
199 T::from_f32((n * const { 1.0 / Self::DELTA }).round()).map(Self::new)
200 }
201
202 #[inline]
203 fn from_f64(n: f64) -> Option<Self> {
204 T::from_f64((n * const { 1.0 / Self::DELTA as f64 }).round()).map(Self::new)
205 }
206}
207
208macro_rules! impl_signed_q {
209 ($($ty:ty),* $(,)?) => {
210 $(
211 impl<A, const F: i8> Signed for Q<$ty, A, F>
212 where
213 Self: Num + core::ops::Neg<Output = Self>,
214 {
215 #[inline]
216 fn abs(&self) -> Self {
217 Self::new(self.inner.abs())
218 }
219
220 #[inline]
221 fn abs_sub(&self, other: &Self) -> Self {
222 Self::new(self.inner.abs_sub(&other.inner))
223 }
224
225 #[inline]
226 fn signum(&self) -> Self {
227 match Signed::signum(&self.inner) {
228 1 => Self::one(),
229 -1 => -Self::one(),
230 _ => Self::zero(),
231 }
232 }
233
234 #[inline]
235 fn is_positive(&self) -> bool {
236 self.inner > 0
237 }
238
239 #[inline]
240 fn is_negative(&self) -> bool {
241 self.inner < 0
242 }
243 }
244
245 impl<A, const F: i8> Signed for Q<Wrapping<$ty>, A, F>
246 where
247 Self: Num + core::ops::Neg<Output = Self>,
248 {
249 #[inline]
250 fn abs(&self) -> Self {
251 Self::new(Wrapping(self.inner.0.abs()))
252 }
253
254 #[inline]
255 fn abs_sub(&self, other: &Self) -> Self {
256 Self::new(self.inner.abs_sub(&other.inner))
257 }
258
259 #[inline]
260 fn signum(&self) -> Self {
261 match Signed::signum(&self.inner) {
262 Wrapping(1) => Self::one(),
263 Wrapping(-1) => -Self::one(),
264 Wrapping(_) => Self::zero(),
265 }
266 }
267
268 #[inline]
269 fn is_positive(&self) -> bool {
270 self.inner.0.is_positive()
271 }
272
273 #[inline]
274 fn is_negative(&self) -> bool {
275 self.inner.0.is_negative()
276 }
277 }
278 )*
279 };
280}
281
282impl_signed_q!(i8, i16, i32, i64);