1use crate::store::{AutoAssertNoGc, StoreOpaque};
2use crate::{
3 AnyRef, ArrayRef, AsContext, AsContextMut, ExnRef, ExternRef, Func, HeapType, RefType, Rooted,
4 StructRef, V128, ValType, prelude::*,
5};
6use core::ptr;
7
8pub use crate::runtime::vm::ValRaw;
9
10#[derive(Debug, Clone, Copy)]
15pub struct ContRef;
16
17#[derive(Debug, Clone, Copy)]
23pub enum Val {
24 I32(i32),
29
30 I64(i64),
32
33 F32(u32),
38
39 F64(u64),
44
45 V128(V128),
47
48 FuncRef(Option<Func>),
50
51 ExternRef(Option<Rooted<ExternRef>>),
53
54 AnyRef(Option<Rooted<AnyRef>>),
56
57 ExnRef(Option<Rooted<ExnRef>>),
59
60 ContRef(Option<ContRef>),
65}
66
67macro_rules! accessors {
68 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
69 #[inline]
72 pub fn $get(&self) -> Option<$ty> {
73 if let Val::$variant($bind) = self {
74 Some($cvt)
75 } else {
76 None
77 }
78 }
79
80 #[inline]
87 pub fn $unwrap(&self) -> $ty {
88 self.$get().expect(concat!("expected ", stringify!($ty)))
89 }
90 )*)
91}
92
93impl Val {
94 #[inline]
96 pub fn null_ref(heap_type: &HeapType) -> Val {
97 Ref::null(&heap_type).into()
98 }
99
100 #[inline]
105 pub const fn null_func_ref() -> Val {
106 Val::FuncRef(None)
107 }
108
109 #[inline]
114 pub const fn null_extern_ref() -> Val {
115 Val::ExternRef(None)
116 }
117
118 #[inline]
123 pub const fn null_any_ref() -> Val {
124 Val::AnyRef(None)
125 }
126
127 pub fn default_for_ty(ty: &ValType) -> Option<Val> {
132 match ty {
133 ValType::I32 => Some(Val::I32(0)),
134 ValType::I64 => Some(Val::I64(0)),
135 ValType::F32 => Some(Val::F32(0)),
136 ValType::F64 => Some(Val::F64(0)),
137 ValType::V128 => Some(Val::V128(V128::from(0))),
138 ValType::Ref(ref_ty) => {
139 if ref_ty.is_nullable() {
140 Some(Val::null_ref(ref_ty.heap_type()))
141 } else {
142 None
143 }
144 }
145 }
146 }
147
148 #[inline]
159 pub fn ty(&self, store: impl AsContext) -> Result<ValType> {
160 self.load_ty(&store.as_context().0)
161 }
162
163 #[inline]
164 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<ValType> {
165 Ok(match self {
166 Val::I32(_) => ValType::I32,
167 Val::I64(_) => ValType::I64,
168 Val::F32(_) => ValType::F32,
169 Val::F64(_) => ValType::F64,
170 Val::V128(_) => ValType::V128,
171 Val::ExternRef(Some(_)) => ValType::EXTERNREF,
172 Val::ExternRef(None) => ValType::NULLFUNCREF,
173 Val::FuncRef(None) => ValType::NULLFUNCREF,
174 Val::FuncRef(Some(f)) => ValType::Ref(RefType::new(
175 false,
176 HeapType::ConcreteFunc(f.load_ty(store)),
177 )),
178 Val::AnyRef(None) => ValType::NULLREF,
179 Val::AnyRef(Some(a)) => ValType::Ref(RefType::new(false, a._ty(store)?)),
180 Val::ExnRef(None) => ValType::NULLEXNREF,
181 Val::ExnRef(Some(e)) => ValType::Ref(RefType::new(false, e._ty(store)?.into())),
182 Val::ContRef(_) => {
183 return Err(crate::format_err!(
185 "continuation references not yet supported in embedder API"
186 ));
187 }
188 })
189 }
190
191 pub fn matches_ty(&self, store: impl AsContext, ty: &ValType) -> Result<bool> {
199 self._matches_ty(&store.as_context().0, ty)
200 }
201
202 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<bool> {
203 assert!(self.comes_from_same_store(store));
204 assert!(ty.comes_from_same_engine(store.engine()));
205 Ok(match (self, ty) {
206 (Val::I32(_), ValType::I32)
207 | (Val::I64(_), ValType::I64)
208 | (Val::F32(_), ValType::F32)
209 | (Val::F64(_), ValType::F64)
210 | (Val::V128(_), ValType::V128) => true,
211
212 (Val::FuncRef(f), ValType::Ref(ref_ty)) => Ref::from(*f)._matches_ty(store, ref_ty)?,
213 (Val::ExternRef(e), ValType::Ref(ref_ty)) => {
214 Ref::from(*e)._matches_ty(store, ref_ty)?
215 }
216 (Val::AnyRef(a), ValType::Ref(ref_ty)) => Ref::from(*a)._matches_ty(store, ref_ty)?,
217 (Val::ExnRef(e), ValType::Ref(ref_ty)) => Ref::from(*e)._matches_ty(store, ref_ty)?,
218
219 (Val::I32(_), _)
220 | (Val::I64(_), _)
221 | (Val::F32(_), _)
222 | (Val::F64(_), _)
223 | (Val::V128(_), _)
224 | (Val::FuncRef(_), _)
225 | (Val::ExternRef(_), _)
226 | (Val::AnyRef(_), _)
227 | (Val::ExnRef(_), _)
228 | (Val::ContRef(_), _) => false,
229 })
230 }
231
232 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<()> {
233 if !self.comes_from_same_store(store) {
234 bail!("value used with wrong store")
235 }
236 if !ty.comes_from_same_engine(store.engine()) {
237 bail!("type used with wrong engine")
238 }
239 if self._matches_ty(store, ty)? {
240 Ok(())
241 } else {
242 let actual_ty = self.load_ty(store)?;
243 bail!("type mismatch: expected {ty}, found {actual_ty}")
244 }
245 }
246
247 pub fn to_raw(&self, mut store: impl AsContextMut) -> Result<ValRaw> {
258 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
259 self.to_raw_(&mut store)
260 }
261
262 pub(crate) fn to_raw_(&self, store: &mut AutoAssertNoGc) -> Result<ValRaw> {
263 match self {
264 Val::I32(i) => Ok(ValRaw::i32(*i)),
265 Val::I64(i) => Ok(ValRaw::i64(*i)),
266 Val::F32(u) => Ok(ValRaw::f32(*u)),
267 Val::F64(u) => Ok(ValRaw::f64(*u)),
268 Val::V128(b) => Ok(ValRaw::v128(b.as_u128())),
269 Val::ExternRef(e) => Ok(ValRaw::externref(match e {
270 None => 0,
271 Some(e) => e._to_raw(store)?,
272 })),
273 Val::AnyRef(e) => Ok(ValRaw::anyref(match e {
274 None => 0,
275 Some(e) => e._to_raw(store)?,
276 })),
277 Val::ExnRef(e) => Ok(ValRaw::exnref(match e {
278 None => 0,
279 Some(e) => e._to_raw(store)?,
280 })),
281 Val::FuncRef(f) => Ok(ValRaw::funcref(match f {
282 Some(f) => f.to_raw_(store),
283 None => ptr::null_mut(),
284 })),
285 Val::ContRef(_) => {
286 Err(crate::format_err!(
288 "continuation references not yet supported in to_raw conversion"
289 ))
290 }
291 }
292 }
293
294 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
302 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
303 unsafe { Self::_from_raw(&mut store, raw, &ty) }
305 }
306
307 pub(crate) unsafe fn _from_raw(
309 store: &mut AutoAssertNoGc<'_>,
310 raw: ValRaw,
311 ty: &ValType,
312 ) -> Val {
313 match ty {
314 ValType::I32 => Val::I32(raw.get_i32()),
315 ValType::I64 => Val::I64(raw.get_i64()),
316 ValType::F32 => Val::F32(raw.get_f32()),
317 ValType::F64 => Val::F64(raw.get_f64()),
318 ValType::V128 => Val::V128(raw.get_v128().into()),
319 ValType::Ref(ref_ty) => {
320 let ref_ = match ref_ty.heap_type() {
321 HeapType::Func | HeapType::ConcreteFunc(_) => unsafe {
324 Func::_from_raw(store, raw.get_funcref()).into()
325 },
326
327 HeapType::NoFunc => Ref::Func(None),
328
329 HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => {
330 unimplemented!()
332 }
333
334 HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
335
336 HeapType::NoExtern => Ref::Extern(None),
337
338 HeapType::Any
339 | HeapType::Eq
340 | HeapType::I31
341 | HeapType::Array
342 | HeapType::ConcreteArray(_)
343 | HeapType::Struct
344 | HeapType::ConcreteStruct(_) => {
345 AnyRef::_from_raw(store, raw.get_anyref()).into()
346 }
347
348 HeapType::Exn | HeapType::ConcreteExn(_) => {
349 ExnRef::_from_raw(store, raw.get_exnref()).into()
350 }
351 HeapType::NoExn => Ref::Exn(None),
352
353 HeapType::None => Ref::Any(None),
354 };
355 assert!(
356 ref_ty.is_nullable() || !ref_.is_null(),
357 "if the type is not nullable, we shouldn't get null; got \
358 type = {ref_ty}, ref = {ref_:?}"
359 );
360 ref_.into()
361 }
362 }
363 }
364
365 accessors! {
366 e
367 (I32(i32) i32 unwrap_i32 *e)
368 (I64(i64) i64 unwrap_i64 *e)
369 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
370 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
371 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
372 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
373 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
374 (V128(V128) v128 unwrap_v128 *e)
375 }
376
377 #[inline]
379 pub fn ref_(self) -> Option<Ref> {
380 match self {
381 Val::FuncRef(f) => Some(Ref::Func(f)),
382 Val::ExternRef(e) => Some(Ref::Extern(e)),
383 Val::AnyRef(a) => Some(Ref::Any(a)),
384 Val::ExnRef(e) => Some(Ref::Exn(e)),
385 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
386 Val::ContRef(_) => None, }
388 }
389
390 #[inline]
398 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
399 match self {
400 Val::ExternRef(None) => Some(None),
401 Val::ExternRef(Some(e)) => Some(Some(e)),
402 _ => None,
403 }
404 }
405
406 #[inline]
417 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
418 self.externref().expect("expected externref")
419 }
420
421 #[inline]
429 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
430 match self {
431 Val::AnyRef(None) => Some(None),
432 Val::AnyRef(Some(e)) => Some(Some(e)),
433 _ => None,
434 }
435 }
436
437 #[inline]
448 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
449 self.anyref().expect("expected anyref")
450 }
451
452 #[inline]
460 pub fn exnref(&self) -> Option<Option<&Rooted<ExnRef>>> {
461 match self {
462 Val::ExnRef(None) => Some(None),
463 Val::ExnRef(Some(e)) => Some(Some(e)),
464 _ => None,
465 }
466 }
467
468 #[inline]
479 pub fn unwrap_exnref(&self) -> Option<&Rooted<ExnRef>> {
480 self.exnref().expect("expected exnref")
481 }
482
483 #[inline]
491 pub fn funcref(&self) -> Option<Option<&Func>> {
492 match self {
493 Val::FuncRef(None) => Some(None),
494 Val::FuncRef(Some(f)) => Some(Some(f)),
495 _ => None,
496 }
497 }
498
499 #[inline]
510 pub fn unwrap_funcref(&self) -> Option<&Func> {
511 self.funcref().expect("expected funcref")
512 }
513
514 #[inline]
515 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
516 match self {
517 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
518 Val::FuncRef(None) => true,
519
520 Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
521 Val::ExternRef(None) => true,
522
523 Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
524 Val::AnyRef(None) => true,
525
526 Val::ExnRef(Some(e)) => e.comes_from_same_store(store),
527 Val::ExnRef(None) => true,
528
529 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
533
534 Val::ContRef(_) => true, }
537 }
538}
539
540impl From<i32> for Val {
541 #[inline]
542 fn from(val: i32) -> Val {
543 Val::I32(val)
544 }
545}
546
547impl From<i64> for Val {
548 #[inline]
549 fn from(val: i64) -> Val {
550 Val::I64(val)
551 }
552}
553
554impl From<f32> for Val {
555 #[inline]
556 fn from(val: f32) -> Val {
557 Val::F32(val.to_bits())
558 }
559}
560
561impl From<f64> for Val {
562 #[inline]
563 fn from(val: f64) -> Val {
564 Val::F64(val.to_bits())
565 }
566}
567
568impl From<Ref> for Val {
569 #[inline]
570 fn from(val: Ref) -> Val {
571 match val {
572 Ref::Extern(e) => Val::ExternRef(e),
573 Ref::Func(f) => Val::FuncRef(f),
574 Ref::Any(a) => Val::AnyRef(a),
575 Ref::Exn(e) => Val::ExnRef(e),
576 }
577 }
578}
579
580impl From<Rooted<ExternRef>> for Val {
581 #[inline]
582 fn from(val: Rooted<ExternRef>) -> Val {
583 Val::ExternRef(Some(val))
584 }
585}
586
587impl From<Option<Rooted<ExternRef>>> for Val {
588 #[inline]
589 fn from(val: Option<Rooted<ExternRef>>) -> Val {
590 Val::ExternRef(val)
591 }
592}
593
594impl From<Rooted<AnyRef>> for Val {
595 #[inline]
596 fn from(val: Rooted<AnyRef>) -> Val {
597 Val::AnyRef(Some(val))
598 }
599}
600
601impl From<Option<Rooted<AnyRef>>> for Val {
602 #[inline]
603 fn from(val: Option<Rooted<AnyRef>>) -> Val {
604 Val::AnyRef(val)
605 }
606}
607
608impl From<Rooted<StructRef>> for Val {
609 #[inline]
610 fn from(val: Rooted<StructRef>) -> Val {
611 Val::AnyRef(Some(val.into()))
612 }
613}
614
615impl From<Option<Rooted<StructRef>>> for Val {
616 #[inline]
617 fn from(val: Option<Rooted<StructRef>>) -> Val {
618 Val::AnyRef(val.map(Into::into))
619 }
620}
621
622impl From<Rooted<ArrayRef>> for Val {
623 #[inline]
624 fn from(val: Rooted<ArrayRef>) -> Val {
625 Val::AnyRef(Some(val.into()))
626 }
627}
628
629impl From<Option<Rooted<ArrayRef>>> for Val {
630 #[inline]
631 fn from(val: Option<Rooted<ArrayRef>>) -> Val {
632 Val::AnyRef(val.map(Into::into))
633 }
634}
635
636impl From<Rooted<ExnRef>> for Val {
637 #[inline]
638 fn from(val: Rooted<ExnRef>) -> Val {
639 Val::ExnRef(Some(val))
640 }
641}
642
643impl From<Option<Rooted<ExnRef>>> for Val {
644 #[inline]
645 fn from(val: Option<Rooted<ExnRef>>) -> Val {
646 Val::ExnRef(val)
647 }
648}
649
650impl From<Func> for Val {
651 #[inline]
652 fn from(val: Func) -> Val {
653 Val::FuncRef(Some(val))
654 }
655}
656
657impl From<Option<Func>> for Val {
658 #[inline]
659 fn from(val: Option<Func>) -> Val {
660 Val::FuncRef(val)
661 }
662}
663
664impl From<u128> for Val {
665 #[inline]
666 fn from(val: u128) -> Val {
667 Val::V128(val.into())
668 }
669}
670
671impl From<V128> for Val {
672 #[inline]
673 fn from(val: V128) -> Val {
674 Val::V128(val)
675 }
676}
677
678#[derive(Debug, Clone)]
703pub enum Ref {
704 Func(Option<Func>),
741
742 Extern(Option<Rooted<ExternRef>>),
752
753 Any(Option<Rooted<AnyRef>>),
762
763 Exn(Option<Rooted<ExnRef>>),
770}
771
772impl From<Func> for Ref {
773 #[inline]
774 fn from(f: Func) -> Ref {
775 Ref::Func(Some(f))
776 }
777}
778
779impl From<Option<Func>> for Ref {
780 #[inline]
781 fn from(f: Option<Func>) -> Ref {
782 Ref::Func(f)
783 }
784}
785
786impl From<Rooted<ExternRef>> for Ref {
787 #[inline]
788 fn from(e: Rooted<ExternRef>) -> Ref {
789 Ref::Extern(Some(e))
790 }
791}
792
793impl From<Option<Rooted<ExternRef>>> for Ref {
794 #[inline]
795 fn from(e: Option<Rooted<ExternRef>>) -> Ref {
796 Ref::Extern(e)
797 }
798}
799
800impl From<Rooted<AnyRef>> for Ref {
801 #[inline]
802 fn from(e: Rooted<AnyRef>) -> Ref {
803 Ref::Any(Some(e))
804 }
805}
806
807impl From<Option<Rooted<AnyRef>>> for Ref {
808 #[inline]
809 fn from(e: Option<Rooted<AnyRef>>) -> Ref {
810 Ref::Any(e)
811 }
812}
813
814impl From<Rooted<StructRef>> for Ref {
815 #[inline]
816 fn from(e: Rooted<StructRef>) -> Ref {
817 Ref::Any(Some(e.into()))
818 }
819}
820
821impl From<Option<Rooted<StructRef>>> for Ref {
822 #[inline]
823 fn from(e: Option<Rooted<StructRef>>) -> Ref {
824 Ref::Any(e.map(Into::into))
825 }
826}
827
828impl From<Rooted<ArrayRef>> for Ref {
829 #[inline]
830 fn from(e: Rooted<ArrayRef>) -> Ref {
831 Ref::Any(Some(e.into()))
832 }
833}
834
835impl From<Option<Rooted<ArrayRef>>> for Ref {
836 #[inline]
837 fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
838 Ref::Any(e.map(Into::into))
839 }
840}
841
842impl From<Rooted<ExnRef>> for Ref {
843 #[inline]
844 fn from(e: Rooted<ExnRef>) -> Ref {
845 Ref::Exn(Some(e))
846 }
847}
848
849impl From<Option<Rooted<ExnRef>>> for Ref {
850 #[inline]
851 fn from(e: Option<Rooted<ExnRef>>) -> Ref {
852 Ref::Exn(e)
853 }
854}
855
856impl Ref {
857 #[inline]
859 pub fn null(heap_type: &HeapType) -> Self {
860 match heap_type.top() {
861 HeapType::Any => Ref::Any(None),
862 HeapType::Extern => Ref::Extern(None),
863 HeapType::Func => Ref::Func(None),
864 HeapType::Exn => Ref::Exn(None),
865 ty => unreachable!("not a heap type: {ty:?}"),
866 }
867 }
868
869 #[inline]
871 pub fn is_null(&self) -> bool {
872 match self {
873 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) | Ref::Exn(None) => true,
874 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) | Ref::Exn(Some(_)) => {
875 false
876 }
877 }
878 }
879
880 #[inline]
882 pub fn is_non_null(&self) -> bool {
883 !self.is_null()
884 }
885
886 #[inline]
888 pub fn is_extern(&self) -> bool {
889 matches!(self, Ref::Extern(_))
890 }
891
892 #[inline]
901 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
902 match self {
903 Ref::Extern(e) => Some(e.as_ref()),
904 _ => None,
905 }
906 }
907
908 #[inline]
915 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
916 self.as_extern()
917 .expect("Ref::unwrap_extern on non-extern reference")
918 }
919
920 #[inline]
922 pub fn is_any(&self) -> bool {
923 matches!(self, Ref::Any(_))
924 }
925
926 #[inline]
935 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
936 match self {
937 Ref::Any(e) => Some(e.as_ref()),
938 _ => None,
939 }
940 }
941
942 #[inline]
949 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
950 self.as_any().expect("Ref::unwrap_any on non-any reference")
951 }
952
953 #[inline]
955 pub fn is_exn(&self) -> bool {
956 matches!(self, Ref::Exn(_))
957 }
958
959 #[inline]
968 pub fn as_exn(&self) -> Option<Option<&Rooted<ExnRef>>> {
969 match self {
970 Ref::Exn(e) => Some(e.as_ref()),
971 _ => None,
972 }
973 }
974
975 #[inline]
982 pub fn unwrap_exn(&self) -> Option<&Rooted<ExnRef>> {
983 self.as_exn().expect("Ref::unwrap_exn on non-exn reference")
984 }
985
986 #[inline]
988 pub fn is_func(&self) -> bool {
989 matches!(self, Ref::Func(_))
990 }
991
992 #[inline]
1001 pub fn as_func(&self) -> Option<Option<&Func>> {
1002 match self {
1003 Ref::Func(f) => Some(f.as_ref()),
1004 _ => None,
1005 }
1006 }
1007
1008 #[inline]
1015 pub fn unwrap_func(&self) -> Option<&Func> {
1016 self.as_func()
1017 .expect("Ref::unwrap_func on non-func reference")
1018 }
1019
1020 pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
1030 self.load_ty(&store.as_context().0)
1031 }
1032
1033 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
1034 assert!(self.comes_from_same_store(store));
1035 Ok(RefType::new(
1036 self.is_null(),
1037 match self {
1041 Ref::Extern(None) => HeapType::NoExtern,
1042 Ref::Extern(Some(_)) => HeapType::Extern,
1043
1044 Ref::Func(None) => HeapType::NoFunc,
1045 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
1046
1047 Ref::Any(None) => HeapType::None,
1048 Ref::Any(Some(a)) => a._ty(store)?,
1049
1050 Ref::Exn(None) => HeapType::None,
1051 Ref::Exn(Some(e)) => e._ty(store)?.into(),
1052 },
1053 ))
1054 }
1055
1056 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
1064 self._matches_ty(&store.as_context().0, ty)
1065 }
1066
1067 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
1068 assert!(self.comes_from_same_store(store));
1069 assert!(ty.comes_from_same_engine(store.engine()));
1070 if self.is_null() && !ty.is_nullable() {
1071 return Ok(false);
1072 }
1073 Ok(match (self, ty.heap_type()) {
1074 (Ref::Extern(_), HeapType::Extern) => true,
1075 (Ref::Extern(None), HeapType::NoExtern) => true,
1076 (Ref::Extern(_), _) => false,
1077
1078 (Ref::Func(_), HeapType::Func) => true,
1079 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
1080 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
1081 (Ref::Func(_), _) => false,
1082
1083 (Ref::Any(_), HeapType::Any) => true,
1084 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
1085 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
1086 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
1087 None => false,
1088 Some(s) => s._matches_ty(store, _ty)?,
1089 },
1090 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
1091 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
1092 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
1093 None => false,
1094 Some(a) => a._matches_ty(store, _ty)?,
1095 },
1096 (
1097 Ref::Any(None),
1098 HeapType::None
1099 | HeapType::I31
1100 | HeapType::ConcreteStruct(_)
1101 | HeapType::Struct
1102 | HeapType::ConcreteArray(_)
1103 | HeapType::Array
1104 | HeapType::Eq,
1105 ) => true,
1106 (Ref::Any(_), _) => false,
1107
1108 (Ref::Exn(_), HeapType::Exn) => true,
1109 (Ref::Exn(None), HeapType::NoExn | HeapType::ConcreteExn(_)) => true,
1110 (Ref::Exn(Some(e)), HeapType::ConcreteExn(_)) => {
1111 e._matches_ty(store, &ty.heap_type())?
1112 }
1113 (Ref::Exn(_), _) => false,
1114 })
1115 }
1116
1117 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
1118 if !self.comes_from_same_store(store) {
1119 bail!("reference used with wrong store")
1120 }
1121 if !ty.comes_from_same_engine(store.engine()) {
1122 bail!("type used with wrong engine")
1123 }
1124 if self._matches_ty(store, ty)? {
1125 Ok(())
1126 } else {
1127 let actual_ty = self.load_ty(store)?;
1128 bail!("type mismatch: expected {ty}, found {actual_ty}")
1129 }
1130 }
1131
1132 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
1133 match self {
1134 Ref::Func(Some(f)) => f.comes_from_same_store(store),
1135 Ref::Func(None) => true,
1136 Ref::Extern(Some(x)) => x.comes_from_same_store(store),
1137 Ref::Extern(None) => true,
1138 Ref::Any(Some(a)) => a.comes_from_same_store(store),
1139 Ref::Any(None) => true,
1140 Ref::Exn(Some(e)) => e.comes_from_same_store(store),
1141 Ref::Exn(None) => true,
1142 }
1143 }
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148 use crate::*;
1149
1150 #[test]
1151 fn size_of_val() {
1152 let expected = if cfg!(target_arch = "x86_64")
1155 || cfg!(target_arch = "aarch64")
1156 || cfg!(target_arch = "s390x")
1157 || cfg!(target_arch = "riscv64")
1158 || cfg!(target_arch = "arm")
1159 {
1160 24
1161 } else if cfg!(target_arch = "x86") {
1162 20
1163 } else {
1164 panic!("unsupported architecture")
1165 };
1166 assert_eq!(std::mem::size_of::<Val>(), expected);
1167 }
1168
1169 #[test]
1170 fn size_of_ref() {
1171 let expected = if cfg!(target_arch = "x86_64")
1174 || cfg!(target_arch = "aarch64")
1175 || cfg!(target_arch = "s390x")
1176 || cfg!(target_arch = "riscv64")
1177 || cfg!(target_arch = "arm")
1178 {
1179 24
1180 } else if cfg!(target_arch = "x86") {
1181 20
1182 } else {
1183 panic!("unsupported architecture")
1184 };
1185 assert_eq!(std::mem::size_of::<Ref>(), expected);
1186 }
1187
1188 #[test]
1189 #[should_panic]
1190 fn val_matches_ty_wrong_engine() {
1191 let e1 = Engine::default();
1192 let e2 = Engine::default();
1193
1194 let t1 = FuncType::new(&e1, None, None);
1195 let t2 = FuncType::new(&e2, None, None);
1196
1197 let mut s1 = Store::new(&e1, ());
1198 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1199
1200 let _ = Val::FuncRef(Some(f)).matches_ty(
1202 &s1,
1203 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1204 );
1205 }
1206
1207 #[test]
1208 #[should_panic]
1209 fn ref_matches_ty_wrong_engine() {
1210 let e1 = Engine::default();
1211 let e2 = Engine::default();
1212
1213 let t1 = FuncType::new(&e1, None, None);
1214 let t2 = FuncType::new(&e2, None, None);
1215
1216 let mut s1 = Store::new(&e1, ());
1217 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1218
1219 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1221 }
1222}