fixed/
impl_num_traits.rs

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