1use wasmer_types::{RawValue, Type};
2
3use crate::{
4 AsStoreRef, Tag,
5 entities::{Exception, ExternRef, Function},
6 vm::{VMExceptionRef, VMExternRef, VMFuncRef},
7};
8
9#[derive(Clone)]
16pub enum Value {
17 I32(i32),
21
22 I64(i64),
26
27 F32(f32),
29
30 F64(f64),
32
33 V128(u128),
35
36 ExternRef(Option<ExternRef>),
39
40 FuncRef(Option<Function>),
42
43 ExceptionRef(Option<Exception>),
45}
46
47macro_rules! accessors {
48 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
49 pub fn $get(&self) -> Option<$ty> {
52 if let Self::$variant($bind) = self {
53 Some($cvt)
54 } else {
55 None
56 }
57 }
58
59 pub fn $unwrap(&self) -> $ty {
66 self.$get().expect(concat!("expected ", stringify!($ty)))
67 }
68 )*)
69}
70
71impl Value {
72 pub fn null() -> Self {
74 Self::ExternRef(None)
75 }
76
77 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 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 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 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 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 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}