1pub trait ToJsString {
3 fn to_js_string(&self) -> String;
4}
5
6impl ToJsString for f64 {
7 fn to_js_string(&self) -> String {
8 let mut buffer = ryu_js::Buffer::new();
9 buffer.format(*self).to_string()
10 }
11}
12
13#[derive(Debug, Clone, Copy, PartialEq)]
14pub struct JsNumber(f64);
15
16impl From<f64> for JsNumber {
17 fn from(v: f64) -> Self {
18 JsNumber(v)
19 }
20}
21
22impl From<JsNumber> for f64 {
23 fn from(v: JsNumber) -> Self {
24 v.0
25 }
26}
27
28impl std::ops::Deref for JsNumber {
29 type Target = f64;
30
31 fn deref(&self) -> &Self::Target {
32 &self.0
33 }
34}
35
36impl JsNumber {
37 fn as_int32(&self) -> i32 {
39 self.as_uint32() as i32
40 }
41
42 fn as_uint32(&self) -> u32 {
44 if !self.0.is_finite() {
45 return 0;
46 }
47
48 self.0.trunc().rem_euclid(4294967296.0) as u32
50 }
51}
52
53impl std::ops::Add<JsNumber> for JsNumber {
55 type Output = JsNumber;
56
57 fn add(self, rhs: JsNumber) -> Self::Output {
58 JsNumber(self.0 + rhs.0)
59 }
60}
61
62impl std::ops::Sub<JsNumber> for JsNumber {
64 type Output = JsNumber;
65
66 fn sub(self, rhs: JsNumber) -> Self::Output {
67 JsNumber(self.0 - rhs.0)
68 }
69}
70
71impl std::ops::Mul<JsNumber> for JsNumber {
73 type Output = JsNumber;
74
75 fn mul(self, rhs: JsNumber) -> Self::Output {
76 JsNumber(self.0 * rhs.0)
77 }
78}
79
80impl std::ops::Div<JsNumber> for JsNumber {
82 type Output = JsNumber;
83
84 fn div(self, rhs: JsNumber) -> Self::Output {
85 JsNumber(self.0 / rhs.0)
86 }
87}
88
89impl std::ops::Rem<JsNumber> for JsNumber {
91 type Output = JsNumber;
92
93 fn rem(self, rhs: JsNumber) -> Self::Output {
94 JsNumber(self.0 % rhs.0)
95 }
96}
97
98impl JsNumber {
100 pub fn pow(self, rhs: JsNumber) -> JsNumber {
101 if rhs.0.is_nan() {
104 return JsNumber(f64::NAN);
105 }
106
107 if self.0.abs() == 1f64 && rhs.0.is_infinite() {
108 return JsNumber(f64::NAN);
109 }
110
111 JsNumber(self.0.powf(rhs.0))
112 }
113}
114
115impl std::ops::Shl<JsNumber> for JsNumber {
118 type Output = JsNumber;
119
120 fn shl(self, rhs: JsNumber) -> Self::Output {
121 JsNumber(self.as_int32().wrapping_shl(rhs.as_uint32()) as f64)
122 }
123}
124
125impl std::ops::Shr<JsNumber> for JsNumber {
128 type Output = JsNumber;
129
130 fn shr(self, rhs: JsNumber) -> Self::Output {
131 JsNumber((self.as_int32()).wrapping_shr(rhs.as_uint32()) as f64)
132 }
133}
134
135impl JsNumber {
138 pub fn unsigned_shr(self, rhs: JsNumber) -> JsNumber {
139 JsNumber((self.as_uint32()).wrapping_shr(rhs.as_uint32()) as f64)
140 }
141}
142
143impl std::ops::BitOr<JsNumber> for JsNumber {
146 type Output = JsNumber;
147
148 fn bitor(self, rhs: JsNumber) -> Self::Output {
149 JsNumber((self.as_int32() | rhs.as_int32()) as f64)
150 }
151}
152
153impl std::ops::BitAnd<JsNumber> for JsNumber {
156 type Output = JsNumber;
157
158 fn bitand(self, rhs: JsNumber) -> Self::Output {
159 JsNumber((self.as_int32() & rhs.as_int32()) as f64)
160 }
161}
162
163impl std::ops::BitXor<JsNumber> for JsNumber {
166 type Output = JsNumber;
167
168 fn bitxor(self, rhs: JsNumber) -> Self::Output {
169 JsNumber((self.as_int32() ^ rhs.as_int32()) as f64)
170 }
171}
172
173impl std::ops::Neg for JsNumber {
175 type Output = JsNumber;
176
177 fn neg(self) -> Self::Output {
178 JsNumber(-self.0)
179 }
180}
181
182impl std::ops::Not for JsNumber {
184 type Output = JsNumber;
185
186 fn not(self) -> Self::Output {
187 JsNumber(!(self.as_int32()) as f64)
188 }
189}
190
191#[cfg(test)]
192mod test_js_number {
193 use super::*;
194
195 #[test]
196 fn test_as_int32() {
197 assert_eq!(JsNumber(f64::NAN).as_int32(), 0);
198 assert_eq!(JsNumber(0.0).as_int32(), 0);
199 assert_eq!(JsNumber(-0.0).as_int32(), 0);
200 assert_eq!(JsNumber(f64::INFINITY).as_int32(), 0);
201 assert_eq!(JsNumber(f64::NEG_INFINITY).as_int32(), 0);
202 }
203
204 #[test]
205 fn test_as_uint32() {
206 assert_eq!(JsNumber(f64::NAN).as_uint32(), 0);
207 assert_eq!(JsNumber(0.0).as_uint32(), 0);
208 assert_eq!(JsNumber(-0.0).as_uint32(), 0);
209 assert_eq!(JsNumber(f64::INFINITY).as_uint32(), 0);
210 assert_eq!(JsNumber(f64::NEG_INFINITY).as_uint32(), 0);
211 assert_eq!(JsNumber(-8.0).as_uint32(), 4294967288);
212 }
213
214 #[test]
215 fn test_add() {
216 assert_eq!(JsNumber(1.0) + JsNumber(2.0), JsNumber(3.0));
217
218 assert!((JsNumber(1.0) + JsNumber(f64::NAN)).is_nan());
219 assert!((JsNumber(f64::NAN) + JsNumber(1.0)).is_nan());
220 assert!((JsNumber(f64::NAN) + JsNumber(f64::NAN)).is_nan());
221 assert!((JsNumber(f64::INFINITY) + JsNumber(f64::NEG_INFINITY)).is_nan());
222 assert!((JsNumber(f64::NEG_INFINITY) + JsNumber(f64::INFINITY)).is_nan());
223
224 assert_eq!(
225 JsNumber(f64::INFINITY) + JsNumber(1.0),
226 JsNumber(f64::INFINITY)
227 );
228 assert_eq!(
229 JsNumber(f64::NEG_INFINITY) + JsNumber(1.0),
230 JsNumber(f64::NEG_INFINITY)
231 );
232 assert_eq!(JsNumber(-0.0) + JsNumber(0.0), JsNumber(-0.0));
233 }
234}