wasm/execution/runtime_structure/
values.rs

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