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