1use crate::{
2 Error,
3 value::Value,
4 value_inner::{self, NumberInner},
5};
6use core::{
7 fmt::{self, Display, Formatter},
8 ops::{Add, Mul, Sub},
9};
10
11#[allow(clippy::derive_partial_eq_without_eq)]
16#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
17#[cfg_attr(not(feature = "float"), derive(Eq, Ord))]
18pub struct Number(NumberInner);
19
20impl Number {
21 const fn new(number: NumberInner) -> Self {
22 Self(value_inner::from_number(number))
23 }
24
25 const fn to_representation(self) -> NumberInner {
26 value_inner::to_number(self.0)
27 }
28
29 pub const fn from_i64(number: i64) -> Self {
31 Self(value_inner::from_i64(number))
32 }
33
34 pub const fn to_i64(self) -> i64 {
36 value_inner::to_i64(self.0)
37 }
38
39 pub const fn from_f64(number: f64) -> Self {
41 Self(value_inner::from_f64(number))
42 }
43
44 pub const fn to_f64(self) -> f64 {
46 value_inner::to_f64(self.0)
47 }
48
49 pub(crate) const fn from_raw(raw: u64) -> Self {
50 Self(value_inner::from_raw(raw))
51 }
52
53 pub(crate) const fn to_raw(self) -> u64 {
54 value_inner::to_raw(self.0)
55 }
56
57 #[allow(clippy::missing_const_for_fn)]
59 pub fn power(self, number: Self) -> Self {
60 Self::new(value_inner::power(
61 self.to_representation(),
62 number.to_representation(),
63 ))
64 }
65
66 pub fn divide(self, other: Self) -> Result<Self, Error> {
70 value_inner::checked_divide(self.to_representation(), other.to_representation())
71 .map(Self::new)
72 .ok_or(Error::DivisionByZero)
73 }
74
75 pub fn remainder(self, other: Self) -> Result<Self, Error> {
79 value_inner::checked_remainder(self.to_representation(), other.to_representation())
80 .map(Self::new)
81 .ok_or(Error::DivisionByZero)
82 }
83}
84
85impl Default for Number {
86 fn default() -> Self {
87 Self::new(Default::default())
88 }
89}
90
91impl Add for Number {
92 type Output = Self;
93
94 fn add(self, other: Self) -> Self::Output {
95 Self::new(self.to_representation() + other.to_representation())
96 }
97}
98
99impl Sub for Number {
100 type Output = Self;
101
102 fn sub(self, other: Self) -> Self::Output {
103 Self::new(self.to_representation() - other.to_representation())
104 }
105}
106
107impl Mul for Number {
108 type Output = Self;
109
110 fn mul(self, other: Self) -> Self::Output {
111 Self::new(self.to_representation() * other.to_representation())
112 }
113}
114
115impl TryFrom<Value> for Number {
116 type Error = Error;
117
118 fn try_from(value: Value) -> Result<Self, Self::Error> {
119 value.to_number().ok_or(Error::NumberExpected)
120 }
121}
122
123impl Display for Number {
124 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
125 write!(formatter, "n{}", self.to_representation())
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use alloc::format;
133
134 #[test]
135 fn default() {
136 assert_eq!(Number::default(), Number::from_i64(0));
137 }
138
139 #[test]
140 fn integer() {
141 assert_eq!(Number::default().to_i64(), 0);
142 assert_eq!(Number::from_i64(42).to_i64(), 42);
143 assert_eq!(Number::from_i64(-1).to_i64(), -1);
144 }
145
146 #[test]
147 fn float() {
148 assert_eq!(Number::default().to_f64(), 0.0);
149 assert_eq!(Number::from_f64(1.0).to_f64(), 1.0);
150 assert_eq!(Number::from_f64(42.0).to_f64(), 42.0);
151 assert_eq!(Number::from_f64(-1.0).to_f64(), -1.0);
152 assert_eq!(Number::from_f64(-42.0).to_f64(), -42.0);
153 }
154
155 #[test]
156 fn format() {
157 assert_eq!(format!("{}", Number::from_i64(42)), "n42");
158 assert_eq!(format!("{}", Number::from_i64(-1)), "n-1");
159 }
160
161 #[test]
162 fn add() {
163 assert_eq!(Number::default() + Number::from_i64(1), Number::from_i64(1));
164 assert_eq!(
165 Number::from_i64(1) + Number::from_i64(2),
166 Number::from_i64(3)
167 );
168 }
169
170 #[test]
171 fn subtract() {
172 assert_eq!(
173 Number::default() - Number::from_i64(1),
174 Number::from_i64(-1)
175 );
176 assert_eq!(Number::from_i64(1) - Number::default(), Number::from_i64(1));
177 assert_eq!(
178 Number::from_i64(3) - Number::from_i64(1),
179 Number::from_i64(2)
180 );
181 }
182
183 #[test]
184 fn multiply() {
185 assert_eq!(Number::default() * Number::from_i64(1), Number::default());
186 assert_eq!(
187 Number::from_i64(1) * Number::from_i64(2),
188 Number::from_i64(2)
189 );
190 assert_eq!(
191 Number::from_i64(2) * Number::from_i64(3),
192 Number::from_i64(6)
193 );
194 }
195
196 #[test]
197 fn divide() {
198 assert_eq!(
199 Number::default().divide(Number::from_i64(1)),
200 Ok(Number::default())
201 );
202 assert_eq!(
203 Number::from_i64(2).divide(Number::from_i64(1)),
204 Ok(Number::from_i64(2))
205 );
206 assert_eq!(
207 Number::from_i64(6).divide(Number::from_i64(2)),
208 Ok(Number::from_i64(3))
209 );
210 }
211
212 #[test]
213 fn remainder() {
214 assert_eq!(
215 Number::default().remainder(Number::from_i64(1)),
216 Ok(Number::default())
217 );
218 assert_eq!(
219 Number::from_i64(3).remainder(Number::from_i64(2)),
220 Ok(Number::from_i64(1))
221 );
222 }
223
224 #[cfg(any(not(feature = "float"), feature = "float62"))]
225 #[test]
226 fn divide_by_zero() {
227 assert_eq!(
228 Number::from_i64(1).divide(Number::from_i64(0)),
229 Err(Error::DivisionByZero)
230 );
231 }
232
233 #[cfg(any(not(feature = "float"), feature = "float62"))]
234 #[test]
235 fn remainder_by_zero() {
236 assert_eq!(
237 Number::from_i64(1).remainder(Number::from_i64(0)),
238 Err(Error::DivisionByZero)
239 );
240 }
241
242 #[cfg(all(feature = "float", not(feature = "float62")))]
243 #[test]
244 fn divide_by_zero_is_infinite() {
245 assert!(
246 Number::from_i64(1)
247 .divide(Number::from_i64(0))
248 .unwrap()
249 .to_f64()
250 .is_infinite()
251 );
252 }
253}