stak_vm/
number.rs

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/// A number.
12///
13/// It represents a signed 63-bit integer by default. If the `float` feature is
14/// enabled, it represents a 64-bit floating-point number.
15#[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    /// Converts `i64` into a number.
32    #[inline]
33    pub const fn from_i64(number: i64) -> Self {
34        Self(value_inner::from_i64(number))
35    }
36
37    /// Converts a number to `i64`.
38    #[inline]
39    pub const fn to_i64(self) -> i64 {
40        value_inner::to_i64(self.0)
41    }
42
43    /// Converts `f64` to a number.
44    #[inline]
45    pub const fn from_f64(number: f64) -> Self {
46        Self(value_inner::from_f64(number))
47    }
48
49    /// Converts a number to `f64`.
50    #[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}