wasmer/entities/
value.rs

1use wasmer_types::{RawValue, Type};
2
3use crate::{
4    AsStoreRef, Tag,
5    entities::{Exception, ExternRef, Function},
6    vm::{VMExceptionRef, VMExternRef, VMFuncRef},
7};
8
9/// WebAssembly computations manipulate values of basic value types:
10/// * Integers (32 or 64 bit width)
11/// * Floating-point (32 or 64 bit width)
12/// * Vectors (128 bits, with 32 or 64 bit lanes)
13///
14/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#values>
15#[derive(Clone)]
16pub enum Value {
17    /// A 32-bit integer.
18    ///
19    /// In Wasm integers are sign-agnostic, i.e. this can either be signed or unsigned.
20    I32(i32),
21
22    /// A 64-bit integer.
23    ///
24    /// In Wasm integers are sign-agnostic, i.e. this can either be signed or unsigned.
25    I64(i64),
26
27    /// A 32-bit float.
28    F32(f32),
29
30    /// A 64-bit float.
31    F64(f64),
32
33    /// A 128-bit number
34    V128(u128),
35
36    // -- references --
37    /// A nullable `externref` value which can hold opaque data to the wasm instance itself.
38    ExternRef(Option<ExternRef>),
39
40    /// A nullable first-class reference to a WebAssembly function.
41    FuncRef(Option<Function>),
42
43    /// A nullable first-class reference to a WebAssembly exception.
44    ExceptionRef(Option<Exception>),
45}
46
47macro_rules! accessors {
48    ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
49        /// Attempt to access the underlying value of this `Value`, returning
50        /// `None` if it is not the correct type.
51        pub fn $get(&self) -> Option<$ty> {
52            if let Self::$variant($bind) = self {
53                Some($cvt)
54            } else {
55                None
56            }
57        }
58
59        /// Returns the underlying value of this `Value`, panicking if it's the
60        /// wrong type.
61        ///
62        /// # Panics
63        ///
64        /// Panics if `self` is not of the right type.
65        pub fn $unwrap(&self) -> $ty {
66            self.$get().expect(concat!("expected ", stringify!($ty)))
67        }
68    )*)
69}
70
71impl Value {
72    /// Returns a null `externref` value.
73    pub fn null() -> Self {
74        Self::ExternRef(None)
75    }
76
77    /// Returns the corresponding [`Type`] for this [`Value`].
78    pub fn ty(&self) -> Type {
79        match self {
80            Self::I32(_) => Type::I32,
81            Self::I64(_) => Type::I64,
82            Self::F32(_) => Type::F32,
83            Self::F64(_) => Type::F64,
84            Self::V128(_) => Type::V128,
85            Self::ExternRef(_) => Type::ExternRef,
86            Self::FuncRef(_) => Type::FuncRef,
87            Self::ExceptionRef(_) => Type::ExceptionRef,
88        }
89    }
90
91    /// Converts the `Value` into a `RawValue`.
92    pub fn as_raw(&self, store: &impl AsStoreRef) -> RawValue {
93        match *self {
94            Self::I32(i32) => RawValue { i32 },
95            Self::I64(i64) => RawValue { i64 },
96            Self::F32(f32) => RawValue { f32 },
97            Self::F64(f64) => RawValue { f64 },
98            Self::V128(u128) => RawValue { u128 },
99            Self::ExceptionRef(Some(ref f)) => f.vm_exceptionref().into_raw(),
100            Self::ExceptionRef(None) => RawValue { exnref: 0 },
101            Self::FuncRef(Some(ref f)) => f.vm_funcref(store).into_raw(),
102            Self::FuncRef(None) => RawValue { funcref: 0 },
103            Self::ExternRef(Some(ref e)) => e.vm_externref().into_raw(),
104            Self::ExternRef(None) => RawValue { externref: 0 },
105        }
106    }
107
108    /// Converts a `RawValue` to a `Value`.
109    ///
110    /// # Safety
111    ///
112    pub unsafe fn from_raw(
113        store: &mut impl crate::entities::store::AsStoreMut,
114        ty: Type,
115        raw: RawValue,
116    ) -> Self {
117        match ty {
118            Type::I32 => Self::I32(unsafe { raw.i32 }),
119            Type::I64 => Self::I64(unsafe { raw.i64 }),
120            Type::F32 => Self::F32(unsafe { raw.f32 }),
121            Type::F64 => Self::F64(unsafe { raw.f64 }),
122            Type::V128 => Self::V128(unsafe { raw.u128 }),
123            Type::FuncRef => match store.as_store_ref().inner.store {
124                #[cfg(feature = "sys")]
125                crate::BackendStore::Sys(_) => Self::FuncRef({
126                    unsafe { crate::backend::sys::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Sys) }
127                        .map(|f| unsafe { Function::from_vm_funcref(store, f) })
128                }),
129
130                #[cfg(feature = "v8")]
131                crate::BackendStore::V8(_) => Self::FuncRef({
132                    unsafe { crate::backend::v8::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::V8) }
133                        .map(|f| unsafe { Function::from_vm_funcref(store, f) })
134                }),
135                #[cfg(feature = "js")]
136                crate::BackendStore::Js(_) => Self::FuncRef({
137                    unsafe { crate::backend::js::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Js) }
138                        .map(|f| unsafe { Function::from_vm_funcref(store, f) })
139                }),
140            },
141            Type::ExternRef => match store.as_store_ref().inner.store {
142                #[cfg(feature = "sys")]
143                crate::BackendStore::Sys(_) => Self::ExternRef({
144                    unsafe {
145                        crate::backend::sys::vm::VMExternRef::from_raw(raw).map(VMExternRef::Sys)
146                    }
147                    .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
148                }),
149
150                #[cfg(feature = "v8")]
151                crate::BackendStore::V8(_) => Self::ExternRef({
152                    unsafe {
153                        crate::backend::v8::vm::VMExternRef::from_raw(raw).map(VMExternRef::V8)
154                    }
155                    .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
156                }),
157                #[cfg(feature = "js")]
158                crate::BackendStore::Js(_) => Self::ExternRef({
159                    unsafe {
160                        crate::backend::js::vm::VMExternRef::from_raw(raw).map(VMExternRef::Js)
161                    }
162                    .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
163                }),
164            },
165            Type::ExceptionRef => match store.as_store_ref().inner.store {
166                #[cfg(feature = "sys")]
167                crate::BackendStore::Sys(_) => Self::ExceptionRef(
168                    unsafe {
169                        crate::backend::sys::vm::VMExceptionRef::from_raw(
170                            store.objects_mut().id(),
171                            raw,
172                        )
173                    }
174                    .map(VMExceptionRef::Sys)
175                    .map(Exception::from_vm_exceptionref),
176                ),
177
178                #[cfg(feature = "v8")]
179                crate::BackendStore::V8(_) => Self::ExceptionRef(
180                    unsafe { crate::backend::v8::vm::VMExceptionRef::from_raw(raw) }
181                        .map(VMExceptionRef::V8)
182                        .map(Exception::from_vm_exceptionref),
183                ),
184                #[cfg(feature = "js")]
185                crate::BackendStore::Js(_) => Self::ExceptionRef(
186                    unsafe { crate::backend::js::vm::VMExceptionRef::from_raw(raw) }
187                        .map(VMExceptionRef::Js)
188                        .map(Exception::from_vm_exceptionref),
189                ),
190            },
191        }
192    }
193
194    /// Checks whether a value can be used with the given context.
195    ///
196    /// Primitive (`i32`, `i64`, etc) and null funcref/externref values are not
197    /// tied to a context and can be freely shared between contexts.
198    ///
199    /// Externref and funcref values are tied to a context and can only be used
200    /// with that context.
201    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
202        match self {
203            Self::I32(_)
204            | Self::I64(_)
205            | Self::F32(_)
206            | Self::F64(_)
207            | Self::V128(_)
208            | Self::ExternRef(None)
209            | Self::ExceptionRef(None)
210            | Self::FuncRef(None) => true,
211            Self::ExternRef(Some(e)) => e.is_from_store(store),
212            Self::ExceptionRef(Some(e)) => e.is_from_store(store),
213            Self::FuncRef(Some(f)) => f.is_from_store(store),
214        }
215    }
216
217    accessors! {
218        e
219        (I32(i32) i32 unwrap_i32 *e)
220        (I64(i64) i64 unwrap_i64 *e)
221        (F32(f32) f32 unwrap_f32 *e)
222        (F64(f64) f64 unwrap_f64 *e)
223        (ExternRef(&Option<ExternRef>) externref unwrap_externref e)
224        (FuncRef(&Option<Function>) funcref unwrap_funcref e)
225        (V128(u128) v128 unwrap_v128 *e)
226    }
227}
228
229impl std::fmt::Debug for Value {
230    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231        match self {
232            Self::I32(v) => write!(f, "I32({v:?})"),
233            Self::I64(v) => write!(f, "I64({v:?})"),
234            Self::F32(v) => write!(f, "F32({v:?})"),
235            Self::F64(v) => write!(f, "F64({v:?})"),
236            Self::ExceptionRef(None) => write!(f, "Null ExceptionRef"),
237            Self::ExceptionRef(Some(v)) => write!(f, "ExceptionRef({v:?})"),
238            Self::ExternRef(None) => write!(f, "Null ExternRef"),
239            Self::ExternRef(Some(v)) => write!(f, "ExternRef({v:?})"),
240            Self::FuncRef(None) => write!(f, "Null FuncRef"),
241            Self::FuncRef(Some(v)) => write!(f, "FuncRef({v:?})"),
242            Self::V128(v) => write!(f, "V128({v:?})"),
243        }
244    }
245}
246
247impl std::fmt::Display for Value {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        write!(
250            f,
251            "{}",
252            match self {
253                Self::I32(v) => v.to_string(),
254                Self::I64(v) => v.to_string(),
255                Self::F32(v) => v.to_string(),
256                Self::F64(v) => v.to_string(),
257                Self::ExceptionRef(_) => "exnref".to_string(),
258                Self::ExternRef(_) => "externref".to_string(),
259                Self::FuncRef(_) => "funcref".to_string(),
260                Self::V128(v) => v.to_string(),
261            }
262        )
263    }
264}
265
266impl PartialEq for Value {
267    fn eq(&self, o: &Self) -> bool {
268        match (self, o) {
269            (Self::I32(a), Self::I32(b)) => a == b,
270            (Self::I64(a), Self::I64(b)) => a == b,
271            (Self::F32(a), Self::F32(b)) => a == b,
272            (Self::F64(a), Self::F64(b)) => a == b,
273            (Self::V128(a), Self::V128(b)) => a == b,
274            _ => false,
275        }
276    }
277}
278
279impl From<i32> for Value {
280    fn from(val: i32) -> Self {
281        Self::I32(val)
282    }
283}
284
285impl From<u32> for Value {
286    fn from(val: u32) -> Self {
287        // In Wasm integers are sign-agnostic, so i32 is basically a 4 byte storage we can use for signed or unsigned 32-bit integers.
288        Self::I32(val as i32)
289    }
290}
291
292impl From<i64> for Value {
293    fn from(val: i64) -> Self {
294        Self::I64(val)
295    }
296}
297
298impl From<u64> for Value {
299    fn from(val: u64) -> Self {
300        // In Wasm integers are sign-agnostic, so i64 is basically an 8 byte storage we can use for signed or unsigned 64-bit integers.
301        Self::I64(val as i64)
302    }
303}
304
305impl From<f32> for Value {
306    fn from(val: f32) -> Self {
307        Self::F32(val)
308    }
309}
310
311impl From<f64> for Value {
312    fn from(val: f64) -> Self {
313        Self::F64(val)
314    }
315}
316
317impl From<Function> for Value {
318    fn from(val: Function) -> Self {
319        Self::FuncRef(Some(val))
320    }
321}
322
323impl From<Option<Function>> for Value {
324    fn from(val: Option<Function>) -> Self {
325        Self::FuncRef(val)
326    }
327}
328
329impl From<ExternRef> for Value {
330    fn from(val: ExternRef) -> Self {
331        Self::ExternRef(Some(val))
332    }
333}
334
335impl From<Option<ExternRef>> for Value {
336    fn from(val: Option<ExternRef>) -> Self {
337        Self::ExternRef(val)
338    }
339}
340
341impl From<Exception> for Value {
342    fn from(val: Exception) -> Self {
343        Self::ExceptionRef(Some(val))
344    }
345}
346
347impl From<Option<Exception>> for Value {
348    fn from(val: Option<Exception>) -> Self {
349        Self::ExceptionRef(val)
350    }
351}
352
353const NOT_I32: &str = "Value is not of Wasm type i32";
354const NOT_I64: &str = "Value is not of Wasm type i64";
355const NOT_F32: &str = "Value is not of Wasm type f32";
356const NOT_F64: &str = "Value is not of Wasm type f64";
357const NOT_FUNCREF: &str = "Value is not of Wasm type funcref";
358const NOT_EXTERNREF: &str = "Value is not of Wasm type externref";
359const NOT_EXCEPTIONREF: &str = "Value is not of Wasm type exceptionref";
360
361impl TryFrom<Value> for i32 {
362    type Error = &'static str;
363
364    fn try_from(value: Value) -> Result<Self, Self::Error> {
365        value.i32().ok_or(NOT_I32)
366    }
367}
368
369impl TryFrom<Value> for u32 {
370    type Error = &'static str;
371
372    fn try_from(value: Value) -> Result<Self, Self::Error> {
373        value.i32().ok_or(NOT_I32).map(|int| int as Self)
374    }
375}
376
377impl TryFrom<Value> for i64 {
378    type Error = &'static str;
379
380    fn try_from(value: Value) -> Result<Self, Self::Error> {
381        value.i64().ok_or(NOT_I64)
382    }
383}
384
385impl TryFrom<Value> for u64 {
386    type Error = &'static str;
387
388    fn try_from(value: Value) -> Result<Self, Self::Error> {
389        value.i64().ok_or(NOT_I64).map(|int| int as Self)
390    }
391}
392
393impl TryFrom<Value> for f32 {
394    type Error = &'static str;
395
396    fn try_from(value: Value) -> Result<Self, Self::Error> {
397        value.f32().ok_or(NOT_F32)
398    }
399}
400
401impl TryFrom<Value> for f64 {
402    type Error = &'static str;
403
404    fn try_from(value: Value) -> Result<Self, Self::Error> {
405        value.f64().ok_or(NOT_F64)
406    }
407}
408
409impl TryFrom<Value> for Option<Function> {
410    type Error = &'static str;
411
412    fn try_from(value: Value) -> Result<Self, Self::Error> {
413        match value {
414            Value::FuncRef(f) => Ok(f),
415            _ => Err(NOT_FUNCREF),
416        }
417    }
418}
419
420impl TryFrom<Value> for Option<ExternRef> {
421    type Error = &'static str;
422
423    fn try_from(value: Value) -> Result<Self, Self::Error> {
424        match value {
425            Value::ExternRef(e) => Ok(e),
426            _ => Err(NOT_EXTERNREF),
427        }
428    }
429}
430
431impl TryFrom<Value> for Option<Exception> {
432    type Error = &'static str;
433
434    fn try_from(value: Value) -> Result<Self, Self::Error> {
435        match value {
436            Value::ExceptionRef(e) => Ok(e),
437            _ => Err(NOT_EXCEPTIONREF),
438        }
439    }
440}
441
442#[cfg(test)]
443mod tests {
444    use super::*;
445
446    #[test]
447    fn test_value_i32_from_u32() {
448        let bytes = [0x00, 0x00, 0x00, 0x00];
449        let v = Value::from(u32::from_be_bytes(bytes));
450        assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
451
452        let bytes = [0x00, 0x00, 0x00, 0x01];
453        let v = Value::from(u32::from_be_bytes(bytes));
454        assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
455
456        let bytes = [0xAA, 0xBB, 0xCC, 0xDD];
457        let v = Value::from(u32::from_be_bytes(bytes));
458        assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
459
460        let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
461        let v = Value::from(u32::from_be_bytes(bytes));
462        assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
463    }
464
465    #[test]
466    fn test_value_i64_from_u64() {
467        let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
468        let v = Value::from(u64::from_be_bytes(bytes));
469        assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
470
471        let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
472        let v = Value::from(u64::from_be_bytes(bytes));
473        assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
474
475        let bytes = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11];
476        let v = Value::from(u64::from_be_bytes(bytes));
477        assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
478
479        let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
480        let v = Value::from(u64::from_be_bytes(bytes));
481        assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
482    }
483
484    #[test]
485    fn convert_value_to_i32() {
486        let value = Value::I32(5678);
487        let result = i32::try_from(value);
488        assert_eq!(result.unwrap(), 5678);
489
490        let value = Value::from(u32::MAX);
491        let result = i32::try_from(value);
492        assert_eq!(result.unwrap(), -1);
493
494        let value = Value::V128(42);
495        let result = i32::try_from(value);
496        assert_eq!(result.unwrap_err(), "Value is not of Wasm type i32");
497    }
498
499    #[test]
500    fn convert_value_to_u32() {
501        let value = Value::from(u32::MAX);
502        let result = u32::try_from(value);
503        assert_eq!(result.unwrap(), u32::MAX);
504
505        let value = Value::I32(-1);
506        let result = u32::try_from(value);
507        assert_eq!(result.unwrap(), u32::MAX);
508
509        let value = Value::V128(42);
510        let result = u32::try_from(value);
511        assert_eq!(result.unwrap_err(), "Value is not of Wasm type i32");
512    }
513
514    #[test]
515    fn convert_value_to_i64() {
516        let value = Value::I64(5678);
517        let result = i64::try_from(value);
518        assert_eq!(result.unwrap(), 5678);
519
520        let value = Value::from(u64::MAX);
521        let result = i64::try_from(value);
522        assert_eq!(result.unwrap(), -1);
523
524        let value = Value::V128(42);
525        let result = i64::try_from(value);
526        assert_eq!(result.unwrap_err(), "Value is not of Wasm type i64");
527    }
528
529    #[test]
530    fn convert_value_to_u64() {
531        let value = Value::from(u64::MAX);
532        let result = u64::try_from(value);
533        assert_eq!(result.unwrap(), u64::MAX);
534
535        let value = Value::I64(-1);
536        let result = u64::try_from(value);
537        assert_eq!(result.unwrap(), u64::MAX);
538
539        let value = Value::V128(42);
540        let result = u64::try_from(value);
541        assert_eq!(result.unwrap_err(), "Value is not of Wasm type i64");
542    }
543
544    #[test]
545    fn convert_value_to_f32() {
546        let value = Value::F32(1.234);
547        let result = f32::try_from(value);
548        assert_eq!(result.unwrap(), 1.234);
549
550        let value = Value::V128(42);
551        let result = f32::try_from(value);
552        assert_eq!(result.unwrap_err(), "Value is not of Wasm type f32");
553
554        let value = Value::F64(1.234);
555        let result = f32::try_from(value);
556        assert_eq!(result.unwrap_err(), "Value is not of Wasm type f32");
557    }
558
559    #[test]
560    fn convert_value_to_f64() {
561        let value = Value::F64(1.234);
562        let result = f64::try_from(value);
563        assert_eq!(result.unwrap(), 1.234);
564
565        let value = Value::V128(42);
566        let result = f64::try_from(value);
567        assert_eq!(result.unwrap_err(), "Value is not of Wasm type f64");
568
569        let value = Value::F32(1.234);
570        let result = f64::try_from(value);
571        assert_eq!(result.unwrap_err(), "Value is not of Wasm type f64");
572    }
573}