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