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 #[inline]
22 const fn new(number: NumberInner) -> Self {
23 Self(value_inner::from_number(number))
24 }
25
26 #[inline]
27 const fn to_representation(self) -> NumberInner {
28 value_inner::to_number(self.0)
29 }
30
31 #[inline]
33 pub const fn from_i64(number: i64) -> Self {
34 Self(value_inner::from_i64(number))
35 }
36
37 #[inline]
39 pub const fn to_i64(self) -> i64 {
40 value_inner::to_i64(self.0)
41 }
42
43 #[inline]
45 pub const fn from_f64(number: f64) -> Self {
46 Self(value_inner::from_f64(number))
47 }
48
49 #[inline]
51 pub const fn to_f64(self) -> f64 {
52 value_inner::to_f64(self.0)
53 }
54
55 #[inline]
56 pub(crate) const fn from_raw(raw: u64) -> Self {
57 Self(value_inner::from_raw(raw))
58 }
59
60 #[inline]
61 pub(crate) const fn to_raw(self) -> u64 {
62 value_inner::to_raw(self.0)
63 }
64}
65
66impl Default for Number {
67 #[inline]
68 fn default() -> Self {
69 Self::new(Default::default())
70 }
71}
72
73impl Add for Number {
74 type Output = Self;
75
76 #[inline]
77 fn add(self, other: Self) -> Self::Output {
78 Self::new(self.to_representation() + other.to_representation())
79 }
80}
81
82impl Sub for Number {
83 type Output = Self;
84
85 #[inline]
86 fn sub(self, other: Self) -> Self::Output {
87 Self::new(self.to_representation() - other.to_representation())
88 }
89}
90
91impl Mul for Number {
92 type Output = Self;
93
94 #[inline]
95 fn mul(self, other: Self) -> Self::Output {
96 Self::new(self.to_representation() * other.to_representation())
97 }
98}
99
100impl Div for Number {
101 type Output = Self;
102
103 #[inline]
104 fn div(self, other: Self) -> Self::Output {
105 Self::new(self.to_representation() / other.to_representation())
106 }
107}
108
109impl Rem for Number {
110 type Output = Self;
111
112 #[inline]
113 fn rem(self, other: Self) -> Self::Output {
114 Self::new(self.to_representation() % other.to_representation())
115 }
116}
117
118impl TryFrom<Value> for Number {
119 type Error = Error;
120
121 #[inline]
122 fn try_from(value: Value) -> Result<Self, Self::Error> {
123 value.to_number().ok_or(Error::NumberExpected)
124 }
125}
126
127impl Display for Number {
128 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
129 write!(formatter, "n{}", self.to_representation())
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use alloc::format;
137
138 #[test]
139 fn default() {
140 assert_eq!(Number::default(), Number::from_i64(0));
141 }
142
143 #[test]
144 fn integer() {
145 assert_eq!(Number::default().to_i64(), 0);
146 assert_eq!(Number::from_i64(42).to_i64(), 42);
147 assert_eq!(Number::from_i64(-1).to_i64(), -1);
148 }
149
150 #[test]
151 fn float() {
152 assert_eq!(Number::default().to_f64(), 0.0);
153 assert_eq!(Number::from_f64(1.0).to_f64(), 1.0);
154 assert_eq!(Number::from_f64(42.0).to_f64(), 42.0);
155 assert_eq!(Number::from_f64(-1.0).to_f64(), -1.0);
156 assert_eq!(Number::from_f64(-42.0).to_f64(), -42.0);
157 }
158
159 #[test]
160 fn format() {
161 assert_eq!(format!("{}", Number::from_i64(42)), "n42");
162 assert_eq!(format!("{}", Number::from_i64(-1)), "n-1");
163 }
164
165 #[test]
166 fn add() {
167 assert_eq!(Number::default() + Number::from_i64(1), Number::from_i64(1));
168 assert_eq!(
169 Number::from_i64(1) + Number::from_i64(2),
170 Number::from_i64(3)
171 );
172 }
173
174 #[test]
175 fn subtract() {
176 assert_eq!(
177 Number::default() - Number::from_i64(1),
178 Number::from_i64(-1)
179 );
180 assert_eq!(Number::from_i64(1) - Number::default(), Number::from_i64(1));
181 assert_eq!(
182 Number::from_i64(3) - Number::from_i64(1),
183 Number::from_i64(2)
184 );
185 }
186
187 #[test]
188 fn multiply() {
189 assert_eq!(Number::default() * Number::from_i64(1), Number::default());
190 assert_eq!(
191 Number::from_i64(1) * Number::from_i64(2),
192 Number::from_i64(2)
193 );
194 assert_eq!(
195 Number::from_i64(2) * Number::from_i64(3),
196 Number::from_i64(6)
197 );
198 }
199
200 #[test]
201 fn divide() {
202 assert_eq!(Number::default() / Number::from_i64(1), Number::default());
203 assert_eq!(
204 Number::from_i64(2) / Number::from_i64(1),
205 Number::from_i64(2)
206 );
207 assert_eq!(
208 Number::from_i64(6) / Number::from_i64(2),
209 Number::from_i64(3)
210 );
211 }
212
213 #[test]
214 fn remainder() {
215 assert_eq!(Number::default() % Number::from_i64(1), Number::default());
216 assert_eq!(
217 Number::from_i64(3) % Number::from_i64(2),
218 Number::from_i64(1)
219 );
220 }
221}