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