1use crate::{
2 Error,
3 value::Value,
4 value_inner::{self, NumberInner},
5};
6use core::{
7 fmt::{self, Display, Formatter},
8 ops::{Add, Div, Mul, Rem, 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
67impl Default for Number {
68 fn default() -> Self {
69 Self::new(Default::default())
70 }
71}
72
73impl Add for Number {
74 type Output = Self;
75
76 fn add(self, other: Self) -> Self::Output {
77 Self::new(self.to_representation() + other.to_representation())
78 }
79}
80
81impl Sub for Number {
82 type Output = Self;
83
84 fn sub(self, other: Self) -> Self::Output {
85 Self::new(self.to_representation() - other.to_representation())
86 }
87}
88
89impl Mul for Number {
90 type Output = Self;
91
92 fn mul(self, other: Self) -> Self::Output {
93 Self::new(self.to_representation() * other.to_representation())
94 }
95}
96
97impl Div for Number {
98 type Output = Self;
99
100 fn div(self, other: Self) -> Self::Output {
101 Self::new(self.to_representation() / other.to_representation())
102 }
103}
104
105impl Rem for Number {
106 type Output = Self;
107
108 fn rem(self, other: Self) -> Self::Output {
109 Self::new(self.to_representation() % other.to_representation())
110 }
111}
112
113impl TryFrom<Value> for Number {
114 type Error = Error;
115
116 fn try_from(value: Value) -> Result<Self, Self::Error> {
117 value.to_number().ok_or(Error::NumberExpected)
118 }
119}
120
121impl Display for Number {
122 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
123 write!(formatter, "n{}", self.to_representation())
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use alloc::format;
131
132 #[test]
133 fn default() {
134 assert_eq!(Number::default(), Number::from_i64(0));
135 }
136
137 #[test]
138 fn integer() {
139 assert_eq!(Number::default().to_i64(), 0);
140 assert_eq!(Number::from_i64(42).to_i64(), 42);
141 assert_eq!(Number::from_i64(-1).to_i64(), -1);
142 }
143
144 #[test]
145 fn float() {
146 assert_eq!(Number::default().to_f64(), 0.0);
147 assert_eq!(Number::from_f64(1.0).to_f64(), 1.0);
148 assert_eq!(Number::from_f64(42.0).to_f64(), 42.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 }
152
153 #[test]
154 fn format() {
155 assert_eq!(format!("{}", Number::from_i64(42)), "n42");
156 assert_eq!(format!("{}", Number::from_i64(-1)), "n-1");
157 }
158
159 #[test]
160 fn add() {
161 assert_eq!(Number::default() + Number::from_i64(1), Number::from_i64(1));
162 assert_eq!(
163 Number::from_i64(1) + Number::from_i64(2),
164 Number::from_i64(3)
165 );
166 }
167
168 #[test]
169 fn subtract() {
170 assert_eq!(
171 Number::default() - Number::from_i64(1),
172 Number::from_i64(-1)
173 );
174 assert_eq!(Number::from_i64(1) - Number::default(), Number::from_i64(1));
175 assert_eq!(
176 Number::from_i64(3) - Number::from_i64(1),
177 Number::from_i64(2)
178 );
179 }
180
181 #[test]
182 fn multiply() {
183 assert_eq!(Number::default() * Number::from_i64(1), Number::default());
184 assert_eq!(
185 Number::from_i64(1) * Number::from_i64(2),
186 Number::from_i64(2)
187 );
188 assert_eq!(
189 Number::from_i64(2) * Number::from_i64(3),
190 Number::from_i64(6)
191 );
192 }
193
194 #[test]
195 fn divide() {
196 assert_eq!(Number::default() / Number::from_i64(1), Number::default());
197 assert_eq!(
198 Number::from_i64(2) / Number::from_i64(1),
199 Number::from_i64(2)
200 );
201 assert_eq!(
202 Number::from_i64(6) / Number::from_i64(2),
203 Number::from_i64(3)
204 );
205 }
206
207 #[test]
208 fn remainder() {
209 assert_eq!(Number::default() % Number::from_i64(1), Number::default());
210 assert_eq!(
211 Number::from_i64(3) % Number::from_i64(2),
212 Number::from_i64(1)
213 );
214 }
215}