1use crate::runtime::vm::TableElement;
2use crate::store::{AutoAssertNoGc, StoreOpaque};
3use crate::{
4 AnyRef, ArrayRef, AsContext, AsContextMut, ExternRef, Func, HeapType, RefType, Rooted,
5 RootedGcRefImpl, StructRef, V128, ValType, prelude::*,
6};
7use core::ptr;
8
9pub use crate::runtime::vm::ValRaw;
10
11#[derive(Debug, Clone, Copy)]
17pub enum Val {
18 I32(i32),
23
24 I64(i64),
26
27 F32(u32),
32
33 F64(u64),
38
39 V128(V128),
41
42 FuncRef(Option<Func>),
44
45 ExternRef(Option<Rooted<ExternRef>>),
47
48 AnyRef(Option<Rooted<AnyRef>>),
50}
51
52macro_rules! accessors {
53 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
54 #[inline]
57 pub fn $get(&self) -> Option<$ty> {
58 if let Val::$variant($bind) = self {
59 Some($cvt)
60 } else {
61 None
62 }
63 }
64
65 #[inline]
72 pub fn $unwrap(&self) -> $ty {
73 self.$get().expect(concat!("expected ", stringify!($ty)))
74 }
75 )*)
76}
77
78impl Val {
79 #[inline]
81 pub fn null_ref(heap_type: &HeapType) -> Val {
82 Ref::null(&heap_type).into()
83 }
84
85 #[inline]
90 pub const fn null_func_ref() -> Val {
91 Val::FuncRef(None)
92 }
93
94 #[inline]
99 pub const fn null_extern_ref() -> Val {
100 Val::ExternRef(None)
101 }
102
103 #[inline]
108 pub const fn null_any_ref() -> Val {
109 Val::AnyRef(None)
110 }
111
112 pub fn default_for_ty(ty: &ValType) -> Option<Val> {
117 match ty {
118 ValType::I32 => Some(Val::I32(0)),
119 ValType::I64 => Some(Val::I64(0)),
120 ValType::F32 => Some(Val::F32(0)),
121 ValType::F64 => Some(Val::F64(0)),
122 ValType::V128 => Some(Val::V128(V128::from(0))),
123 ValType::Ref(ref_ty) => {
124 if ref_ty.is_nullable() {
125 Some(Val::null_ref(ref_ty.heap_type()))
126 } else {
127 None
128 }
129 }
130 }
131 }
132
133 #[inline]
144 pub fn ty(&self, store: impl AsContext) -> Result<ValType> {
145 self.load_ty(&store.as_context().0)
146 }
147
148 #[inline]
149 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<ValType> {
150 Ok(match self {
151 Val::I32(_) => ValType::I32,
152 Val::I64(_) => ValType::I64,
153 Val::F32(_) => ValType::F32,
154 Val::F64(_) => ValType::F64,
155 Val::V128(_) => ValType::V128,
156 Val::ExternRef(Some(_)) => ValType::EXTERNREF,
157 Val::ExternRef(None) => ValType::NULLFUNCREF,
158 Val::FuncRef(None) => ValType::NULLFUNCREF,
159 Val::FuncRef(Some(f)) => ValType::Ref(RefType::new(
160 false,
161 HeapType::ConcreteFunc(f.load_ty(store)),
162 )),
163 Val::AnyRef(None) => ValType::NULLREF,
164 Val::AnyRef(Some(a)) => ValType::Ref(RefType::new(false, a._ty(store)?)),
165 })
166 }
167
168 pub fn matches_ty(&self, store: impl AsContext, ty: &ValType) -> Result<bool> {
176 self._matches_ty(&store.as_context().0, ty)
177 }
178
179 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<bool> {
180 assert!(self.comes_from_same_store(store));
181 assert!(ty.comes_from_same_engine(store.engine()));
182 Ok(match (self, ty) {
183 (Val::I32(_), ValType::I32)
184 | (Val::I64(_), ValType::I64)
185 | (Val::F32(_), ValType::F32)
186 | (Val::F64(_), ValType::F64)
187 | (Val::V128(_), ValType::V128) => true,
188
189 (Val::FuncRef(f), ValType::Ref(ref_ty)) => Ref::from(*f)._matches_ty(store, ref_ty)?,
190 (Val::ExternRef(e), ValType::Ref(ref_ty)) => {
191 Ref::from(*e)._matches_ty(store, ref_ty)?
192 }
193 (Val::AnyRef(a), ValType::Ref(ref_ty)) => Ref::from(*a)._matches_ty(store, ref_ty)?,
194
195 (Val::I32(_), _)
196 | (Val::I64(_), _)
197 | (Val::F32(_), _)
198 | (Val::F64(_), _)
199 | (Val::V128(_), _)
200 | (Val::FuncRef(_), _)
201 | (Val::ExternRef(_), _)
202 | (Val::AnyRef(_), _) => false,
203 })
204 }
205
206 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<()> {
207 if !self.comes_from_same_store(store) {
208 bail!("value used with wrong store")
209 }
210 if !ty.comes_from_same_engine(store.engine()) {
211 bail!("type used with wrong engine")
212 }
213 if self._matches_ty(store, ty)? {
214 Ok(())
215 } else {
216 let actual_ty = self.load_ty(store)?;
217 bail!("type mismatch: expected {ty}, found {actual_ty}")
218 }
219 }
220
221 pub unsafe fn to_raw(&self, store: impl AsContextMut) -> Result<ValRaw> {
231 match self {
232 Val::I32(i) => Ok(ValRaw::i32(*i)),
233 Val::I64(i) => Ok(ValRaw::i64(*i)),
234 Val::F32(u) => Ok(ValRaw::f32(*u)),
235 Val::F64(u) => Ok(ValRaw::f64(*u)),
236 Val::V128(b) => Ok(ValRaw::v128(b.as_u128())),
237 Val::ExternRef(e) => Ok(ValRaw::externref(match e {
238 None => 0,
239 Some(e) => e.to_raw(store)?,
240 })),
241 Val::AnyRef(e) => Ok(ValRaw::anyref(match e {
242 None => 0,
243 Some(e) => e.to_raw(store)?,
244 })),
245 Val::FuncRef(f) => Ok(ValRaw::funcref(match f {
246 Some(f) => f.to_raw(store),
247 None => ptr::null_mut(),
248 })),
249 }
250 }
251
252 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
260 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
261 Self::_from_raw(&mut store, raw, &ty)
262 }
263
264 pub(crate) unsafe fn _from_raw(
265 store: &mut AutoAssertNoGc<'_>,
266 raw: ValRaw,
267 ty: &ValType,
268 ) -> Val {
269 match ty {
270 ValType::I32 => Val::I32(raw.get_i32()),
271 ValType::I64 => Val::I64(raw.get_i64()),
272 ValType::F32 => Val::F32(raw.get_f32()),
273 ValType::F64 => Val::F64(raw.get_f64()),
274 ValType::V128 => Val::V128(raw.get_v128().into()),
275 ValType::Ref(ref_ty) => {
276 let ref_ = match ref_ty.heap_type() {
277 HeapType::Func | HeapType::ConcreteFunc(_) => {
278 Func::_from_raw(store, raw.get_funcref()).into()
279 }
280
281 HeapType::NoFunc => Ref::Func(None),
282
283 HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => {
284 unimplemented!()
286 }
287
288 HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
289
290 HeapType::NoExtern => Ref::Extern(None),
291
292 HeapType::Any
293 | HeapType::Eq
294 | HeapType::I31
295 | HeapType::Array
296 | HeapType::ConcreteArray(_)
297 | HeapType::Struct
298 | HeapType::ConcreteStruct(_) => {
299 AnyRef::_from_raw(store, raw.get_anyref()).into()
300 }
301
302 HeapType::None => Ref::Any(None),
303 };
304 assert!(
305 ref_ty.is_nullable() || !ref_.is_null(),
306 "if the type is not nullable, we shouldn't get null; got \
307 type = {ref_ty}, ref = {ref_:?}"
308 );
309 ref_.into()
310 }
311 }
312 }
313
314 accessors! {
315 e
316 (I32(i32) i32 unwrap_i32 *e)
317 (I64(i64) i64 unwrap_i64 *e)
318 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
319 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
320 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
321 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
322 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
323 (V128(V128) v128 unwrap_v128 *e)
324 }
325
326 #[inline]
328 pub fn ref_(self) -> Option<Ref> {
329 match self {
330 Val::FuncRef(f) => Some(Ref::Func(f)),
331 Val::ExternRef(e) => Some(Ref::Extern(e)),
332 Val::AnyRef(a) => Some(Ref::Any(a)),
333 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
334 }
335 }
336
337 #[inline]
345 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
346 match self {
347 Val::ExternRef(None) => Some(None),
348 Val::ExternRef(Some(e)) => Some(Some(e)),
349 _ => None,
350 }
351 }
352
353 #[inline]
364 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
365 self.externref().expect("expected externref")
366 }
367
368 #[inline]
376 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
377 match self {
378 Val::AnyRef(None) => Some(None),
379 Val::AnyRef(Some(e)) => Some(Some(e)),
380 _ => None,
381 }
382 }
383
384 #[inline]
395 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
396 self.anyref().expect("expected anyref")
397 }
398
399 #[inline]
407 pub fn funcref(&self) -> Option<Option<&Func>> {
408 match self {
409 Val::FuncRef(None) => Some(None),
410 Val::FuncRef(Some(f)) => Some(Some(f)),
411 _ => None,
412 }
413 }
414
415 #[inline]
426 pub fn unwrap_funcref(&self) -> Option<&Func> {
427 self.funcref().expect("expected funcref")
428 }
429
430 #[inline]
431 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
432 match self {
433 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
434 Val::FuncRef(None) => true,
435
436 Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
437 Val::ExternRef(None) => true,
438
439 Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
440 Val::AnyRef(None) => true,
441
442 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
446 }
447 }
448}
449
450impl From<i32> for Val {
451 #[inline]
452 fn from(val: i32) -> Val {
453 Val::I32(val)
454 }
455}
456
457impl From<i64> for Val {
458 #[inline]
459 fn from(val: i64) -> Val {
460 Val::I64(val)
461 }
462}
463
464impl From<f32> for Val {
465 #[inline]
466 fn from(val: f32) -> Val {
467 Val::F32(val.to_bits())
468 }
469}
470
471impl From<f64> for Val {
472 #[inline]
473 fn from(val: f64) -> Val {
474 Val::F64(val.to_bits())
475 }
476}
477
478impl From<Ref> for Val {
479 #[inline]
480 fn from(val: Ref) -> Val {
481 match val {
482 Ref::Extern(e) => Val::ExternRef(e),
483 Ref::Func(f) => Val::FuncRef(f),
484 Ref::Any(a) => Val::AnyRef(a),
485 }
486 }
487}
488
489impl From<Rooted<ExternRef>> for Val {
490 #[inline]
491 fn from(val: Rooted<ExternRef>) -> Val {
492 Val::ExternRef(Some(val))
493 }
494}
495
496impl From<Option<Rooted<ExternRef>>> for Val {
497 #[inline]
498 fn from(val: Option<Rooted<ExternRef>>) -> Val {
499 Val::ExternRef(val)
500 }
501}
502
503impl From<Rooted<AnyRef>> for Val {
504 #[inline]
505 fn from(val: Rooted<AnyRef>) -> Val {
506 Val::AnyRef(Some(val))
507 }
508}
509
510impl From<Option<Rooted<AnyRef>>> for Val {
511 #[inline]
512 fn from(val: Option<Rooted<AnyRef>>) -> Val {
513 Val::AnyRef(val)
514 }
515}
516
517impl From<Rooted<StructRef>> for Val {
518 #[inline]
519 fn from(val: Rooted<StructRef>) -> Val {
520 Val::AnyRef(Some(val.into()))
521 }
522}
523
524impl From<Option<Rooted<StructRef>>> for Val {
525 #[inline]
526 fn from(val: Option<Rooted<StructRef>>) -> Val {
527 Val::AnyRef(val.map(Into::into))
528 }
529}
530
531impl From<Rooted<ArrayRef>> for Val {
532 #[inline]
533 fn from(val: Rooted<ArrayRef>) -> Val {
534 Val::AnyRef(Some(val.into()))
535 }
536}
537
538impl From<Option<Rooted<ArrayRef>>> for Val {
539 #[inline]
540 fn from(val: Option<Rooted<ArrayRef>>) -> Val {
541 Val::AnyRef(val.map(Into::into))
542 }
543}
544
545impl From<Func> for Val {
546 #[inline]
547 fn from(val: Func) -> Val {
548 Val::FuncRef(Some(val))
549 }
550}
551
552impl From<Option<Func>> for Val {
553 #[inline]
554 fn from(val: Option<Func>) -> Val {
555 Val::FuncRef(val)
556 }
557}
558
559impl From<u128> for Val {
560 #[inline]
561 fn from(val: u128) -> Val {
562 Val::V128(val.into())
563 }
564}
565
566impl From<V128> for Val {
567 #[inline]
568 fn from(val: V128) -> Val {
569 Val::V128(val)
570 }
571}
572
573#[derive(Debug, Clone)]
598pub enum Ref {
599 Func(Option<Func>),
636
637 Extern(Option<Rooted<ExternRef>>),
647
648 Any(Option<Rooted<AnyRef>>),
657}
658
659impl From<Func> for Ref {
660 #[inline]
661 fn from(f: Func) -> Ref {
662 Ref::Func(Some(f))
663 }
664}
665
666impl From<Option<Func>> for Ref {
667 #[inline]
668 fn from(f: Option<Func>) -> Ref {
669 Ref::Func(f)
670 }
671}
672
673impl From<Rooted<ExternRef>> for Ref {
674 #[inline]
675 fn from(e: Rooted<ExternRef>) -> Ref {
676 Ref::Extern(Some(e))
677 }
678}
679
680impl From<Option<Rooted<ExternRef>>> for Ref {
681 #[inline]
682 fn from(e: Option<Rooted<ExternRef>>) -> Ref {
683 Ref::Extern(e)
684 }
685}
686
687impl From<Rooted<AnyRef>> for Ref {
688 #[inline]
689 fn from(e: Rooted<AnyRef>) -> Ref {
690 Ref::Any(Some(e))
691 }
692}
693
694impl From<Option<Rooted<AnyRef>>> for Ref {
695 #[inline]
696 fn from(e: Option<Rooted<AnyRef>>) -> Ref {
697 Ref::Any(e)
698 }
699}
700
701impl From<Rooted<StructRef>> for Ref {
702 #[inline]
703 fn from(e: Rooted<StructRef>) -> Ref {
704 Ref::Any(Some(e.into()))
705 }
706}
707
708impl From<Option<Rooted<StructRef>>> for Ref {
709 #[inline]
710 fn from(e: Option<Rooted<StructRef>>) -> Ref {
711 Ref::Any(e.map(Into::into))
712 }
713}
714
715impl From<Rooted<ArrayRef>> for Ref {
716 #[inline]
717 fn from(e: Rooted<ArrayRef>) -> Ref {
718 Ref::Any(Some(e.into()))
719 }
720}
721
722impl From<Option<Rooted<ArrayRef>>> for Ref {
723 #[inline]
724 fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
725 Ref::Any(e.map(Into::into))
726 }
727}
728
729impl Ref {
730 #[inline]
732 pub fn null(heap_type: &HeapType) -> Self {
733 match heap_type.top() {
734 HeapType::Any => Ref::Any(None),
735 HeapType::Extern => Ref::Extern(None),
736 HeapType::Func => Ref::Func(None),
737 ty => unreachable!("not a heap type: {ty:?}"),
738 }
739 }
740
741 #[inline]
743 pub fn is_null(&self) -> bool {
744 match self {
745 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) => true,
746 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) => false,
747 }
748 }
749
750 #[inline]
752 pub fn is_non_null(&self) -> bool {
753 !self.is_null()
754 }
755
756 #[inline]
758 pub fn is_extern(&self) -> bool {
759 matches!(self, Ref::Extern(_))
760 }
761
762 #[inline]
771 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
772 match self {
773 Ref::Extern(e) => Some(e.as_ref()),
774 _ => None,
775 }
776 }
777
778 #[inline]
785 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
786 self.as_extern()
787 .expect("Ref::unwrap_extern on non-extern reference")
788 }
789
790 #[inline]
792 pub fn is_any(&self) -> bool {
793 matches!(self, Ref::Any(_))
794 }
795
796 #[inline]
805 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
806 match self {
807 Ref::Any(e) => Some(e.as_ref()),
808 _ => None,
809 }
810 }
811
812 #[inline]
819 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
820 self.as_any().expect("Ref::unwrap_any on non-any reference")
821 }
822
823 #[inline]
825 pub fn is_func(&self) -> bool {
826 matches!(self, Ref::Func(_))
827 }
828
829 #[inline]
838 pub fn as_func(&self) -> Option<Option<&Func>> {
839 match self {
840 Ref::Func(f) => Some(f.as_ref()),
841 _ => None,
842 }
843 }
844
845 #[inline]
852 pub fn unwrap_func(&self) -> Option<&Func> {
853 self.as_func()
854 .expect("Ref::unwrap_func on non-func reference")
855 }
856
857 pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
867 self.load_ty(&store.as_context().0)
868 }
869
870 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
871 assert!(self.comes_from_same_store(store));
872 Ok(RefType::new(
873 self.is_null(),
874 match self {
878 Ref::Extern(None) => HeapType::NoExtern,
879 Ref::Extern(Some(_)) => HeapType::Extern,
880
881 Ref::Func(None) => HeapType::NoFunc,
882 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
883
884 Ref::Any(None) => HeapType::None,
885 Ref::Any(Some(a)) => a._ty(store)?,
886 },
887 ))
888 }
889
890 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
898 self._matches_ty(&store.as_context().0, ty)
899 }
900
901 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
902 assert!(self.comes_from_same_store(store));
903 assert!(ty.comes_from_same_engine(store.engine()));
904 if self.is_null() && !ty.is_nullable() {
905 return Ok(false);
906 }
907 Ok(match (self, ty.heap_type()) {
908 (Ref::Extern(_), HeapType::Extern) => true,
909 (Ref::Extern(None), HeapType::NoExtern) => true,
910 (Ref::Extern(_), _) => false,
911
912 (Ref::Func(_), HeapType::Func) => true,
913 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
914 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
915 (Ref::Func(_), _) => false,
916
917 (Ref::Any(_), HeapType::Any) => true,
918 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
919 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
920 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
921 None => false,
922 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
923 Some(s) => s._matches_ty(store, _ty)?,
924 },
925 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
926 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
927 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
928 None => false,
929 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
930 Some(a) => a._matches_ty(store, _ty)?,
931 },
932 (
933 Ref::Any(None),
934 HeapType::None
935 | HeapType::I31
936 | HeapType::ConcreteStruct(_)
937 | HeapType::Struct
938 | HeapType::ConcreteArray(_)
939 | HeapType::Array
940 | HeapType::Eq,
941 ) => true,
942 (Ref::Any(_), _) => false,
943 })
944 }
945
946 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
947 if !self.comes_from_same_store(store) {
948 bail!("reference used with wrong store")
949 }
950 if !ty.comes_from_same_engine(store.engine()) {
951 bail!("type used with wrong engine")
952 }
953 if self._matches_ty(store, ty)? {
954 Ok(())
955 } else {
956 let actual_ty = self.load_ty(store)?;
957 bail!("type mismatch: expected {ty}, found {actual_ty}")
958 }
959 }
960
961 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
962 match self {
963 Ref::Func(Some(f)) => f.comes_from_same_store(store),
964 Ref::Func(None) => true,
965 Ref::Extern(Some(x)) => x.comes_from_same_store(store),
966 Ref::Extern(None) => true,
967 Ref::Any(Some(a)) => a.comes_from_same_store(store),
968 Ref::Any(None) => true,
969 }
970 }
971
972 pub(crate) fn into_table_element(
973 self,
974 store: &mut StoreOpaque,
975 ty: &RefType,
976 ) -> Result<TableElement> {
977 let mut store = AutoAssertNoGc::new(store);
978 self.ensure_matches_ty(&store, &ty)
979 .context("type mismatch: value does not match table element type")?;
980
981 match (self, ty.heap_type().top()) {
982 (Ref::Func(None), HeapType::Func) => {
983 assert!(ty.is_nullable());
984 Ok(TableElement::FuncRef(None))
985 }
986 (Ref::Func(Some(f)), HeapType::Func) => {
987 debug_assert!(
988 f.comes_from_same_store(&store),
989 "checked in `ensure_matches_ty`"
990 );
991 Ok(TableElement::FuncRef(Some(f.vm_func_ref(&store))))
992 }
993
994 (Ref::Extern(e), HeapType::Extern) => match e {
995 None => {
996 assert!(ty.is_nullable());
997 Ok(TableElement::GcRef(None))
998 }
999 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
1000 Some(e) => {
1001 let gc_ref = e.try_clone_gc_ref(&mut store)?;
1002 Ok(TableElement::GcRef(Some(gc_ref)))
1003 }
1004 },
1005
1006 (Ref::Any(a), HeapType::Any) => match a {
1007 None => {
1008 assert!(ty.is_nullable());
1009 Ok(TableElement::GcRef(None))
1010 }
1011 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
1012 Some(a) => {
1013 let gc_ref = a.try_clone_gc_ref(&mut store)?;
1014 Ok(TableElement::GcRef(Some(gc_ref)))
1015 }
1016 },
1017
1018 _ => unreachable!("checked that the value matches the type above"),
1019 }
1020 }
1021}
1022
1023#[cfg(test)]
1024mod tests {
1025 use crate::*;
1026
1027 #[test]
1028 fn size_of_val() {
1029 let expected = if cfg!(target_arch = "x86_64")
1032 || cfg!(target_arch = "aarch64")
1033 || cfg!(target_arch = "s390x")
1034 || cfg!(target_arch = "riscv64")
1035 || cfg!(target_arch = "arm")
1036 {
1037 24
1038 } else if cfg!(target_arch = "x86") {
1039 20
1040 } else {
1041 panic!("unsupported architecture")
1042 };
1043 assert_eq!(std::mem::size_of::<Val>(), expected);
1044 }
1045
1046 #[test]
1047 fn size_of_ref() {
1048 let expected = if cfg!(target_arch = "x86_64")
1051 || cfg!(target_arch = "aarch64")
1052 || cfg!(target_arch = "s390x")
1053 || cfg!(target_arch = "riscv64")
1054 || cfg!(target_arch = "arm")
1055 {
1056 24
1057 } else if cfg!(target_arch = "x86") {
1058 20
1059 } else {
1060 panic!("unsupported architecture")
1061 };
1062 assert_eq!(std::mem::size_of::<Ref>(), expected);
1063 }
1064
1065 #[test]
1066 #[should_panic]
1067 fn val_matches_ty_wrong_engine() {
1068 let e1 = Engine::default();
1069 let e2 = Engine::default();
1070
1071 let t1 = FuncType::new(&e1, None, None);
1072 let t2 = FuncType::new(&e2, None, None);
1073
1074 let mut s1 = Store::new(&e1, ());
1075 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1076
1077 let _ = Val::FuncRef(Some(f)).matches_ty(
1079 &s1,
1080 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1081 );
1082 }
1083
1084 #[test]
1085 #[should_panic]
1086 fn ref_matches_ty_wrong_engine() {
1087 let e1 = Engine::default();
1088 let e2 = Engine::default();
1089
1090 let t1 = FuncType::new(&e1, None, None);
1091 let t2 = FuncType::new(&e2, None, None);
1092
1093 let mut s1 = Store::new(&e1, ());
1094 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1095
1096 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1098 }
1099}