Skip to main content

dsp_fixedpoint/
num_traits_impl.rs

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; // .round()
10
11use 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);