// Copyright © 2018–2025 Trevor Spiteri // This library is free software: you can redistribute it and/or // modify it under the terms of either // // * the Apache License, Version 2.0 or // * the MIT License // // at your option. // // You should have recieved copies of the Apache License and the MIT // License along with the library. If not, see // and // . use crate::consts; use crate::traits::Fixed; use crate::types::extra::{ IsLessOrEqual, LeEqU8, LeEqU16, LeEqU32, LeEqU64, LeEqU128, True, U6, U7, U14, U15, U30, U31, U62, U63, U126, U127, }; use crate::{ FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32, FixedU64, FixedU128, ParseFixedError, }; use core::fmt::{Display, Formatter, Result as FmtResult}; use num_traits::bounds::Bounded; use num_traits::cast::{FromPrimitive, ToPrimitive}; use num_traits::float::FloatConst; use num_traits::identities::{ConstOne, ConstZero, One, Zero}; use core::error::Error; use num_traits::Num; use num_traits::ops::bytes::{FromBytes, ToBytes}; use num_traits::ops::checked::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, }; use num_traits::ops::inv::Inv; use num_traits::ops::mul_add::{MulAdd, MulAddAssign}; use num_traits::ops::overflowing::{OverflowingAdd, OverflowingMul, OverflowingSub}; use num_traits::ops::saturating::{SaturatingAdd, SaturatingMul, SaturatingSub}; use num_traits::ops::wrapping::{ WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, }; use num_traits::sign::{Signed, Unsigned}; /// An error which can be returned when parsing a fixed-point number /// with a given radix. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RadixParseFixedError { /// The radix is not 2, 8, 10 or 16. UnsupportedRadix, /// The string could not be parsed as a fixed-point number. ParseFixedError(ParseFixedError), } impl RadixParseFixedError { fn message(&self) -> &str { match self { RadixParseFixedError::UnsupportedRadix => "unsupported radix", RadixParseFixedError::ParseFixedError(e) => e.message(), } } } impl Display for RadixParseFixedError { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { Display::fmt(self.message(), f) } } impl Error for RadixParseFixedError { fn description(&self) -> &str { self.message() } } macro_rules! impl_traits { ($Fixed:ident, $LeEqU:ident, $OneMaxFrac:ident, $Signedness:ident) => { impl Bounded for $Fixed { #[inline] fn min_value() -> Self { Self::MIN } #[inline] fn max_value() -> Self { Self::MAX } } impl Zero for $Fixed { #[inline] fn zero() -> Self { Self::ZERO } #[inline] fn is_zero(&self) -> bool { (*self).is_zero() } } impl ConstZero for $Fixed { const ZERO: Self = Self::ZERO; } impl One for $Fixed where Frac: IsLessOrEqual<$OneMaxFrac, Output = True>, { #[inline] fn one() -> Self { Self::ONE } } impl ConstOne for $Fixed where Frac: IsLessOrEqual<$OneMaxFrac, Output = True>, { const ONE: Self = Self::ONE; } impl Num for $Fixed where Frac: IsLessOrEqual<$OneMaxFrac, Output = True>, { type FromStrRadixErr = RadixParseFixedError; #[inline] fn from_str_radix(str: &str, radix: u32) -> Result { match radix { 2 => Self::from_str_binary(str), 8 => Self::from_str_octal(str), 10 => str.parse(), 16 => Self::from_str_hex(str), _ => return Err(RadixParseFixedError::UnsupportedRadix), } .map_err(RadixParseFixedError::ParseFixedError) } } impl Inv for $Fixed { type Output = Self; #[inline] fn inv(self) -> Self::Output { self.recip() } } if_signed! { $Signedness; impl Signed for $Fixed where Frac: IsLessOrEqual<$OneMaxFrac, Output = True>, { #[inline] fn abs(&self) -> Self { (*self).abs() } #[inline] fn abs_sub(&self, other: &Self) -> Self { if *self < *other { Self::ZERO } else { *self - *other } } #[inline] fn signum(&self) -> Self { (*self).signum() } #[inline] fn is_positive(&self) -> bool { (*self).is_positive() } #[inline] fn is_negative(&self) -> bool { (*self).is_negative() } } } if_unsigned! { $Signedness; impl Unsigned for $Fixed where Frac: IsLessOrEqual<$OneMaxFrac, Output = True>, { } } impl CheckedAdd for $Fixed { #[inline] fn checked_add(&self, v: &Self) -> Option { (*self).checked_add(*v) } } impl CheckedSub for $Fixed { #[inline] fn checked_sub(&self, v: &Self) -> Option { (*self).checked_sub(*v) } } impl CheckedNeg for $Fixed { #[inline] fn checked_neg(&self) -> Option { (*self).checked_neg() } } impl CheckedMul for $Fixed { #[inline] fn checked_mul(&self, v: &Self) -> Option { (*self).checked_mul(*v) } } impl CheckedDiv for $Fixed { #[inline] fn checked_div(&self, v: &Self) -> Option { (*self).checked_div(*v) } } impl CheckedRem for $Fixed { #[inline] fn checked_rem(&self, v: &Self) -> Option { (*self).checked_rem(*v) } } impl CheckedShl for $Fixed { #[inline] fn checked_shl(&self, rhs: u32) -> Option { (*self).checked_shl(rhs) } } impl CheckedShr for $Fixed { #[inline] fn checked_shr(&self, rhs: u32) -> Option { (*self).checked_shr(rhs) } } impl SaturatingAdd for $Fixed { #[inline] fn saturating_add(&self, v: &Self) -> Self { (*self).saturating_add(*v) } } impl SaturatingSub for $Fixed { #[inline] fn saturating_sub(&self, v: &Self) -> Self { (*self).saturating_sub(*v) } } impl SaturatingMul for $Fixed { #[inline] fn saturating_mul(&self, v: &Self) -> Self { (*self).saturating_mul(*v) } } impl WrappingAdd for $Fixed { #[inline] fn wrapping_add(&self, v: &Self) -> Self { (*self).wrapping_add(*v) } } impl WrappingSub for $Fixed { #[inline] fn wrapping_sub(&self, v: &Self) -> Self { (*self).wrapping_sub(*v) } } impl WrappingNeg for $Fixed { #[inline] fn wrapping_neg(&self) -> Self { (*self).wrapping_neg() } } impl WrappingMul for $Fixed { #[inline] fn wrapping_mul(&self, v: &Self) -> Self { (*self).wrapping_mul(*v) } } impl WrappingShl for $Fixed { #[inline] fn wrapping_shl(&self, rhs: u32) -> Self { (*self).wrapping_shl(rhs) } } impl WrappingShr for $Fixed { #[inline] fn wrapping_shr(&self, rhs: u32) -> Self { (*self).wrapping_shr(rhs) } } impl OverflowingAdd for $Fixed { #[inline] fn overflowing_add(&self, v: &Self) -> (Self, bool) { (*self).overflowing_add(*v) } } impl OverflowingSub for $Fixed { #[inline] fn overflowing_sub(&self, v: &Self) -> (Self, bool) { (*self).overflowing_sub(*v) } } impl OverflowingMul for $Fixed { #[inline] fn overflowing_mul(&self, v: &Self) -> (Self, bool) { (*self).overflowing_mul(*v) } } impl MulAdd<$Fixed> for $Fixed { type Output = $Fixed; #[inline] fn mul_add(self, a: $Fixed, b: $Fixed) -> $Fixed { self.mul_add(a, b) } } impl MulAddAssign<$Fixed> for $Fixed { #[inline] fn mul_add_assign(&mut self, a: $Fixed, b: $Fixed) { *self = self.mul_add(a, b) } } impl FloatConst for $Fixed { #[inline] fn E() -> Self { consts::E.to_num() } #[inline] fn FRAC_1_PI() -> Self { consts::FRAC_1_PI.to_num() } #[inline] fn FRAC_1_SQRT_2() -> Self { consts::FRAC_1_SQRT_2.to_num() } #[inline] fn FRAC_2_PI() -> Self { consts::FRAC_2_PI.to_num() } #[inline] fn FRAC_2_SQRT_PI() -> Self { consts::FRAC_2_SQRT_PI.to_num() } #[inline] fn FRAC_PI_2() -> Self { consts::FRAC_PI_2.to_num() } #[inline] fn FRAC_PI_3() -> Self { consts::FRAC_PI_3.to_num() } #[inline] fn FRAC_PI_4() -> Self { consts::FRAC_PI_4.to_num() } #[inline] fn FRAC_PI_6() -> Self { consts::FRAC_PI_6.to_num() } #[inline] fn FRAC_PI_8() -> Self { consts::FRAC_PI_8.to_num() } #[inline] fn LN_10() -> Self { consts::LN_10.to_num() } #[inline] fn LN_2() -> Self { consts::LN_2.to_num() } #[inline] fn LOG10_E() -> Self { consts::LOG10_E.to_num() } #[inline] fn LOG2_E() -> Self { consts::LOG2_E.to_num() } #[inline] fn PI() -> Self { consts::PI.to_num() } #[inline] fn SQRT_2() -> Self { consts::SQRT_2.to_num() } #[inline] fn TAU() -> Self { consts::TAU.to_num() } #[inline] fn LOG10_2() -> Self { consts::LOG10_2.to_num() } #[inline] fn LOG2_10() -> Self { consts::LOG2_10.to_num() } } impl ToPrimitive for $Fixed { #[inline] fn to_i64(&self) -> Option { self.checked_to_num() } #[inline] fn to_u64(&self) -> Option { self.checked_to_num() } #[inline] fn to_isize(&self) -> Option { self.checked_to_num() } #[inline] fn to_i8(&self) -> Option { self.checked_to_num() } #[inline] fn to_i16(&self) -> Option { self.checked_to_num() } #[inline] fn to_i32(&self) -> Option { self.checked_to_num() } #[inline] fn to_i128(&self) -> Option { self.checked_to_num() } #[inline] fn to_usize(&self) -> Option { self.checked_to_num() } #[inline] fn to_u8(&self) -> Option { self.checked_to_num() } #[inline] fn to_u16(&self) -> Option { self.checked_to_num() } #[inline] fn to_u32(&self) -> Option { self.checked_to_num() } #[inline] fn to_u128(&self) -> Option { self.checked_to_num() } #[inline] fn to_f32(&self) -> Option { self.checked_to_num() } #[inline] fn to_f64(&self) -> Option { self.checked_to_num() } } impl FromPrimitive for $Fixed { #[inline] fn from_i64(n: i64) -> Option { Self::checked_from_num(n) } #[inline] fn from_u64(n: u64) -> Option { Self::checked_from_num(n) } #[inline] fn from_isize(n: isize) -> Option { Self::checked_from_num(n) } #[inline] fn from_i8(n: i8) -> Option { Self::checked_from_num(n) } #[inline] fn from_i16(n: i16) -> Option { Self::checked_from_num(n) } #[inline] fn from_i32(n: i32) -> Option { Self::checked_from_num(n) } #[inline] fn from_i128(n: i128) -> Option { Self::checked_from_num(n) } #[inline] fn from_usize(n: usize) -> Option { Self::checked_from_num(n) } #[inline] fn from_u8(n: u8) -> Option { Self::checked_from_num(n) } #[inline] fn from_u16(n: u16) -> Option { Self::checked_from_num(n) } #[inline] fn from_u32(n: u32) -> Option { Self::checked_from_num(n) } #[inline] fn from_u128(n: u128) -> Option { Self::checked_from_num(n) } #[inline] fn from_f32(n: f32) -> Option { Self::checked_from_num(n) } #[inline] fn from_f64(n: f64) -> Option { Self::checked_from_num(n) } } impl ToBytes for $Fixed { type Bytes = ::Bytes; fn to_be_bytes(&self) -> Self::Bytes { (*self).to_be_bytes() } fn to_le_bytes(&self) -> Self::Bytes { (*self).to_le_bytes() } fn to_ne_bytes(&self) -> Self::Bytes { (*self).to_ne_bytes() } } impl FromBytes for $Fixed { type Bytes = ::Bytes; fn from_be_bytes(bytes: &Self::Bytes) -> Self { Self::from_be_bytes(*bytes) } fn from_le_bytes(bytes: &Self::Bytes) -> Self { Self::from_le_bytes(*bytes) } fn from_ne_bytes(bytes: &Self::Bytes) -> Self { Self::from_ne_bytes(*bytes) } } }; } impl_traits! { FixedI8, LeEqU8, U6, Signed } impl_traits! { FixedI16, LeEqU16, U14, Signed } impl_traits! { FixedI32, LeEqU32, U30, Signed } impl_traits! { FixedI64, LeEqU64, U62, Signed } impl_traits! { FixedI128, LeEqU128, U126, Signed } impl_traits! { FixedU8, LeEqU8, U7, Unsigned } impl_traits! { FixedU16, LeEqU16, U15, Unsigned } impl_traits! { FixedU32, LeEqU32, U31, Unsigned } impl_traits! { FixedU64, LeEqU64, U63, Unsigned } impl_traits! { FixedU128, LeEqU128, U127, Unsigned }