wasmer/
value.rs

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