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