linera_wasmer/
value.rs

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