fixed/
impl_num_traits.rs

1// Copyright © 2018–2025 Trevor Spiteri
2
3// This library is free software: you can redistribute it and/or
4// modify it under the terms of either
5//
6//   * the Apache License, Version 2.0 or
7//   * the MIT License
8//
9// at your option.
10//
11// You should have recieved copies of the Apache License and the MIT
12// License along with the library. If not, see
13// <https://www.apache.org/licenses/LICENSE-2.0> and
14// <https://opensource.org/licenses/MIT>.
15
16use crate::consts;
17use crate::traits::Fixed;
18use crate::types::extra::{
19    IsLessOrEqual, LeEqU8, LeEqU16, LeEqU32, LeEqU64, LeEqU128, True, U6, U7, U14, U15, U30, U31,
20    U62, U63, U126, U127,
21};
22use crate::{
23    FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32, FixedU64,
24    FixedU128, ParseFixedError,
25};
26use core::fmt::{Display, Formatter, Result as FmtResult};
27use num_traits::bounds::Bounded;
28use num_traits::cast::{FromPrimitive, ToPrimitive};
29use num_traits::float::FloatConst;
30use num_traits::identities::{ConstOne, ConstZero, One, Zero};
31
32use core::error::Error;
33use num_traits::Num;
34use num_traits::ops::bytes::{FromBytes, ToBytes};
35use num_traits::ops::checked::{
36    CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
37};
38use num_traits::ops::inv::Inv;
39use num_traits::ops::mul_add::{MulAdd, MulAddAssign};
40use num_traits::ops::overflowing::{OverflowingAdd, OverflowingMul, OverflowingSub};
41use num_traits::ops::saturating::{SaturatingAdd, SaturatingMul, SaturatingSub};
42use num_traits::ops::wrapping::{
43    WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
44};
45use num_traits::sign::{Signed, Unsigned};
46
47/// An error which can be returned when parsing a fixed-point number
48/// with a given radix.
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum RadixParseFixedError {
51    /// The radix is not 2, 8, 10 or 16.
52    UnsupportedRadix,
53    /// The string could not be parsed as a fixed-point number.
54    ParseFixedError(ParseFixedError),
55}
56
57impl RadixParseFixedError {
58    fn message(&self) -> &str {
59        match self {
60            RadixParseFixedError::UnsupportedRadix => "unsupported radix",
61            RadixParseFixedError::ParseFixedError(e) => e.message(),
62        }
63    }
64}
65
66impl Display for RadixParseFixedError {
67    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
68        Display::fmt(self.message(), f)
69    }
70}
71
72impl Error for RadixParseFixedError {
73    fn description(&self) -> &str {
74        self.message()
75    }
76}
77
78macro_rules! impl_traits {
79    ($Fixed:ident, $LeEqU:ident, $OneMaxFrac:ident, $Signedness:ident) => {
80        impl<Frac> Bounded for $Fixed<Frac> {
81            #[inline]
82            fn min_value() -> Self {
83                Self::MIN
84            }
85            #[inline]
86            fn max_value() -> Self {
87                Self::MAX
88            }
89        }
90
91        impl<Frac> Zero for $Fixed<Frac> {
92            #[inline]
93            fn zero() -> Self {
94                Self::ZERO
95            }
96            #[inline]
97            fn is_zero(&self) -> bool {
98                (*self).is_zero()
99            }
100        }
101
102        impl<Frac> ConstZero for $Fixed<Frac> {
103            const ZERO: Self = Self::ZERO;
104        }
105
106        impl<Frac: $LeEqU> One for $Fixed<Frac>
107        where
108            Frac: IsLessOrEqual<$OneMaxFrac, Output = True>,
109        {
110            #[inline]
111            fn one() -> Self {
112                Self::ONE
113            }
114        }
115
116        impl<Frac: $LeEqU> ConstOne for $Fixed<Frac>
117        where
118            Frac: IsLessOrEqual<$OneMaxFrac, Output = True>,
119        {
120            const ONE: Self = Self::ONE;
121        }
122
123        impl<Frac: $LeEqU> Num for $Fixed<Frac>
124        where
125            Frac: IsLessOrEqual<$OneMaxFrac, Output = True>,
126        {
127            type FromStrRadixErr = RadixParseFixedError;
128
129            #[inline]
130            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
131                match radix {
132                    2 => Self::from_str_binary(str),
133                    8 => Self::from_str_octal(str),
134                    10 => str.parse(),
135                    16 => Self::from_str_hex(str),
136                    _ => return Err(RadixParseFixedError::UnsupportedRadix),
137                }
138                .map_err(RadixParseFixedError::ParseFixedError)
139            }
140        }
141
142        impl<Frac: $LeEqU> Inv for $Fixed<Frac> {
143            type Output = Self;
144            #[inline]
145            fn inv(self) -> Self::Output {
146                self.recip()
147            }
148        }
149
150        if_signed! {
151            $Signedness;
152            impl<Frac: $LeEqU> Signed for $Fixed<Frac>
153            where
154                Frac: IsLessOrEqual<$OneMaxFrac, Output = True>,
155            {
156                #[inline]
157                fn abs(&self) -> Self {
158                    (*self).abs()
159                }
160                #[inline]
161                fn abs_sub(&self, other: &Self) -> Self {
162                    if *self < *other {
163                        Self::ZERO
164                    } else {
165                        *self - *other
166                    }
167                }
168                #[inline]
169                fn signum(&self) -> Self {
170                    (*self).signum()
171                }
172                #[inline]
173                fn is_positive(&self) -> bool {
174                    (*self).is_positive()
175                }
176                #[inline]
177                fn is_negative(&self) -> bool {
178                    (*self).is_negative()
179                }
180            }
181        }
182
183        if_unsigned! {
184            $Signedness;
185            impl<Frac: $LeEqU> Unsigned for $Fixed<Frac>
186            where
187                Frac: IsLessOrEqual<$OneMaxFrac, Output = True>,
188            {
189            }
190        }
191
192        impl<Frac> CheckedAdd for $Fixed<Frac> {
193            #[inline]
194            fn checked_add(&self, v: &Self) -> Option<Self> {
195                (*self).checked_add(*v)
196            }
197        }
198
199        impl<Frac> CheckedSub for $Fixed<Frac> {
200            #[inline]
201            fn checked_sub(&self, v: &Self) -> Option<Self> {
202                (*self).checked_sub(*v)
203            }
204        }
205
206        impl<Frac> CheckedNeg for $Fixed<Frac> {
207            #[inline]
208            fn checked_neg(&self) -> Option<Self> {
209                (*self).checked_neg()
210            }
211        }
212
213        impl<Frac: $LeEqU> CheckedMul for $Fixed<Frac> {
214            #[inline]
215            fn checked_mul(&self, v: &Self) -> Option<Self> {
216                (*self).checked_mul(*v)
217            }
218        }
219
220        impl<Frac: $LeEqU> CheckedDiv for $Fixed<Frac> {
221            #[inline]
222            fn checked_div(&self, v: &Self) -> Option<Self> {
223                (*self).checked_div(*v)
224            }
225        }
226
227        impl<Frac> CheckedRem for $Fixed<Frac> {
228            #[inline]
229            fn checked_rem(&self, v: &Self) -> Option<Self> {
230                (*self).checked_rem(*v)
231            }
232        }
233
234        impl<Frac> CheckedShl for $Fixed<Frac> {
235            #[inline]
236            fn checked_shl(&self, rhs: u32) -> Option<Self> {
237                (*self).checked_shl(rhs)
238            }
239        }
240
241        impl<Frac> CheckedShr for $Fixed<Frac> {
242            #[inline]
243            fn checked_shr(&self, rhs: u32) -> Option<Self> {
244                (*self).checked_shr(rhs)
245            }
246        }
247
248        impl<Frac> SaturatingAdd for $Fixed<Frac> {
249            #[inline]
250            fn saturating_add(&self, v: &Self) -> Self {
251                (*self).saturating_add(*v)
252            }
253        }
254
255        impl<Frac> SaturatingSub for $Fixed<Frac> {
256            #[inline]
257            fn saturating_sub(&self, v: &Self) -> Self {
258                (*self).saturating_sub(*v)
259            }
260        }
261
262        impl<Frac: $LeEqU> SaturatingMul for $Fixed<Frac> {
263            #[inline]
264            fn saturating_mul(&self, v: &Self) -> Self {
265                (*self).saturating_mul(*v)
266            }
267        }
268
269        impl<Frac> WrappingAdd for $Fixed<Frac> {
270            #[inline]
271            fn wrapping_add(&self, v: &Self) -> Self {
272                (*self).wrapping_add(*v)
273            }
274        }
275
276        impl<Frac> WrappingSub for $Fixed<Frac> {
277            #[inline]
278            fn wrapping_sub(&self, v: &Self) -> Self {
279                (*self).wrapping_sub(*v)
280            }
281        }
282
283        impl<Frac> WrappingNeg for $Fixed<Frac> {
284            #[inline]
285            fn wrapping_neg(&self) -> Self {
286                (*self).wrapping_neg()
287            }
288        }
289
290        impl<Frac: $LeEqU> WrappingMul for $Fixed<Frac> {
291            #[inline]
292            fn wrapping_mul(&self, v: &Self) -> Self {
293                (*self).wrapping_mul(*v)
294            }
295        }
296
297        impl<Frac> WrappingShl for $Fixed<Frac> {
298            #[inline]
299            fn wrapping_shl(&self, rhs: u32) -> Self {
300                (*self).wrapping_shl(rhs)
301            }
302        }
303
304        impl<Frac> WrappingShr for $Fixed<Frac> {
305            #[inline]
306            fn wrapping_shr(&self, rhs: u32) -> Self {
307                (*self).wrapping_shr(rhs)
308            }
309        }
310
311        impl<Frac> OverflowingAdd for $Fixed<Frac> {
312            #[inline]
313            fn overflowing_add(&self, v: &Self) -> (Self, bool) {
314                (*self).overflowing_add(*v)
315            }
316        }
317
318        impl<Frac> OverflowingSub for $Fixed<Frac> {
319            #[inline]
320            fn overflowing_sub(&self, v: &Self) -> (Self, bool) {
321                (*self).overflowing_sub(*v)
322            }
323        }
324
325        impl<Frac: $LeEqU> OverflowingMul for $Fixed<Frac> {
326            #[inline]
327            fn overflowing_mul(&self, v: &Self) -> (Self, bool) {
328                (*self).overflowing_mul(*v)
329            }
330        }
331
332        impl<Frac, MulFrac: $LeEqU> MulAdd<$Fixed<MulFrac>> for $Fixed<Frac> {
333            type Output = $Fixed<Frac>;
334            #[inline]
335            fn mul_add(self, a: $Fixed<MulFrac>, b: $Fixed<Frac>) -> $Fixed<Frac> {
336                self.mul_add(a, b)
337            }
338        }
339
340        impl<Frac, MulFrac: $LeEqU> MulAddAssign<$Fixed<MulFrac>> for $Fixed<Frac> {
341            #[inline]
342            fn mul_add_assign(&mut self, a: $Fixed<MulFrac>, b: $Fixed<Frac>) {
343                *self = self.mul_add(a, b)
344            }
345        }
346
347        impl<Frac: $LeEqU> FloatConst for $Fixed<Frac> {
348            #[inline]
349            fn E() -> Self {
350                consts::E.to_num()
351            }
352            #[inline]
353            fn FRAC_1_PI() -> Self {
354                consts::FRAC_1_PI.to_num()
355            }
356            #[inline]
357            fn FRAC_1_SQRT_2() -> Self {
358                consts::FRAC_1_SQRT_2.to_num()
359            }
360            #[inline]
361            fn FRAC_2_PI() -> Self {
362                consts::FRAC_2_PI.to_num()
363            }
364            #[inline]
365            fn FRAC_2_SQRT_PI() -> Self {
366                consts::FRAC_2_SQRT_PI.to_num()
367            }
368            #[inline]
369            fn FRAC_PI_2() -> Self {
370                consts::FRAC_PI_2.to_num()
371            }
372            #[inline]
373            fn FRAC_PI_3() -> Self {
374                consts::FRAC_PI_3.to_num()
375            }
376            #[inline]
377            fn FRAC_PI_4() -> Self {
378                consts::FRAC_PI_4.to_num()
379            }
380            #[inline]
381            fn FRAC_PI_6() -> Self {
382                consts::FRAC_PI_6.to_num()
383            }
384            #[inline]
385            fn FRAC_PI_8() -> Self {
386                consts::FRAC_PI_8.to_num()
387            }
388            #[inline]
389            fn LN_10() -> Self {
390                consts::LN_10.to_num()
391            }
392            #[inline]
393            fn LN_2() -> Self {
394                consts::LN_2.to_num()
395            }
396            #[inline]
397            fn LOG10_E() -> Self {
398                consts::LOG10_E.to_num()
399            }
400            #[inline]
401            fn LOG2_E() -> Self {
402                consts::LOG2_E.to_num()
403            }
404            #[inline]
405            fn PI() -> Self {
406                consts::PI.to_num()
407            }
408            #[inline]
409            fn SQRT_2() -> Self {
410                consts::SQRT_2.to_num()
411            }
412            #[inline]
413            fn TAU() -> Self {
414                consts::TAU.to_num()
415            }
416            #[inline]
417            fn LOG10_2() -> Self {
418                consts::LOG10_2.to_num()
419            }
420            #[inline]
421            fn LOG2_10() -> Self {
422                consts::LOG2_10.to_num()
423            }
424        }
425
426        impl<Frac: $LeEqU> ToPrimitive for $Fixed<Frac> {
427            #[inline]
428            fn to_i64(&self) -> Option<i64> {
429                self.checked_to_num()
430            }
431            #[inline]
432            fn to_u64(&self) -> Option<u64> {
433                self.checked_to_num()
434            }
435            #[inline]
436            fn to_isize(&self) -> Option<isize> {
437                self.checked_to_num()
438            }
439            #[inline]
440            fn to_i8(&self) -> Option<i8> {
441                self.checked_to_num()
442            }
443            #[inline]
444            fn to_i16(&self) -> Option<i16> {
445                self.checked_to_num()
446            }
447            #[inline]
448            fn to_i32(&self) -> Option<i32> {
449                self.checked_to_num()
450            }
451            #[inline]
452            fn to_i128(&self) -> Option<i128> {
453                self.checked_to_num()
454            }
455            #[inline]
456            fn to_usize(&self) -> Option<usize> {
457                self.checked_to_num()
458            }
459            #[inline]
460            fn to_u8(&self) -> Option<u8> {
461                self.checked_to_num()
462            }
463            #[inline]
464            fn to_u16(&self) -> Option<u16> {
465                self.checked_to_num()
466            }
467            #[inline]
468            fn to_u32(&self) -> Option<u32> {
469                self.checked_to_num()
470            }
471            #[inline]
472            fn to_u128(&self) -> Option<u128> {
473                self.checked_to_num()
474            }
475            #[inline]
476            fn to_f32(&self) -> Option<f32> {
477                self.checked_to_num()
478            }
479            #[inline]
480            fn to_f64(&self) -> Option<f64> {
481                self.checked_to_num()
482            }
483        }
484
485        impl<Frac: $LeEqU> FromPrimitive for $Fixed<Frac> {
486            #[inline]
487            fn from_i64(n: i64) -> Option<Self> {
488                Self::checked_from_num(n)
489            }
490            #[inline]
491            fn from_u64(n: u64) -> Option<Self> {
492                Self::checked_from_num(n)
493            }
494            #[inline]
495            fn from_isize(n: isize) -> Option<Self> {
496                Self::checked_from_num(n)
497            }
498            #[inline]
499            fn from_i8(n: i8) -> Option<Self> {
500                Self::checked_from_num(n)
501            }
502            #[inline]
503            fn from_i16(n: i16) -> Option<Self> {
504                Self::checked_from_num(n)
505            }
506            #[inline]
507            fn from_i32(n: i32) -> Option<Self> {
508                Self::checked_from_num(n)
509            }
510            #[inline]
511            fn from_i128(n: i128) -> Option<Self> {
512                Self::checked_from_num(n)
513            }
514            #[inline]
515            fn from_usize(n: usize) -> Option<Self> {
516                Self::checked_from_num(n)
517            }
518            #[inline]
519            fn from_u8(n: u8) -> Option<Self> {
520                Self::checked_from_num(n)
521            }
522            #[inline]
523            fn from_u16(n: u16) -> Option<Self> {
524                Self::checked_from_num(n)
525            }
526            #[inline]
527            fn from_u32(n: u32) -> Option<Self> {
528                Self::checked_from_num(n)
529            }
530            #[inline]
531            fn from_u128(n: u128) -> Option<Self> {
532                Self::checked_from_num(n)
533            }
534            #[inline]
535            fn from_f32(n: f32) -> Option<Self> {
536                Self::checked_from_num(n)
537            }
538            #[inline]
539            fn from_f64(n: f64) -> Option<Self> {
540                Self::checked_from_num(n)
541            }
542        }
543
544        impl<Frac: $LeEqU> ToBytes for $Fixed<Frac> {
545            type Bytes = <Self as Fixed>::Bytes;
546
547            fn to_be_bytes(&self) -> Self::Bytes {
548                (*self).to_be_bytes()
549            }
550
551            fn to_le_bytes(&self) -> Self::Bytes {
552                (*self).to_le_bytes()
553            }
554
555            fn to_ne_bytes(&self) -> Self::Bytes {
556                (*self).to_ne_bytes()
557            }
558        }
559
560        impl<Frac: $LeEqU> FromBytes for $Fixed<Frac> {
561            type Bytes = <Self as Fixed>::Bytes;
562
563            fn from_be_bytes(bytes: &Self::Bytes) -> Self {
564                Self::from_be_bytes(*bytes)
565            }
566
567            fn from_le_bytes(bytes: &Self::Bytes) -> Self {
568                Self::from_le_bytes(*bytes)
569            }
570
571            fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
572                Self::from_ne_bytes(*bytes)
573            }
574        }
575    };
576}
577
578impl_traits! { FixedI8, LeEqU8, U6, Signed }
579impl_traits! { FixedI16, LeEqU16, U14, Signed }
580impl_traits! { FixedI32, LeEqU32, U30, Signed }
581impl_traits! { FixedI64, LeEqU64, U62, Signed }
582impl_traits! { FixedI128, LeEqU128, U126, Signed }
583impl_traits! { FixedU8, LeEqU8, U7, Unsigned }
584impl_traits! { FixedU16, LeEqU16, U15, Unsigned }
585impl_traits! { FixedU32, LeEqU32, U31, Unsigned }
586impl_traits! { FixedU64, LeEqU64, U63, Unsigned }
587impl_traits! { FixedU128, LeEqU128, U127, Unsigned }