makepad_stitch/
val.rs

1use {
2    crate::{
3        decode::{Decode, DecodeError, Decoder},
4        extern_ref::{ExternRef, UnguardedExternRef},
5        func_ref::{FuncRef, UnguardedFuncRef},
6        ref_::{Ref, RefType, UnguardedRef},
7        stack::StackSlot,
8        store::StoreId,
9    },
10    std::fmt,
11};
12
13/// A Wasm value.
14#[derive(Clone, Copy, Debug, PartialEq)]
15pub enum Val {
16    I32(i32),
17    I64(i64),
18    F32(f32),
19    F64(f64),
20    FuncRef(FuncRef),
21    ExternRef(ExternRef),
22}
23
24impl Val {
25    /// Returns a default [`Val`] of the given [`ValType`].
26    pub fn default(type_: ValType) -> Self {
27        match type_ {
28            ValType::I32 => 0i32.into(),
29            ValType::I64 => 0i64.into(),
30            ValType::F32 => 0f32.into(),
31            ValType::F64 => 0f64.into(),
32            ValType::FuncRef => FuncRef::null().into(),
33            ValType::ExternRef => ExternRef::null().into(),
34        }
35    }
36
37    /// Returns the [`ValType`] of this [`Val`].
38    pub fn type_(self) -> ValType {
39        match self {
40            Val::I32(_) => ValType::I32,
41            Val::I64(_) => ValType::I64,
42            Val::F32(_) => ValType::F32,
43            Val::F64(_) => ValType::F64,
44            Val::FuncRef(_) => ValType::FuncRef,
45            Val::ExternRef(_) => ValType::ExternRef,
46        }
47    }
48
49    /// Returns `true` if this [`Val`] is an `i32`.
50    pub fn is_i32(self) -> bool {
51        self.to_i32().is_some()
52    }
53
54    /// Returns `true` if this [`Val`] is an `i64`.
55    pub fn is_i64(self) -> bool {
56        self.to_i64().is_some()
57    }
58
59    /// Returns `true` if this [`Val`] is an `f32`.
60    pub fn is_f32(self) -> bool {
61        self.to_f32().is_some()
62    }
63
64    /// Returns `true` if this [`Val`] is an `f64`.
65    pub fn is_f64(self) -> bool {
66        self.to_f64().is_some()
67    }
68
69    /// Returns `true` if this [`Val`] is a [`Ref`].
70    pub fn is_ref(self) -> bool {
71        self.to_ref().is_some()
72    }
73
74    /// Returns `true` if this [`Val`] is a [`FuncRef`].
75    pub fn is_func_ref(self) -> bool {
76        self.to_func_ref().is_some()
77    }
78
79    /// Returns `true` if this [`Val`] is an [`ExternRef`].
80    pub fn is_extern_ref(self) -> bool {
81        self.to_extern_ref().is_some()
82    }
83
84    /// Converts this [`Val`] to an `i32`, if it is one.
85    pub fn to_i32(self) -> Option<i32> {
86        match self {
87            Val::I32(val) => Some(val),
88            _ => None,
89        }
90    }
91
92    /// Converts this [`Val`] to an `i64`, if it is one.
93    pub fn to_i64(self) -> Option<i64> {
94        match self {
95            Val::I64(val) => Some(val),
96            _ => None,
97        }
98    }
99
100    /// Converts this [`Val`] to an `f32`, if it is one.
101    pub fn to_f32(self) -> Option<f32> {
102        match self {
103            Val::F32(val) => Some(val),
104            _ => None,
105        }
106    }
107
108    /// Converts this [`Val`] to an `f64`, if it is one.
109    pub fn to_f64(self) -> Option<f64> {
110        match self {
111            Val::F64(val) => Some(val),
112            _ => None,
113        }
114    }
115
116    /// Converts this [`Val`] to a [`Ref`], if it is one.
117    pub fn to_ref(self) -> Option<Ref> {
118        match self {
119            Val::FuncRef(val) => Some(val.into()),
120            Val::ExternRef(val) => Some(val.into()),
121            _ => None,
122        }
123    }
124
125    /// Converts this [`Val`] to a [`FuncRef`], if it is one.
126    pub fn to_func_ref(self) -> Option<FuncRef> {
127        match self {
128            Val::FuncRef(val) => Some(val),
129            _ => None,
130        }
131    }
132
133    /// Converts this [`Val`] to an [`ExternRef`], if it is one.
134    pub fn to_extern_ref(self) -> Option<ExternRef> {
135        match self {
136            Val::ExternRef(val) => Some(val),
137            _ => None,
138        }
139    }
140
141    /// Converts the given [`UnguardedVal`] to a [`Val`].
142    ///
143    /// # Safety
144    ///
145    /// The [`UnguardedVal`] must be owned by the [`Store`] with the given [`StoreId`].
146    pub(crate) unsafe fn from_unguarded(val: UnguardedVal, store_id: StoreId) -> Self {
147        match val {
148            UnguardedVal::I32(val) => val.into(),
149            UnguardedVal::I64(val) => val.into(),
150            UnguardedVal::F32(val) => val.into(),
151            UnguardedVal::F64(val) => val.into(),
152            UnguardedVal::FuncRef(val) => FuncRef::from_unguarded(val, store_id).into(),
153            UnguardedVal::ExternRef(val) => ExternRef::from_unguarded(val, store_id).into(),
154        }
155    }
156
157    /// Converts this [`Val`] to an [`UnguardedVal`].
158    ///
159    /// # Panics
160    ///
161    /// This [`Val`] is not owned by the [`Store`] with the given [`StoreId`].
162    pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedVal {
163        match self {
164            Val::I32(val) => val.into(),
165            Val::I64(val) => val.into(),
166            Val::F32(val) => val.into(),
167            Val::F64(val) => val.into(),
168            Val::FuncRef(val) => val.to_unguarded(store_id).into(),
169            Val::ExternRef(val) => val.to_unguarded(store_id).into(),
170        }
171    }
172}
173
174impl From<i32> for Val {
175    fn from(val: i32) -> Self {
176        Val::I32(val)
177    }
178}
179
180impl From<i64> for Val {
181    fn from(val: i64) -> Self {
182        Val::I64(val)
183    }
184}
185
186impl From<f32> for Val {
187    fn from(val: f32) -> Self {
188        Val::F32(val)
189    }
190}
191
192impl From<f64> for Val {
193    fn from(val: f64) -> Self {
194        Val::F64(val)
195    }
196}
197
198impl From<FuncRef> for Val {
199    fn from(val: FuncRef) -> Self {
200        Val::FuncRef(val)
201    }
202}
203
204impl From<ExternRef> for Val {
205    fn from(val: ExternRef) -> Self {
206        Val::ExternRef(val)
207    }
208}
209
210impl From<Ref> for Val {
211    fn from(val: Ref) -> Self {
212        match val {
213            Ref::FuncRef(val) => val.into(),
214            Ref::ExternRef(val) => val.into(),
215        }
216    }
217}
218
219/// An unguarded [`Val`].
220#[derive(Clone, Copy, Debug, PartialEq)]
221pub(crate) enum UnguardedVal {
222    I32(i32),
223    I64(i64),
224    F32(f32),
225    F64(f64),
226    FuncRef(UnguardedFuncRef),
227    ExternRef(UnguardedExternRef),
228}
229
230impl UnguardedVal {
231    /// Reads an [`UnguardedVal`] of the given [`ValType`] from the given stack slot.
232    pub(crate) unsafe fn read_from_stack(ptr: *const StackSlot, type_: ValType) -> Self {
233        let val = match type_ {
234            ValType::I32 => (*ptr.cast::<i32>()).into(),
235            ValType::I64 => (*ptr.cast::<i64>()).into(),
236            ValType::F32 => (*ptr.cast::<f32>()).into(),
237            ValType::F64 => (*ptr.cast::<f64>()).into(),
238            ValType::FuncRef => (*ptr.cast::<UnguardedFuncRef>()).into(),
239            ValType::ExternRef => (*ptr.cast::<UnguardedExternRef>()).into(),
240        };
241        val
242    }
243
244    /// Writes this [`UnguardedVal`] to the given stack slot.
245    pub(crate) unsafe fn write_to_stack(self, ptr: *mut StackSlot) {
246        match self {
247            UnguardedVal::I32(val) => *ptr.cast() = val,
248            UnguardedVal::I64(val) => *ptr.cast() = val,
249            UnguardedVal::F32(val) => *ptr.cast() = val,
250            UnguardedVal::F64(val) => *ptr.cast() = val,
251            UnguardedVal::FuncRef(val) => *ptr.cast() = val,
252            UnguardedVal::ExternRef(val) => *ptr.cast() = val,
253        }
254    }
255}
256
257impl From<i32> for UnguardedVal {
258    fn from(val: i32) -> Self {
259        UnguardedVal::I32(val)
260    }
261}
262
263impl From<i64> for UnguardedVal {
264    fn from(val: i64) -> Self {
265        UnguardedVal::I64(val)
266    }
267}
268
269impl From<f32> for UnguardedVal {
270    fn from(val: f32) -> Self {
271        UnguardedVal::F32(val)
272    }
273}
274
275impl From<f64> for UnguardedVal {
276    fn from(val: f64) -> Self {
277        UnguardedVal::F64(val)
278    }
279}
280
281impl From<UnguardedRef> for UnguardedVal {
282    fn from(val: UnguardedRef) -> Self {
283        match val {
284            UnguardedRef::FuncRef(val) => val.into(),
285            UnguardedRef::ExternRef(val) => val.into(),
286        }
287    }
288}
289
290impl From<UnguardedFuncRef> for UnguardedVal {
291    fn from(val: UnguardedFuncRef) -> Self {
292        UnguardedVal::FuncRef(val)
293    }
294}
295
296impl From<UnguardedExternRef> for UnguardedVal {
297    fn from(val: UnguardedExternRef) -> Self {
298        UnguardedVal::ExternRef(val)
299    }
300}
301
302/// The type of a [`Val`].
303#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
304pub enum ValType {
305    I32,
306    I64,
307    F32,
308    F64,
309    FuncRef,
310    ExternRef,
311}
312
313impl ValType {
314    /// Returns `true` if this [`ValType`] is a number type.
315    pub fn is_num(self) -> bool {
316        match self {
317            Self::I32 | Self::I64 | Self::F32 | Self::F64 => true,
318            _ => false,
319        }
320    }
321
322    /// Returns `true` if this [`ValType`] is a `RefType`.
323    pub fn is_ref(self) -> bool {
324        self.to_ref().is_some()
325    }
326
327    /// Converts this [`ValType`] to a `RefType`, if it is one.
328    pub fn to_ref(self) -> Option<RefType> {
329        match self {
330            Self::FuncRef => Some(RefType::FuncRef),
331            Self::ExternRef => Some(RefType::ExternRef),
332            _ => None,
333        }
334    }
335
336    /// Returns the index of the register to be used for [`Val`]s of this [`ValType`].
337    pub(crate) fn reg_idx(self) -> usize {
338        match self {
339            ValType::I32 | ValType::I64 | ValType::FuncRef | ValType::ExternRef => 0,
340            ValType::F32 | ValType::F64 => 1,
341        }
342    }
343}
344
345impl Decode for ValType {
346    fn decode(decoder: &mut Decoder<'_>) -> Result<Self, DecodeError> {
347        match decoder.read_byte()? {
348            0x6F => Ok(Self::ExternRef),
349            0x70 => Ok(Self::FuncRef),
350            0x7C => Ok(Self::F64),
351            0x7D => Ok(Self::F32),
352            0x7E => Ok(Self::I64),
353            0x7F => Ok(Self::I32),
354            _ => Err(DecodeError::new("malformed value type")),
355        }
356    }
357}
358
359impl fmt::Display for ValType {
360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361        match self {
362            Self::I32 => write!(f, "i32"),
363            Self::I64 => write!(f, "i64"),
364            Self::F32 => write!(f, "f32"),
365            Self::F64 => write!(f, "f64"),
366            Self::FuncRef => write!(f, "funcref"),
367            Self::ExternRef => write!(f, "externref"),
368        }
369    }
370}
371
372impl From<RefType> for ValType {
373    fn from(val: RefType) -> Self {
374        match val {
375            RefType::FuncRef => Self::FuncRef,
376            RefType::ExternRef => Self::ExternRef,
377        }
378    }
379}