/build/source/src/execution/runtime_structure/values.rs
Line | Count | Source |
1 | | use core::{ |
2 | | fmt::{Debug, Display}, |
3 | | ops::{Add, Div, Mul, Sub}, |
4 | | }; |
5 | | |
6 | | use crate::{FuncAddr, NumType, RefType, ValType}; |
7 | | |
8 | | #[derive(Clone, Debug, Copy, PartialOrd)] |
9 | | #[repr(transparent)] |
10 | | pub struct F32(pub f32); |
11 | | |
12 | | impl Display for F32 { |
13 | 10 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
14 | 10 | write!(f, "{}", self.0) |
15 | 10 | } |
16 | | } |
17 | | |
18 | | impl PartialEq for F32 { |
19 | 5.22k | fn eq(&self, other: &Self) -> bool { |
20 | 5.22k | self.0.eq(&other.0) |
21 | 5.22k | } |
22 | | } |
23 | | |
24 | | impl Add for F32 { |
25 | | type Output = Self; |
26 | 14.4k | fn add(self, rhs: Self) -> Self::Output { |
27 | 14.4k | Self(self.0 + rhs.0) |
28 | 14.4k | } |
29 | | } |
30 | | |
31 | | impl Sub for F32 { |
32 | | type Output = Self; |
33 | 25.5k | fn sub(self, rhs: Self) -> Self::Output { |
34 | 25.5k | Self(self.0 - rhs.0) |
35 | 25.5k | } |
36 | | } |
37 | | |
38 | | impl Mul for F32 { |
39 | | type Output = Self; |
40 | 2.35k | fn mul(self, rhs: Self) -> Self::Output { |
41 | 2.35k | Self(self.0 * rhs.0) |
42 | 2.35k | } |
43 | | } |
44 | | |
45 | | impl Div for F32 { |
46 | | type Output = Self; |
47 | 2.34k | fn div(self, rhs: Self) -> Self::Output { |
48 | 2.34k | Self(self.0 / rhs.0) |
49 | 2.34k | } |
50 | | } |
51 | | |
52 | | impl F32 { |
53 | 132 | pub fn abs(&self) -> Self { |
54 | 132 | Self(libm::fabsf(self.0)) |
55 | 132 | } |
56 | 277 | pub fn neg(&self) -> Self { |
57 | 277 | Self(-self.0) |
58 | 277 | } |
59 | 205 | pub fn ceil(&self) -> Self { |
60 | 205 | if self.0.is_nan() { |
61 | 20 | return Self(f32::NAN); |
62 | 185 | } |
63 | 185 | Self(libm::ceilf(self.0)) |
64 | 205 | } |
65 | 204 | pub fn floor(&self) -> Self { |
66 | 204 | if self.0.is_nan() { |
67 | 20 | return Self(f32::NAN); |
68 | 184 | } |
69 | 184 | Self(libm::floorf(self.0)) |
70 | 204 | } |
71 | 201 | pub fn trunc(&self) -> Self { |
72 | 201 | if self.0.is_nan() { |
73 | 20 | return Self(f32::NAN); |
74 | 181 | } |
75 | 181 | Self(libm::truncf(self.0)) |
76 | 201 | } |
77 | 209 | pub fn nearest(&self) -> Self { |
78 | 209 | if self.0.is_nan() { |
79 | 20 | return Self(f32::NAN); |
80 | 189 | } |
81 | 189 | Self(libm::rintf(self.0)) |
82 | 209 | } |
83 | 2 | pub fn round(&self) -> Self { |
84 | 2 | Self(libm::roundf(self.0)) |
85 | 2 | } |
86 | 324 | pub fn sqrt(&self) -> Self { |
87 | 324 | Self(libm::sqrtf(self.0)) |
88 | 324 | } |
89 | | |
90 | 1.92k | pub fn min(&self, rhs: Self) -> Self { |
91 | 1.92k | Self(if self.0.is_nan() || rhs.01.51k .is_nan1.51k () { |
92 | 471 | f32::NAN |
93 | 1.45k | } else if self.0 == 0.0 && rhs.0 == 0.0182 { |
94 | 39 | if self.to_bits() >> 31 == 1 { |
95 | 16 | self.0 |
96 | | } else { |
97 | 23 | rhs.0 |
98 | | } |
99 | | } else { |
100 | 1.41k | self.0.min(rhs.0) |
101 | | }) |
102 | 1.92k | } |
103 | 1.91k | pub fn max(&self, rhs: Self) -> Self { |
104 | 1.91k | Self(if self.0.is_nan() || rhs.01.50k .is_nan1.50k () { |
105 | 471 | f32::NAN |
106 | 1.44k | } else if self.0 == 0.0 && rhs.0 == 0.0182 { |
107 | 39 | if self.to_bits() >> 31 == 1 { |
108 | 16 | rhs.0 |
109 | | } else { |
110 | 23 | self.0 |
111 | | } |
112 | | } else { |
113 | 1.40k | self.0.max(rhs.0) |
114 | | }) |
115 | 1.91k | } |
116 | 333 | pub fn copysign(&self, rhs: Self) -> Self { |
117 | 333 | Self(libm::copysignf(self.0, rhs.0)) |
118 | 333 | } |
119 | 57.5k | pub fn from_bits(other: u32) -> Self { |
120 | 57.5k | Self(f32::from_bits(other)) |
121 | 57.5k | } |
122 | 754 | pub fn is_nan(&self) -> bool { |
123 | 754 | self.0.is_nan() |
124 | 754 | } |
125 | 698 | pub fn is_infinity(&self) -> bool { |
126 | 698 | self.0.is_infinite() |
127 | 698 | } |
128 | 524 | pub fn is_negative_infinity(&self) -> bool { |
129 | 524 | self.0.is_infinite() && self.0 < 0.032 |
130 | 524 | } |
131 | | |
132 | 255 | pub fn as_i32(&self) -> i32 { |
133 | 255 | self.0 as i32 |
134 | 255 | } |
135 | 243 | pub fn as_u32(&self) -> u32 { |
136 | 243 | self.0 as u32 |
137 | 243 | } |
138 | 72 | pub fn as_i64(&self) -> i64 { |
139 | 72 | self.0 as i64 |
140 | 72 | } |
141 | 52 | pub fn as_u64(&self) -> u64 { |
142 | 52 | self.0 as u64 |
143 | 52 | } |
144 | 127 | pub fn as_f64(&self) -> F64 { |
145 | 127 | F64(self.0 as f64) |
146 | 127 | } |
147 | 87 | pub fn reinterpret_as_i32(&self) -> i32 { |
148 | 87 | self.0.to_bits() as i32 |
149 | 87 | } |
150 | 31.3k | pub fn to_bits(&self) -> u32 { |
151 | 31.3k | self.0.to_bits() |
152 | 31.3k | } |
153 | | } |
154 | | |
155 | | #[derive(Clone, Debug, Copy, PartialOrd)] |
156 | | #[repr(transparent)] |
157 | | pub struct F64(pub f64); |
158 | | |
159 | | impl Display for F64 { |
160 | 10 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
161 | 10 | write!(f, "{}", self.0) |
162 | 10 | } |
163 | | } |
164 | | |
165 | | impl PartialEq for F64 { |
166 | 2.95k | fn eq(&self, other: &Self) -> bool { |
167 | 2.95k | self.0.eq(&other.0) |
168 | 2.95k | } |
169 | | } |
170 | | |
171 | | impl Add for F64 { |
172 | | type Output = Self; |
173 | 13.3k | fn add(self, rhs: Self) -> Self::Output { |
174 | 13.3k | Self(self.0 + rhs.0) |
175 | 13.3k | } |
176 | | } |
177 | | |
178 | | impl Sub for F64 { |
179 | | type Output = Self; |
180 | 24.2k | fn sub(self, rhs: Self) -> Self::Output { |
181 | 24.2k | Self(self.0 - rhs.0) |
182 | 24.2k | } |
183 | | } |
184 | | |
185 | | impl Mul for F64 { |
186 | | type Output = Self; |
187 | 1.62k | fn mul(self, rhs: Self) -> Self::Output { |
188 | 1.62k | Self(self.0 * rhs.0) |
189 | 1.62k | } |
190 | | } |
191 | | |
192 | | impl Div for F64 { |
193 | | type Output = Self; |
194 | 1.55k | fn div(self, rhs: Self) -> Self::Output { |
195 | 1.55k | Self(self.0 / rhs.0) |
196 | 1.55k | } |
197 | | } |
198 | | |
199 | | impl F64 { |
200 | 78 | pub fn abs(&self) -> Self { |
201 | 78 | Self(libm::fabs(self.0)) |
202 | 78 | } |
203 | 182 | pub fn neg(&self) -> Self { |
204 | 182 | Self(-self.0) |
205 | 182 | } |
206 | 117 | pub fn ceil(&self) -> Self { |
207 | 117 | if self.0.is_nan() { |
208 | 12 | return Self(f64::NAN); |
209 | 105 | } |
210 | 105 | Self(libm::ceil(self.0)) |
211 | 117 | } |
212 | 116 | pub fn floor(&self) -> Self { |
213 | 116 | if self.0.is_nan() { |
214 | 12 | return Self(f64::NAN); |
215 | 104 | } |
216 | 104 | Self(libm::floor(self.0)) |
217 | 116 | } |
218 | 113 | pub fn trunc(&self) -> Self { |
219 | 113 | if self.0.is_nan() { |
220 | 12 | return Self(f64::NAN); |
221 | 101 | } |
222 | 101 | Self(libm::trunc(self.0)) |
223 | 113 | } |
224 | 121 | pub fn nearest(&self) -> Self { |
225 | 121 | if self.0.is_nan() { |
226 | 12 | return Self(f64::NAN); |
227 | 109 | } |
228 | 109 | Self(libm::rint(self.0)) |
229 | 121 | } |
230 | 2 | pub fn round(&self) -> Self { |
231 | 2 | Self(libm::round(self.0)) |
232 | 2 | } |
233 | 222 | pub fn sqrt(&self) -> Self { |
234 | 222 | Self(libm::sqrt(self.0)) |
235 | 222 | } |
236 | | |
237 | 1.18k | pub fn min(&self, rhs: Self) -> Self { |
238 | 1.18k | Self(if self.0.is_nan() || rhs.0938 .is_nan938 () { |
239 | 310 | f64::NAN |
240 | 872 | } else if self.0 == 0.0 && rhs.0 == 0.0114 { |
241 | 28 | if self.to_bits() >> 63 == 1 { |
242 | 10 | self.0 |
243 | | } else { |
244 | 18 | rhs.0 |
245 | | } |
246 | | } else { |
247 | 844 | self.0.min(rhs.0) |
248 | | }) |
249 | 1.18k | } |
250 | 1.18k | pub fn max(&self, rhs: Self) -> Self { |
251 | 1.18k | Self(if self.0.is_nan() || rhs.0938 .is_nan938 () { |
252 | 310 | f64::NAN |
253 | 872 | } else if self.0 == 0.0 && rhs.0 == 0.0114 { |
254 | 28 | if self.to_bits() >> 63 == 1 { |
255 | 10 | rhs.0 |
256 | | } else { |
257 | 18 | self.0 |
258 | | } |
259 | | } else { |
260 | 844 | self.0.max(rhs.0) |
261 | | }) |
262 | 1.18k | } |
263 | 333 | pub fn copysign(&self, rhs: Self) -> Self { |
264 | 333 | Self(libm::copysign(self.0, rhs.0)) |
265 | 333 | } |
266 | | |
267 | 56.2k | pub fn from_bits(other: u64) -> Self { |
268 | 56.2k | Self(f64::from_bits(other)) |
269 | 56.2k | } |
270 | 833 | pub fn is_nan(&self) -> bool { |
271 | 833 | self.0.is_nan() |
272 | 833 | } |
273 | 549 | pub fn is_infinity(&self) -> bool { |
274 | 549 | self.0.is_infinite() |
275 | 549 | } |
276 | 345 | pub fn is_negative_infinity(&self) -> bool { |
277 | 345 | self.0.is_infinite() && self.0 < 0.024 |
278 | 345 | } |
279 | | |
280 | 158 | pub fn as_i32(&self) -> i32 { |
281 | 158 | self.0 as i32 |
282 | 158 | } |
283 | 164 | pub fn as_u32(&self) -> u32 { |
284 | 164 | self.0 as u32 |
285 | 164 | } |
286 | 77 | pub fn as_i64(&self) -> i64 { |
287 | 77 | self.0 as i64 |
288 | 77 | } |
289 | 72 | pub fn as_u64(&self) -> u64 { |
290 | 72 | self.0 as u64 |
291 | 72 | } |
292 | 264 | pub fn as_f32(&self) -> F32 { |
293 | 264 | F32(self.0 as f32) |
294 | 264 | } |
295 | 86 | pub fn reinterpret_as_i64(&self) -> i64 { |
296 | 86 | self.0.to_bits() as i64 |
297 | 86 | } |
298 | 17.6k | pub fn to_bits(&self) -> u64 { |
299 | 17.6k | self.0.to_bits() |
300 | 17.6k | } |
301 | | } |
302 | | |
303 | | /// A value at runtime. This is essentially a duplicate of [ValType] just with additional values. |
304 | | /// |
305 | | /// See <https://webassembly.github.io/spec/core/exec/runtime.html#values> |
306 | | // TODO implement missing variants |
307 | | #[derive(Clone, Copy, Debug, PartialEq)] |
308 | | pub enum Value { |
309 | | I32(u32), |
310 | | I64(u64), |
311 | | F32(F32), |
312 | | F64(F64), |
313 | | V128([u8; 16]), |
314 | | Ref(Ref), |
315 | | } |
316 | | |
317 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
318 | | pub enum Ref { |
319 | | Null(RefType), |
320 | | Func(FuncAddr), |
321 | | Extern(ExternAddr), |
322 | | } |
323 | | |
324 | | impl Display for Ref { |
325 | 4 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
326 | 4 | match self { |
327 | 1 | Ref::Func(func_addr) => write!(f, "FuncRef({func_addr:?})"), |
328 | 1 | Ref::Extern(extern_addr) => write!(f, "ExternRef({extern_addr:?})"), |
329 | 2 | Ref::Null(ty) => write!(f, "Null({ty:?})"), |
330 | | } |
331 | 4 | } |
332 | | } |
333 | | |
334 | | impl Ref { |
335 | 146 | pub fn ty(self) -> RefType { |
336 | 146 | match self { |
337 | 145 | Ref::Null(ref_type) => ref_type, |
338 | 0 | Ref::Func(_) => RefType::FuncRef, |
339 | 1 | Ref::Extern(_) => RefType::ExternRef, |
340 | | } |
341 | 146 | } |
342 | | } |
343 | | |
344 | | /// The WebAssembly specification defines an externaddr as an address to an |
345 | | /// "external" type, i.e. is a type which is managed by the embedder. For this |
346 | | /// interpreter the task of managing external objects and relating them to |
347 | | /// addresses is handed off to the user, which means that an [`ExternAddr`] can |
348 | | /// simply be seen as an integer that is opaque to Wasm code without any meaning |
349 | | /// assigned to it. |
350 | | /// |
351 | | /// See: WebAssembly Specification 2.0 - 2.3.3, 4.2.1 |
352 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
353 | | pub struct ExternAddr(pub usize); |
354 | | |
355 | | impl Value { |
356 | 645k | pub fn default_from_ty(ty: ValType) -> Self { |
357 | 645k | match ty { |
358 | 157 | ValType::NumType(NumType::I32) => Self::I32(0), |
359 | 645k | ValType::NumType(NumType::I64) => Self::I64(0), |
360 | 83 | ValType::NumType(NumType::F32) => Self::F32(F32(0.0)), |
361 | 56 | ValType::NumType(NumType::F64) => Self::F64(F64(0.0_f64)), |
362 | 2 | ValType::RefType(ref_type) => Self::Ref(Ref::Null(ref_type)), |
363 | 19 | ValType::VecType => Self::V128([0; 16]), |
364 | | } |
365 | 645k | } |
366 | | |
367 | 88.6k | pub fn to_ty(&self) -> ValType { |
368 | 63 | match self { |
369 | 17.0k | Value::I32(_) => ValType::NumType(NumType::I32), |
370 | 1.94k | Value::I64(_) => ValType::NumType(NumType::I64), |
371 | 12.2k | Value::F32(_) => ValType::NumType(NumType::F32), |
372 | 12.4k | Value::F64(_) => ValType::NumType(NumType::F64), |
373 | 18 | Value::Ref(Ref::Null(ref_type)) => ValType::RefType(*ref_type), |
374 | 0 | Value::Ref(Ref::Func(_)) => ValType::RefType(RefType::FuncRef), |
375 | 45 | Value::Ref(Ref::Extern(_)) => ValType::RefType(RefType::ExternRef), |
376 | 44.8k | Value::V128(_) => ValType::VecType, |
377 | | } |
378 | 88.6k | } |
379 | | } |
380 | | |
381 | | /// An error used in all [`TryFrom<Value>`] implementations for Rust types ([`i32`], [`F32`], [`Ref`], ...) |
382 | | #[derive(Debug, PartialEq, Eq)] |
383 | | pub struct ValueTypeMismatchError; |
384 | | |
385 | | impl Display for ValueTypeMismatchError { |
386 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
387 | 0 | f.write_str("failed to convert Value to a Rust value because the types did not match") |
388 | 0 | } |
389 | | } |
390 | | |
391 | | impl From<u32> for Value { |
392 | 14 | fn from(x: u32) -> Self { |
393 | 14 | Value::I32(x) |
394 | 14 | } |
395 | | } |
396 | | impl TryFrom<Value> for u32 { |
397 | | type Error = ValueTypeMismatchError; |
398 | | |
399 | 1.03M | fn try_from(value: Value) -> Result<Self, Self::Error> { |
400 | 1.03M | match value { |
401 | 1.03M | Value::I32(x) => Ok(x), |
402 | 0 | _ => Err(ValueTypeMismatchError), |
403 | | } |
404 | 1.03M | } |
405 | | } |
406 | | |
407 | | impl From<i32> for Value { |
408 | 4.80M | fn from(x: i32) -> Self { |
409 | 4.80M | Value::I32(x as u32) |
410 | 4.80M | } |
411 | | } |
412 | | impl TryFrom<Value> for i32 { |
413 | | type Error = ValueTypeMismatchError; |
414 | | |
415 | 8.78M | fn try_from(value: Value) -> Result<Self, Self::Error> { |
416 | 8.78M | match value { |
417 | 8.78M | Value::I32(x) => Ok(x as i32), |
418 | 0 | _ => Err(ValueTypeMismatchError), |
419 | | } |
420 | 8.78M | } |
421 | | } |
422 | | |
423 | | impl From<u64> for Value { |
424 | 72 | fn from(x: u64) -> Self { |
425 | 72 | Value::I64(x) |
426 | 72 | } |
427 | | } |
428 | | impl TryFrom<Value> for u64 { |
429 | | type Error = ValueTypeMismatchError; |
430 | | |
431 | 106 | fn try_from(value: Value) -> Result<Self, Self::Error> { |
432 | 106 | match value { |
433 | 106 | Value::I64(x) => Ok(x), |
434 | 0 | _ => Err(ValueTypeMismatchError), |
435 | | } |
436 | 106 | } |
437 | | } |
438 | | impl From<i64> for Value { |
439 | 191k | fn from(x: i64) -> Self { |
440 | 191k | Value::I64(x as u64) |
441 | 191k | } |
442 | | } |
443 | | impl TryFrom<Value> for i64 { |
444 | | type Error = ValueTypeMismatchError; |
445 | | |
446 | 241k | fn try_from(value: Value) -> Result<Self, Self::Error> { |
447 | 241k | match value { |
448 | 241k | Value::I64(x) => Ok(x as i64), |
449 | 0 | _ => Err(ValueTypeMismatchError), |
450 | | } |
451 | 241k | } |
452 | | } |
453 | | |
454 | | impl From<F32> for Value { |
455 | 97.1k | fn from(x: F32) -> Self { |
456 | 97.1k | Value::F32(x) |
457 | 97.1k | } |
458 | | } |
459 | | impl TryFrom<Value> for F32 { |
460 | | type Error = ValueTypeMismatchError; |
461 | | |
462 | 130k | fn try_from(value: Value) -> Result<Self, Self::Error> { |
463 | 130k | match value { |
464 | 130k | Value::F32(x) => Ok(x), |
465 | 0 | _ => Err(ValueTypeMismatchError), |
466 | | } |
467 | 130k | } |
468 | | } |
469 | | |
470 | | impl From<F64> for Value { |
471 | 95.3k | fn from(x: F64) -> Self { |
472 | 95.3k | Value::F64(x) |
473 | 95.3k | } |
474 | | } |
475 | | impl TryFrom<Value> for F64 { |
476 | | type Error = ValueTypeMismatchError; |
477 | | |
478 | 127k | fn try_from(value: Value) -> Result<Self, Self::Error> { |
479 | 127k | match value { |
480 | 127k | Value::F64(x) => Ok(x), |
481 | 0 | _ => Err(ValueTypeMismatchError), |
482 | | } |
483 | 127k | } |
484 | | } |
485 | | |
486 | | impl From<[u8; 16]> for Value { |
487 | 530 | fn from(value: [u8; 16]) -> Self { |
488 | 530 | Value::V128(value) |
489 | 530 | } |
490 | | } |
491 | | impl TryFrom<Value> for [u8; 16] { |
492 | | type Error = ValueTypeMismatchError; |
493 | | |
494 | 46.3k | fn try_from(value: Value) -> Result<Self, Self::Error> { |
495 | 46.3k | match value { |
496 | 46.3k | Value::V128(x) => Ok(x), |
497 | 0 | _ => Err(ValueTypeMismatchError), |
498 | | } |
499 | 46.3k | } |
500 | | } |
501 | | |
502 | | impl From<Ref> for Value { |
503 | 135 | fn from(value: Ref) -> Self { |
504 | 135 | Self::Ref(value) |
505 | 135 | } |
506 | | } |
507 | | |
508 | | impl TryFrom<Value> for Ref { |
509 | | type Error = ValueTypeMismatchError; |
510 | | |
511 | 1.25k | fn try_from(value: Value) -> Result<Self, Self::Error> { |
512 | 1.25k | match value { |
513 | 1.25k | Value::Ref(rref) => Ok(rref), |
514 | 0 | _ => Err(ValueTypeMismatchError), |
515 | | } |
516 | 1.25k | } |
517 | | } |
518 | | |
519 | | impl From<f32> for Value { |
520 | 0 | fn from(value: f32) -> Self { |
521 | 0 | F32(value).into() |
522 | 0 | } |
523 | | } |
524 | | |
525 | | impl TryFrom<Value> for f32 { |
526 | | type Error = ValueTypeMismatchError; |
527 | | |
528 | 0 | fn try_from(value: Value) -> Result<Self, Self::Error> { |
529 | 0 | F32::try_from(value).map(|f| f.0) |
530 | 0 | } |
531 | | } |
532 | | |
533 | | impl From<f64> for Value { |
534 | 0 | fn from(value: f64) -> Self { |
535 | 0 | F64(value).into() |
536 | 0 | } |
537 | | } |
538 | | |
539 | | impl TryFrom<Value> for f64 { |
540 | | type Error = ValueTypeMismatchError; |
541 | | |
542 | 0 | fn try_from(value: Value) -> Result<Self, Self::Error> { |
543 | 0 | F64::try_from(value).map(|f| f.0) |
544 | 0 | } |
545 | | } |
546 | | |
547 | | #[cfg(test)] |
548 | | mod test { |
549 | | use alloc::string::ToString; |
550 | | |
551 | | use crate::{Addr, ExternAddr, RefType, F32, F64}; |
552 | | |
553 | | use super::{FuncAddr, Ref}; |
554 | | |
555 | | #[test] |
556 | 1 | fn rounding_f32() { |
557 | 1 | let round_towards_0_f32 = F32(0.5 - f32::EPSILON).round(); |
558 | 1 | let round_towards_1_f32 = F32(0.5 + f32::EPSILON).round(); |
559 | | |
560 | 1 | assert_eq!(round_towards_0_f32, F32(0.0)); |
561 | 1 | assert_eq!(round_towards_1_f32, F32(1.0)); |
562 | 1 | } |
563 | | |
564 | | #[test] |
565 | 1 | fn rounding_f64() { |
566 | 1 | let round_towards_0_f64 = F64(0.5 - f64::EPSILON).round(); |
567 | 1 | let round_towards_1_f64 = F64(0.5 + f64::EPSILON).round(); |
568 | | |
569 | 1 | assert_eq!(round_towards_0_f64, F64(0.0)); |
570 | 1 | assert_eq!(round_towards_1_f64, F64(1.0)); |
571 | 1 | } |
572 | | |
573 | | #[test] |
574 | 1 | fn display_f32() { |
575 | 10 | for x in [ |
576 | 1 | -1.0, |
577 | 1 | 0.0, |
578 | 1 | 1.0, |
579 | 1 | 13.3, |
580 | 1 | f32::INFINITY, |
581 | 1 | f32::MAX, |
582 | 1 | f32::MIN, |
583 | 1 | f32::NAN, |
584 | 1 | f32::NEG_INFINITY, |
585 | 1 | core::f32::consts::PI, |
586 | 1 | ] { |
587 | 10 | let wrapped = F32(x).to_string(); |
588 | 10 | let expected = x.to_string(); |
589 | 10 | assert_eq!(wrapped, expected); |
590 | | } |
591 | 1 | } |
592 | | |
593 | | #[test] |
594 | 1 | fn display_f64() { |
595 | 10 | for x in [ |
596 | 1 | -1.0, |
597 | 1 | 0.0, |
598 | 1 | 1.0, |
599 | 1 | 13.3, |
600 | 1 | f64::INFINITY, |
601 | 1 | f64::MAX, |
602 | 1 | f64::MIN, |
603 | 1 | f64::NAN, |
604 | 1 | f64::NEG_INFINITY, |
605 | 1 | core::f64::consts::PI, |
606 | 1 | ] { |
607 | 10 | let wrapped = F64(x).to_string(); |
608 | 10 | let expected = x.to_string(); |
609 | 10 | assert_eq!(wrapped, expected); |
610 | | } |
611 | 1 | } |
612 | | |
613 | | #[test] |
614 | 1 | fn display_ref() { |
615 | 1 | assert_eq!( |
616 | 1 | Ref::Func(FuncAddr::new(11)).to_string(), |
617 | | "FuncRef(FuncAddr(11))" |
618 | | ); |
619 | 1 | assert_eq!( |
620 | 1 | Ref::Extern(ExternAddr(13)).to_string(), |
621 | | "ExternRef(ExternAddr(13))" |
622 | | ); |
623 | 1 | assert_eq!(Ref::Null(RefType::FuncRef).to_string(), "Null(FuncRef)"); |
624 | 1 | assert_eq!(Ref::Null(RefType::ExternRef).to_string(), "Null(ExternRef)"); |
625 | 1 | } |
626 | | } |