wasm/execution/
value.rs

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