oxidd_core/util/num/
mod.rs1use std::fmt;
4use std::ops::{Add, Shl, Shr, Sub};
5
6use crate::util::IsFloatingPoint;
7
8mod bigint;
9pub use bigint::Natural;
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug)]
13pub struct NotRepresentable;
14
15impl std::error::Error for NotRepresentable {}
16
17impl fmt::Display for NotRepresentable {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 "number is not representable in the target type".fmt(f)
20 }
21}
22
23#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct Saturating<T>(pub T);
30
31impl<T> IsFloatingPoint for Saturating<T> {
33 const FLOATING_POINT: bool = false;
34 const MIN_EXP: i32 = 0;
35}
36
37impl<T: From<u32>> From<u32> for Saturating<T> {
38 #[inline]
39 fn from(value: u32) -> Self {
40 Self(T::from(value))
41 }
42}
43
44macro_rules! impl_assign_via_copy {
45 ($t:ty) => {
46 impl<'a> ::std::ops::AddAssign<&'a Self> for $t {
47 #[inline]
48 fn add_assign(&mut self, rhs: &'a Self) {
49 *self = *self + *rhs;
50 }
51 }
52 impl<'a> ::std::ops::SubAssign<&'a Self> for $t {
53 #[inline]
54 fn sub_assign(&mut self, rhs: &'a Self) {
55 *self = *self - *rhs;
56 }
57 }
58 impl<'a> ::std::ops::ShlAssign<u32> for $t {
59 #[inline]
60 fn shl_assign(&mut self, rhs: u32) {
61 *self = *self << rhs;
62 }
63 }
64 impl<'a> ::std::ops::ShrAssign<u32> for $t {
65 #[inline]
66 fn shr_assign(&mut self, rhs: u32) {
67 *self = *self >> rhs;
68 }
69 }
70 };
71}
72
73macro_rules! impl_saturating {
74 ($t:ty) => {
75 impl ::std::ops::Add for Saturating<$t> {
76 type Output = Self;
77 #[inline]
78 fn add(self, rhs: Self) -> Self {
79 Self(self.0.saturating_add(rhs.0))
80 }
81 }
82
83 impl ::std::ops::Sub for Saturating<$t> {
84 type Output = Self;
85 #[inline]
86 fn sub(self, rhs: Self) -> Self {
87 Self(if self.0 == <$t>::MAX {
88 <$t>::MAX
89 } else {
90 self.0 - rhs.0
91 })
92 }
93 }
94
95 impl ::std::ops::Shl<u32> for Saturating<$t> {
96 type Output = Self;
97 #[inline]
98 fn shl(self, rhs: u32) -> Self {
99 Self(self.0.checked_shl(rhs).unwrap_or(<$t>::MAX))
100 }
101 }
102
103 impl ::std::ops::Shr<u32> for Saturating<$t> {
104 type Output = Self;
105 #[inline]
106 fn shr(self, rhs: u32) -> Self {
107 Self(if self.0 == <$t>::MAX {
108 <$t>::MAX
109 } else {
110 self.0 >> rhs
111 })
112 }
113 }
114
115 impl_assign_via_copy!(Saturating<$t>);
116 };
117}
118
119impl_saturating!(u64);
120impl_saturating!(u128);
121
122#[derive(Clone, Copy, PartialEq, PartialOrd)]
125#[repr(transparent)]
126pub struct F64(pub f64);
127
128impl From<u32> for F64 {
129 #[inline]
130 fn from(value: u32) -> Self {
131 Self(value as f64)
132 }
133}
134
135impl IsFloatingPoint for F64 {
137 const FLOATING_POINT: bool = true;
138 const MIN_EXP: i32 = f64::MIN_EXP;
139}
140
141impl Add for F64 {
142 type Output = F64;
143 #[inline]
144 fn add(self, rhs: F64) -> F64 {
145 F64(self.0 + rhs.0)
146 }
147}
148impl Sub for F64 {
149 type Output = F64;
150 #[inline]
151 fn sub(self, rhs: F64) -> F64 {
152 F64(self.0 - rhs.0)
153 }
154}
155
156impl Shl<u32> for F64 {
157 type Output = F64;
158 #[inline]
159 #[allow(clippy::suspicious_arithmetic_impl)]
160 fn shl(self, rhs: u32) -> F64 {
161 F64(self.0 * (rhs as f64).exp2())
162 }
163}
164impl Shr<u32> for F64 {
165 type Output = F64;
166 #[inline]
167 #[allow(clippy::suspicious_arithmetic_impl)]
168 fn shr(self, rhs: u32) -> F64 {
169 F64(self.0 * (-(rhs as f64)).exp2())
170 }
171}
172
173impl_assign_via_copy!(F64);