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 #[cfg(feature = "wamr")]
130 crate::BackendStore::Wamr(_) => Self::FuncRef({
131 unsafe {
132 crate::backend::wamr::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Wamr)
133 }
134 .map(|f| unsafe { Function::from_vm_funcref(store, f) })
135 }),
136 #[cfg(feature = "wasmi")]
137 crate::BackendStore::Wasmi(_) => Self::FuncRef({
138 unsafe {
139 crate::backend::wasmi::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Wasmi)
140 }
141 .map(|f| unsafe { Function::from_vm_funcref(store, f) })
142 }),
143
144 #[cfg(feature = "v8")]
145 crate::BackendStore::V8(_) => Self::FuncRef({
146 unsafe { crate::backend::v8::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::V8) }
147 .map(|f| unsafe { Function::from_vm_funcref(store, f) })
148 }),
149 #[cfg(feature = "js")]
150 crate::BackendStore::Js(_) => Self::FuncRef({
151 unsafe { crate::backend::js::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Js) }
152 .map(|f| unsafe { Function::from_vm_funcref(store, f) })
153 }),
154 #[cfg(feature = "jsc")]
155 crate::BackendStore::Jsc(_) => Self::FuncRef({
156 unsafe { crate::backend::jsc::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Jsc) }
157 .map(|f| unsafe { Function::from_vm_funcref(store, f) })
158 }),
159 },
160 Type::ExternRef => match store.as_store_ref().inner.store {
161 #[cfg(feature = "sys")]
162 crate::BackendStore::Sys(_) => Self::ExternRef({
163 unsafe {
164 crate::backend::sys::vm::VMExternRef::from_raw(raw).map(VMExternRef::Sys)
165 }
166 .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
167 }),
168 #[cfg(feature = "wamr")]
169 crate::BackendStore::Wamr(_) => Self::ExternRef({
170 unsafe {
171 crate::backend::wamr::vm::VMExternRef::from_raw(raw).map(VMExternRef::Wamr)
172 }
173 .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
174 }),
175 #[cfg(feature = "wasmi")]
176 crate::BackendStore::Wasmi(_) => Self::ExternRef({
177 unsafe {
178 crate::backend::wasmi::vm::VMExternRef::from_raw(raw)
179 .map(VMExternRef::Wasmi)
180 }
181 .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
182 }),
183
184 #[cfg(feature = "v8")]
185 crate::BackendStore::V8(_) => Self::ExternRef({
186 unsafe {
187 crate::backend::v8::vm::VMExternRef::from_raw(raw).map(VMExternRef::V8)
188 }
189 .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
190 }),
191 #[cfg(feature = "js")]
192 crate::BackendStore::Js(_) => Self::ExternRef({
193 unsafe {
194 crate::backend::js::vm::VMExternRef::from_raw(raw).map(VMExternRef::Js)
195 }
196 .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
197 }),
198 #[cfg(feature = "jsc")]
199 crate::BackendStore::Jsc(_) => Self::ExternRef({
200 unsafe {
201 crate::backend::jsc::vm::VMExternRef::from_raw(raw).map(VMExternRef::Jsc)
202 }
203 .map(|f| unsafe { ExternRef::from_vm_externref(store, f) })
204 }),
205 },
206 Type::ExceptionRef => match store.as_store_ref().inner.store {
207 #[cfg(feature = "sys")]
208 crate::BackendStore::Sys(_) => Self::ExceptionRef(
209 unsafe {
210 crate::backend::sys::vm::VMExceptionRef::from_raw(
211 store.as_store_ref().objects().id(),
212 raw,
213 )
214 }
215 .map(VMExceptionRef::Sys)
216 .map(Exception::from_vm_exceptionref),
217 ),
218 #[cfg(feature = "wamr")]
219 crate::BackendStore::Wamr(_) => Self::ExceptionRef(
220 unsafe { crate::backend::wamr::vm::VMExceptionRef::from_raw(raw) }
221 .map(VMExceptionRef::Wamr)
222 .map(Exception::from_vm_exceptionref),
223 ),
224 #[cfg(feature = "wasmi")]
225 crate::BackendStore::Wasmi(_) => Self::ExceptionRef(
226 unsafe { crate::backend::wasmi::vm::VMExceptionRef::from_raw(raw) }
227 .map(VMExceptionRef::Wasmi)
228 .map(Exception::from_vm_exceptionref),
229 ),
230
231 #[cfg(feature = "v8")]
232 crate::BackendStore::V8(_) => Self::ExceptionRef(
233 unsafe { crate::backend::v8::vm::VMExceptionRef::from_raw(raw) }
234 .map(VMExceptionRef::V8)
235 .map(Exception::from_vm_exceptionref),
236 ),
237 #[cfg(feature = "js")]
238 crate::BackendStore::Js(_) => Self::ExceptionRef(
239 unsafe { crate::backend::js::vm::VMExceptionRef::from_raw(raw) }
240 .map(VMExceptionRef::Js)
241 .map(Exception::from_vm_exceptionref),
242 ),
243 #[cfg(feature = "jsc")]
244 crate::BackendStore::Jsc(_) => Self::ExceptionRef(
245 unsafe { crate::backend::jsc::vm::VMExceptionRef::from_raw(raw) }
246 .map(VMExceptionRef::Jsc)
247 .map(Exception::from_vm_exceptionref),
248 ),
249 },
250 }
251 }
252
253 pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
261 match self {
262 Self::I32(_)
263 | Self::I64(_)
264 | Self::F32(_)
265 | Self::F64(_)
266 | Self::V128(_)
267 | Self::ExternRef(None)
268 | Self::ExceptionRef(None)
269 | Self::FuncRef(None) => true,
270 Self::ExternRef(Some(e)) => e.is_from_store(store),
271 Self::ExceptionRef(Some(e)) => e.is_from_store(store),
272 Self::FuncRef(Some(f)) => f.is_from_store(store),
273 }
274 }
275
276 accessors! {
277 e
278 (I32(i32) i32 unwrap_i32 *e)
279 (I64(i64) i64 unwrap_i64 *e)
280 (F32(f32) f32 unwrap_f32 *e)
281 (F64(f64) f64 unwrap_f64 *e)
282 (ExternRef(&Option<ExternRef>) externref unwrap_externref e)
283 (FuncRef(&Option<Function>) funcref unwrap_funcref e)
284 (V128(u128) v128 unwrap_v128 *e)
285 }
286}
287
288impl std::fmt::Debug for Value {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 match self {
291 Self::I32(v) => write!(f, "I32({v:?})"),
292 Self::I64(v) => write!(f, "I64({v:?})"),
293 Self::F32(v) => write!(f, "F32({v:?})"),
294 Self::F64(v) => write!(f, "F64({v:?})"),
295 Self::ExceptionRef(None) => write!(f, "Null ExceptionRef"),
296 Self::ExceptionRef(Some(v)) => write!(f, "ExceptionRef({v:?})"),
297 Self::ExternRef(None) => write!(f, "Null ExternRef"),
298 Self::ExternRef(Some(v)) => write!(f, "ExternRef({v:?})"),
299 Self::FuncRef(None) => write!(f, "Null FuncRef"),
300 Self::FuncRef(Some(v)) => write!(f, "FuncRef({v:?})"),
301 Self::V128(v) => write!(f, "V128({v:?})"),
302 }
303 }
304}
305
306impl std::fmt::Display for Value {
307 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308 write!(
309 f,
310 "{}",
311 match self {
312 Self::I32(v) => v.to_string(),
313 Self::I64(v) => v.to_string(),
314 Self::F32(v) => v.to_string(),
315 Self::F64(v) => v.to_string(),
316 Self::ExceptionRef(_) => "exnref".to_string(),
317 Self::ExternRef(_) => "externref".to_string(),
318 Self::FuncRef(_) => "funcref".to_string(),
319 Self::V128(v) => v.to_string(),
320 }
321 )
322 }
323}
324
325impl PartialEq for Value {
326 fn eq(&self, o: &Self) -> bool {
327 match (self, o) {
328 (Self::I32(a), Self::I32(b)) => a == b,
329 (Self::I64(a), Self::I64(b)) => a == b,
330 (Self::F32(a), Self::F32(b)) => a == b,
331 (Self::F64(a), Self::F64(b)) => a == b,
332 (Self::V128(a), Self::V128(b)) => a == b,
333 _ => false,
334 }
335 }
336}
337
338impl From<i32> for Value {
339 fn from(val: i32) -> Self {
340 Self::I32(val)
341 }
342}
343
344impl From<u32> for Value {
345 fn from(val: u32) -> Self {
346 Self::I32(val as i32)
348 }
349}
350
351impl From<i64> for Value {
352 fn from(val: i64) -> Self {
353 Self::I64(val)
354 }
355}
356
357impl From<u64> for Value {
358 fn from(val: u64) -> Self {
359 Self::I64(val as i64)
361 }
362}
363
364impl From<f32> for Value {
365 fn from(val: f32) -> Self {
366 Self::F32(val)
367 }
368}
369
370impl From<f64> for Value {
371 fn from(val: f64) -> Self {
372 Self::F64(val)
373 }
374}
375
376impl From<Function> for Value {
377 fn from(val: Function) -> Self {
378 Self::FuncRef(Some(val))
379 }
380}
381
382impl From<Option<Function>> for Value {
383 fn from(val: Option<Function>) -> Self {
384 Self::FuncRef(val)
385 }
386}
387
388impl From<ExternRef> for Value {
389 fn from(val: ExternRef) -> Self {
390 Self::ExternRef(Some(val))
391 }
392}
393
394impl From<Option<ExternRef>> for Value {
395 fn from(val: Option<ExternRef>) -> Self {
396 Self::ExternRef(val)
397 }
398}
399
400impl From<Exception> for Value {
401 fn from(val: Exception) -> Self {
402 Self::ExceptionRef(Some(val))
403 }
404}
405
406impl From<Option<Exception>> for Value {
407 fn from(val: Option<Exception>) -> Self {
408 Self::ExceptionRef(val)
409 }
410}
411
412const NOT_I32: &str = "Value is not of Wasm type i32";
413const NOT_I64: &str = "Value is not of Wasm type i64";
414const NOT_F32: &str = "Value is not of Wasm type f32";
415const NOT_F64: &str = "Value is not of Wasm type f64";
416const NOT_FUNCREF: &str = "Value is not of Wasm type funcref";
417const NOT_EXTERNREF: &str = "Value is not of Wasm type externref";
418const NOT_EXCEPTIONREF: &str = "Value is not of Wasm type exceptionref";
419
420impl TryFrom<Value> for i32 {
421 type Error = &'static str;
422
423 fn try_from(value: Value) -> Result<Self, Self::Error> {
424 value.i32().ok_or(NOT_I32)
425 }
426}
427
428impl TryFrom<Value> for u32 {
429 type Error = &'static str;
430
431 fn try_from(value: Value) -> Result<Self, Self::Error> {
432 value.i32().ok_or(NOT_I32).map(|int| int as Self)
433 }
434}
435
436impl TryFrom<Value> for i64 {
437 type Error = &'static str;
438
439 fn try_from(value: Value) -> Result<Self, Self::Error> {
440 value.i64().ok_or(NOT_I64)
441 }
442}
443
444impl TryFrom<Value> for u64 {
445 type Error = &'static str;
446
447 fn try_from(value: Value) -> Result<Self, Self::Error> {
448 value.i64().ok_or(NOT_I64).map(|int| int as Self)
449 }
450}
451
452impl TryFrom<Value> for f32 {
453 type Error = &'static str;
454
455 fn try_from(value: Value) -> Result<Self, Self::Error> {
456 value.f32().ok_or(NOT_F32)
457 }
458}
459
460impl TryFrom<Value> for f64 {
461 type Error = &'static str;
462
463 fn try_from(value: Value) -> Result<Self, Self::Error> {
464 value.f64().ok_or(NOT_F64)
465 }
466}
467
468impl TryFrom<Value> for Option<Function> {
469 type Error = &'static str;
470
471 fn try_from(value: Value) -> Result<Self, Self::Error> {
472 match value {
473 Value::FuncRef(f) => Ok(f),
474 _ => Err(NOT_FUNCREF),
475 }
476 }
477}
478
479impl TryFrom<Value> for Option<ExternRef> {
480 type Error = &'static str;
481
482 fn try_from(value: Value) -> Result<Self, Self::Error> {
483 match value {
484 Value::ExternRef(e) => Ok(e),
485 _ => Err(NOT_EXTERNREF),
486 }
487 }
488}
489
490impl TryFrom<Value> for Option<Exception> {
491 type Error = &'static str;
492
493 fn try_from(value: Value) -> Result<Self, Self::Error> {
494 match value {
495 Value::ExceptionRef(e) => Ok(e),
496 _ => Err(NOT_EXCEPTIONREF),
497 }
498 }
499}
500
501#[cfg(test)]
502mod tests {
503 use super::*;
504
505 #[test]
506 fn test_value_i32_from_u32() {
507 let bytes = [0x00, 0x00, 0x00, 0x00];
508 let v = Value::from(u32::from_be_bytes(bytes));
509 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
510
511 let bytes = [0x00, 0x00, 0x00, 0x01];
512 let v = Value::from(u32::from_be_bytes(bytes));
513 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
514
515 let bytes = [0xAA, 0xBB, 0xCC, 0xDD];
516 let v = Value::from(u32::from_be_bytes(bytes));
517 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
518
519 let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
520 let v = Value::from(u32::from_be_bytes(bytes));
521 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
522 }
523
524 #[test]
525 fn test_value_i64_from_u64() {
526 let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
527 let v = Value::from(u64::from_be_bytes(bytes));
528 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
529
530 let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
531 let v = Value::from(u64::from_be_bytes(bytes));
532 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
533
534 let bytes = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11];
535 let v = Value::from(u64::from_be_bytes(bytes));
536 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
537
538 let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
539 let v = Value::from(u64::from_be_bytes(bytes));
540 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
541 }
542
543 #[test]
544 fn convert_value_to_i32() {
545 let value = Value::I32(5678);
546 let result = i32::try_from(value);
547 assert_eq!(result.unwrap(), 5678);
548
549 let value = Value::from(u32::MAX);
550 let result = i32::try_from(value);
551 assert_eq!(result.unwrap(), -1);
552
553 let value = Value::V128(42);
554 let result = i32::try_from(value);
555 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i32");
556 }
557
558 #[test]
559 fn convert_value_to_u32() {
560 let value = Value::from(u32::MAX);
561 let result = u32::try_from(value);
562 assert_eq!(result.unwrap(), u32::MAX);
563
564 let value = Value::I32(-1);
565 let result = u32::try_from(value);
566 assert_eq!(result.unwrap(), u32::MAX);
567
568 let value = Value::V128(42);
569 let result = u32::try_from(value);
570 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i32");
571 }
572
573 #[test]
574 fn convert_value_to_i64() {
575 let value = Value::I64(5678);
576 let result = i64::try_from(value);
577 assert_eq!(result.unwrap(), 5678);
578
579 let value = Value::from(u64::MAX);
580 let result = i64::try_from(value);
581 assert_eq!(result.unwrap(), -1);
582
583 let value = Value::V128(42);
584 let result = i64::try_from(value);
585 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i64");
586 }
587
588 #[test]
589 fn convert_value_to_u64() {
590 let value = Value::from(u64::MAX);
591 let result = u64::try_from(value);
592 assert_eq!(result.unwrap(), u64::MAX);
593
594 let value = Value::I64(-1);
595 let result = u64::try_from(value);
596 assert_eq!(result.unwrap(), u64::MAX);
597
598 let value = Value::V128(42);
599 let result = u64::try_from(value);
600 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i64");
601 }
602
603 #[test]
604 fn convert_value_to_f32() {
605 let value = Value::F32(1.234);
606 let result = f32::try_from(value);
607 assert_eq!(result.unwrap(), 1.234);
608
609 let value = Value::V128(42);
610 let result = f32::try_from(value);
611 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f32");
612
613 let value = Value::F64(1.234);
614 let result = f32::try_from(value);
615 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f32");
616 }
617
618 #[test]
619 fn convert_value_to_f64() {
620 let value = Value::F64(1.234);
621 let result = f64::try_from(value);
622 assert_eq!(result.unwrap(), 1.234);
623
624 let value = Value::V128(42);
625 let result = f64::try_from(value);
626 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f64");
627
628 let value = Value::F32(1.234);
629 let result = f64::try_from(value);
630 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f64");
631 }
632}