Skip to main content

wasmtime/runtime/wave/
core.rs

1use crate::prelude::*;
2use std::borrow::Cow;
3
4use super::{canonicalize_nan32, canonicalize_nan64, unwrap_val};
5use wasm_wave::wasm::{WasmFunc, WasmType, WasmTypeKind, WasmValue, WasmValueError};
6
7impl WasmType for crate::ValType {
8    fn kind(&self) -> WasmTypeKind {
9        match self {
10            Self::I32 => WasmTypeKind::S32,
11            Self::I64 => WasmTypeKind::S64,
12            Self::F32 => WasmTypeKind::F32,
13            Self::F64 => WasmTypeKind::F64,
14            Self::V128 => WasmTypeKind::Tuple,
15
16            Self::Ref(_) => WasmTypeKind::Unsupported,
17        }
18    }
19
20    fn tuple_element_types(&self) -> Box<dyn Iterator<Item = Self> + '_> {
21        match *self {
22            Self::V128 => {}
23            _ => panic!("tuple_element_types called on non-tuple type"),
24        }
25        Box::new([Self::I64, Self::I64].into_iter())
26    }
27}
28
29impl WasmValue for crate::Val {
30    type Type = crate::ValType;
31
32    fn kind(&self) -> WasmTypeKind {
33        match self {
34            Self::I32(_) => WasmTypeKind::S32,
35            Self::I64(_) => WasmTypeKind::S64,
36            Self::F32(_) => WasmTypeKind::F32,
37            Self::F64(_) => WasmTypeKind::F64,
38            Self::V128(_) => WasmTypeKind::Tuple,
39            Self::FuncRef(_) => WasmTypeKind::Unsupported,
40            Self::ExternRef(_) => WasmTypeKind::Unsupported,
41            Self::AnyRef(_) => WasmTypeKind::Unsupported,
42            Self::ExnRef(_) => WasmTypeKind::Unsupported,
43            Self::ContRef(_) => WasmTypeKind::Unsupported,
44        }
45    }
46
47    fn make_s32(val: i32) -> Self {
48        Self::I32(val)
49    }
50    fn make_s64(val: i64) -> Self {
51        Self::I64(val)
52    }
53    fn make_f32(val: f32) -> Self {
54        let val = canonicalize_nan32(val);
55        Self::F32(val.to_bits())
56    }
57    fn make_f64(val: f64) -> Self {
58        let val = canonicalize_nan64(val);
59        Self::F64(val.to_bits())
60    }
61    fn make_tuple(
62        ty: &Self::Type,
63        vals: impl IntoIterator<Item = Self>,
64    ) -> Result<Self, WasmValueError> {
65        match *ty {
66            Self::Type::V128 => {}
67            _ => {
68                return Err(WasmValueError::Other(
69                    "tuples only used for v128 (v64x2)".to_string(),
70                ));
71            }
72        }
73        let mut iter = vals.into_iter();
74        let Some(l_val) = iter.next() else {
75            return Err(WasmValueError::Other("expected 2 values".to_string()));
76        };
77        let Some(h_val) = iter.next() else {
78            return Err(WasmValueError::Other("expected 2 values".to_string()));
79        };
80        if iter.next().is_some() {
81            return Err(WasmValueError::Other("expected 2 values".to_string()));
82        }
83
84        let (Some(l), Some(h)) = (l_val.i64(), h_val.i64()) else {
85            return Err(WasmValueError::Other("expected 2 i64s (v64x2)".to_string()));
86        };
87        Ok(Self::V128(((h as u128) << 64 | (l as u128)).into()))
88    }
89
90    fn unwrap_s32(&self) -> i32 {
91        *unwrap_val!(self, Self::I32, "s32")
92    }
93
94    fn unwrap_s64(&self) -> i64 {
95        *unwrap_val!(self, Self::I64, "s64")
96    }
97
98    fn unwrap_f32(&self) -> f32 {
99        let val = f32::from_bits(*unwrap_val!(self, Self::F32, "f32"));
100        canonicalize_nan32(val)
101    }
102
103    fn unwrap_f64(&self) -> f64 {
104        let val = f64::from_bits(*unwrap_val!(self, Self::F64, "f64"));
105        canonicalize_nan64(val)
106    }
107    #[expect(clippy::cast_possible_truncation, reason = "handled losslessly here")]
108    fn unwrap_tuple(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
109        let v = unwrap_val!(self, Self::V128, "tuple").as_u128();
110        let low = v as i64;
111        let high = (v >> 64) as i64;
112        Box::new(
113            [Self::I64(low), Self::I64(high)]
114                .into_iter()
115                .map(Cow::Owned),
116        )
117    }
118}
119
120impl WasmFunc for crate::FuncType {
121    type Type = crate::ValType;
122
123    fn params(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> {
124        Box::new(self.params())
125    }
126
127    fn results(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> {
128        Box::new(self.results())
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    #[test]
135    fn core_vals_smoke_test() {
136        use crate::Val;
137        for (val, want) in [
138            (Val::I32(10), "10"),
139            (Val::I64(-10), "-10"),
140            (1.5f32.into(), "1.5"),
141            (f32::NAN.into(), "nan"),
142            (f32::INFINITY.into(), "inf"),
143            (f32::NEG_INFINITY.into(), "-inf"),
144            ((-1.5f64).into(), "-1.5"),
145            (f32::NAN.into(), "nan"),
146            (f32::INFINITY.into(), "inf"),
147            (f32::NEG_INFINITY.into(), "-inf"),
148            (
149                Val::V128(0x1234567890abcdef1122334455667788.into()),
150                "(1234605616436508552, 1311768467294899695)",
151            ),
152        ] {
153            let got = wasm_wave::to_string(&val)
154                .unwrap_or_else(|err| panic!("failed to serialize {val:?}: {err}"));
155            assert_eq!(got, want, "for {val:?}");
156        }
157    }
158}