1use crate::runtime::vm::TableElement;
2use crate::store::{AutoAssertNoGc, StoreOpaque};
3use crate::{
4 prelude::*, AnyRef, ArrayRef, AsContext, AsContextMut, ExternRef, Func, HeapType, RefType,
5 Rooted, RootedGcRefImpl, StructRef, ValType, V128,
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::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
284
285 HeapType::NoExtern => Ref::Extern(None),
286
287 HeapType::Any
288 | HeapType::Eq
289 | HeapType::I31
290 | HeapType::Array
291 | HeapType::ConcreteArray(_)
292 | HeapType::Struct
293 | HeapType::ConcreteStruct(_) => {
294 AnyRef::_from_raw(store, raw.get_anyref()).into()
295 }
296
297 HeapType::None => Ref::Any(None),
298 };
299 assert!(
300 ref_ty.is_nullable() || !ref_.is_null(),
301 "if the type is not nullable, we shouldn't get null; got \
302 type = {ref_ty}, ref = {ref_:?}"
303 );
304 ref_.into()
305 }
306 }
307 }
308
309 accessors! {
310 e
311 (I32(i32) i32 unwrap_i32 *e)
312 (I64(i64) i64 unwrap_i64 *e)
313 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
314 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
315 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
316 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
317 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
318 (V128(V128) v128 unwrap_v128 *e)
319 }
320
321 #[inline]
323 pub fn ref_(self) -> Option<Ref> {
324 match self {
325 Val::FuncRef(f) => Some(Ref::Func(f)),
326 Val::ExternRef(e) => Some(Ref::Extern(e)),
327 Val::AnyRef(a) => Some(Ref::Any(a)),
328 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
329 }
330 }
331
332 #[inline]
340 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
341 match self {
342 Val::ExternRef(None) => Some(None),
343 Val::ExternRef(Some(e)) => Some(Some(e)),
344 _ => None,
345 }
346 }
347
348 #[inline]
359 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
360 self.externref().expect("expected externref")
361 }
362
363 #[inline]
371 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
372 match self {
373 Val::AnyRef(None) => Some(None),
374 Val::AnyRef(Some(e)) => Some(Some(e)),
375 _ => None,
376 }
377 }
378
379 #[inline]
390 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
391 self.anyref().expect("expected anyref")
392 }
393
394 #[inline]
402 pub fn funcref(&self) -> Option<Option<&Func>> {
403 match self {
404 Val::FuncRef(None) => Some(None),
405 Val::FuncRef(Some(f)) => Some(Some(f)),
406 _ => None,
407 }
408 }
409
410 #[inline]
421 pub fn unwrap_funcref(&self) -> Option<&Func> {
422 self.funcref().expect("expected funcref")
423 }
424
425 #[inline]
426 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
427 match self {
428 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
429 Val::FuncRef(None) => true,
430
431 Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
432 Val::ExternRef(None) => true,
433
434 Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
435 Val::AnyRef(None) => true,
436
437 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
441 }
442 }
443}
444
445impl From<i32> for Val {
446 #[inline]
447 fn from(val: i32) -> Val {
448 Val::I32(val)
449 }
450}
451
452impl From<i64> for Val {
453 #[inline]
454 fn from(val: i64) -> Val {
455 Val::I64(val)
456 }
457}
458
459impl From<f32> for Val {
460 #[inline]
461 fn from(val: f32) -> Val {
462 Val::F32(val.to_bits())
463 }
464}
465
466impl From<f64> for Val {
467 #[inline]
468 fn from(val: f64) -> Val {
469 Val::F64(val.to_bits())
470 }
471}
472
473impl From<Ref> for Val {
474 #[inline]
475 fn from(val: Ref) -> Val {
476 match val {
477 Ref::Extern(e) => Val::ExternRef(e),
478 Ref::Func(f) => Val::FuncRef(f),
479 Ref::Any(a) => Val::AnyRef(a),
480 }
481 }
482}
483
484impl From<Rooted<ExternRef>> for Val {
485 #[inline]
486 fn from(val: Rooted<ExternRef>) -> Val {
487 Val::ExternRef(Some(val))
488 }
489}
490
491impl From<Option<Rooted<ExternRef>>> for Val {
492 #[inline]
493 fn from(val: Option<Rooted<ExternRef>>) -> Val {
494 Val::ExternRef(val)
495 }
496}
497
498impl From<Rooted<AnyRef>> for Val {
499 #[inline]
500 fn from(val: Rooted<AnyRef>) -> Val {
501 Val::AnyRef(Some(val))
502 }
503}
504
505impl From<Option<Rooted<AnyRef>>> for Val {
506 #[inline]
507 fn from(val: Option<Rooted<AnyRef>>) -> Val {
508 Val::AnyRef(val)
509 }
510}
511
512impl From<Rooted<StructRef>> for Val {
513 #[inline]
514 fn from(val: Rooted<StructRef>) -> Val {
515 Val::AnyRef(Some(val.into()))
516 }
517}
518
519impl From<Option<Rooted<StructRef>>> for Val {
520 #[inline]
521 fn from(val: Option<Rooted<StructRef>>) -> Val {
522 Val::AnyRef(val.map(Into::into))
523 }
524}
525
526impl From<Rooted<ArrayRef>> for Val {
527 #[inline]
528 fn from(val: Rooted<ArrayRef>) -> Val {
529 Val::AnyRef(Some(val.into()))
530 }
531}
532
533impl From<Option<Rooted<ArrayRef>>> for Val {
534 #[inline]
535 fn from(val: Option<Rooted<ArrayRef>>) -> Val {
536 Val::AnyRef(val.map(Into::into))
537 }
538}
539
540impl From<Func> for Val {
541 #[inline]
542 fn from(val: Func) -> Val {
543 Val::FuncRef(Some(val))
544 }
545}
546
547impl From<Option<Func>> for Val {
548 #[inline]
549 fn from(val: Option<Func>) -> Val {
550 Val::FuncRef(val)
551 }
552}
553
554impl From<u128> for Val {
555 #[inline]
556 fn from(val: u128) -> Val {
557 Val::V128(val.into())
558 }
559}
560
561impl From<V128> for Val {
562 #[inline]
563 fn from(val: V128) -> Val {
564 Val::V128(val)
565 }
566}
567
568#[derive(Debug, Clone)]
593pub enum Ref {
594 Func(Option<Func>),
631
632 Extern(Option<Rooted<ExternRef>>),
642
643 Any(Option<Rooted<AnyRef>>),
652}
653
654impl From<Func> for Ref {
655 #[inline]
656 fn from(f: Func) -> Ref {
657 Ref::Func(Some(f))
658 }
659}
660
661impl From<Option<Func>> for Ref {
662 #[inline]
663 fn from(f: Option<Func>) -> Ref {
664 Ref::Func(f)
665 }
666}
667
668impl From<Rooted<ExternRef>> for Ref {
669 #[inline]
670 fn from(e: Rooted<ExternRef>) -> Ref {
671 Ref::Extern(Some(e))
672 }
673}
674
675impl From<Option<Rooted<ExternRef>>> for Ref {
676 #[inline]
677 fn from(e: Option<Rooted<ExternRef>>) -> Ref {
678 Ref::Extern(e)
679 }
680}
681
682impl From<Rooted<AnyRef>> for Ref {
683 #[inline]
684 fn from(e: Rooted<AnyRef>) -> Ref {
685 Ref::Any(Some(e))
686 }
687}
688
689impl From<Option<Rooted<AnyRef>>> for Ref {
690 #[inline]
691 fn from(e: Option<Rooted<AnyRef>>) -> Ref {
692 Ref::Any(e)
693 }
694}
695
696impl From<Rooted<StructRef>> for Ref {
697 #[inline]
698 fn from(e: Rooted<StructRef>) -> Ref {
699 Ref::Any(Some(e.into()))
700 }
701}
702
703impl From<Option<Rooted<StructRef>>> for Ref {
704 #[inline]
705 fn from(e: Option<Rooted<StructRef>>) -> Ref {
706 Ref::Any(e.map(Into::into))
707 }
708}
709
710impl From<Rooted<ArrayRef>> for Ref {
711 #[inline]
712 fn from(e: Rooted<ArrayRef>) -> Ref {
713 Ref::Any(Some(e.into()))
714 }
715}
716
717impl From<Option<Rooted<ArrayRef>>> for Ref {
718 #[inline]
719 fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
720 Ref::Any(e.map(Into::into))
721 }
722}
723
724impl Ref {
725 #[inline]
727 pub fn null(heap_type: &HeapType) -> Self {
728 match heap_type.top() {
729 HeapType::Any => Ref::Any(None),
730 HeapType::Extern => Ref::Extern(None),
731 HeapType::Func => Ref::Func(None),
732 ty => unreachable!("not a heap type: {ty:?}"),
733 }
734 }
735
736 #[inline]
738 pub fn is_null(&self) -> bool {
739 match self {
740 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) => true,
741 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) => false,
742 }
743 }
744
745 #[inline]
747 pub fn is_non_null(&self) -> bool {
748 !self.is_null()
749 }
750
751 #[inline]
753 pub fn is_extern(&self) -> bool {
754 matches!(self, Ref::Extern(_))
755 }
756
757 #[inline]
766 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
767 match self {
768 Ref::Extern(e) => Some(e.as_ref()),
769 _ => None,
770 }
771 }
772
773 #[inline]
780 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
781 self.as_extern()
782 .expect("Ref::unwrap_extern on non-extern reference")
783 }
784
785 #[inline]
787 pub fn is_any(&self) -> bool {
788 matches!(self, Ref::Any(_))
789 }
790
791 #[inline]
800 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
801 match self {
802 Ref::Any(e) => Some(e.as_ref()),
803 _ => None,
804 }
805 }
806
807 #[inline]
814 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
815 self.as_any().expect("Ref::unwrap_any on non-any reference")
816 }
817
818 #[inline]
820 pub fn is_func(&self) -> bool {
821 matches!(self, Ref::Func(_))
822 }
823
824 #[inline]
833 pub fn as_func(&self) -> Option<Option<&Func>> {
834 match self {
835 Ref::Func(f) => Some(f.as_ref()),
836 _ => None,
837 }
838 }
839
840 #[inline]
847 pub fn unwrap_func(&self) -> Option<&Func> {
848 self.as_func()
849 .expect("Ref::unwrap_func on non-func reference")
850 }
851
852 pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
862 self.load_ty(&store.as_context().0)
863 }
864
865 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
866 assert!(self.comes_from_same_store(store));
867 Ok(RefType::new(
868 self.is_null(),
869 match self {
873 Ref::Extern(None) => HeapType::NoExtern,
874 Ref::Extern(Some(_)) => HeapType::Extern,
875
876 Ref::Func(None) => HeapType::NoFunc,
877 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
878
879 Ref::Any(None) => HeapType::None,
880 Ref::Any(Some(a)) => a._ty(store)?,
881 },
882 ))
883 }
884
885 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
893 self._matches_ty(&store.as_context().0, ty)
894 }
895
896 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
897 assert!(self.comes_from_same_store(store));
898 assert!(ty.comes_from_same_engine(store.engine()));
899 if self.is_null() && !ty.is_nullable() {
900 return Ok(false);
901 }
902 Ok(match (self, ty.heap_type()) {
903 (Ref::Extern(_), HeapType::Extern) => true,
904 (Ref::Extern(None), HeapType::NoExtern) => true,
905 (Ref::Extern(_), _) => false,
906
907 (Ref::Func(_), HeapType::Func) => true,
908 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
909 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
910 (Ref::Func(_), _) => false,
911
912 (Ref::Any(_), HeapType::Any) => true,
913 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
914 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
915 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
916 None => false,
917 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
918 Some(s) => s._matches_ty(store, _ty)?,
919 },
920 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
921 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
922 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
923 None => false,
924 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
925 Some(a) => a._matches_ty(store, _ty)?,
926 },
927 (
928 Ref::Any(None),
929 HeapType::None
930 | HeapType::I31
931 | HeapType::ConcreteStruct(_)
932 | HeapType::Struct
933 | HeapType::ConcreteArray(_)
934 | HeapType::Array
935 | HeapType::Eq,
936 ) => true,
937 (Ref::Any(_), _) => false,
938 })
939 }
940
941 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
942 if !self.comes_from_same_store(store) {
943 bail!("reference used with wrong store")
944 }
945 if !ty.comes_from_same_engine(store.engine()) {
946 bail!("type used with wrong engine")
947 }
948 if self._matches_ty(store, ty)? {
949 Ok(())
950 } else {
951 let actual_ty = self.load_ty(store)?;
952 bail!("type mismatch: expected {ty}, found {actual_ty}")
953 }
954 }
955
956 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
957 match self {
958 Ref::Func(Some(f)) => f.comes_from_same_store(store),
959 Ref::Func(None) => true,
960 Ref::Extern(Some(x)) => x.comes_from_same_store(store),
961 Ref::Extern(None) => true,
962 Ref::Any(Some(a)) => a.comes_from_same_store(store),
963 Ref::Any(None) => true,
964 }
965 }
966
967 pub(crate) fn into_table_element(
968 self,
969 store: &mut StoreOpaque,
970 ty: &RefType,
971 ) -> Result<TableElement> {
972 let mut store = AutoAssertNoGc::new(store);
973 self.ensure_matches_ty(&store, &ty)
974 .context("type mismatch: value does not match table element type")?;
975
976 match (self, ty.heap_type().top()) {
977 (Ref::Func(None), HeapType::Func) => {
978 assert!(ty.is_nullable());
979 Ok(TableElement::FuncRef(None))
980 }
981 (Ref::Func(Some(f)), HeapType::Func) => {
982 debug_assert!(
983 f.comes_from_same_store(&store),
984 "checked in `ensure_matches_ty`"
985 );
986 Ok(TableElement::FuncRef(Some(f.vm_func_ref(&mut store))))
987 }
988
989 (Ref::Extern(e), HeapType::Extern) => match e {
990 None => {
991 assert!(ty.is_nullable());
992 Ok(TableElement::GcRef(None))
993 }
994 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
995 Some(e) => {
996 let gc_ref = e.try_clone_gc_ref(&mut store)?;
997 Ok(TableElement::GcRef(Some(gc_ref)))
998 }
999 },
1000
1001 (Ref::Any(a), HeapType::Any) => match a {
1002 None => {
1003 assert!(ty.is_nullable());
1004 Ok(TableElement::GcRef(None))
1005 }
1006 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
1007 Some(a) => {
1008 let gc_ref = a.try_clone_gc_ref(&mut store)?;
1009 Ok(TableElement::GcRef(Some(gc_ref)))
1010 }
1011 },
1012
1013 _ => unreachable!("checked that the value matches the type above"),
1014 }
1015 }
1016}
1017
1018#[cfg(test)]
1019mod tests {
1020 use crate::*;
1021
1022 #[test]
1023 fn size_of_val() {
1024 let expected = if cfg!(target_arch = "x86_64")
1027 || cfg!(target_arch = "aarch64")
1028 || cfg!(target_arch = "s390x")
1029 || cfg!(target_arch = "riscv64")
1030 || cfg!(target_arch = "arm")
1031 {
1032 24
1033 } else if cfg!(target_arch = "x86") {
1034 20
1035 } else {
1036 panic!("unsupported architecture")
1037 };
1038 assert_eq!(std::mem::size_of::<Val>(), expected);
1039 }
1040
1041 #[test]
1042 fn size_of_ref() {
1043 let expected = if cfg!(target_arch = "x86_64")
1046 || cfg!(target_arch = "aarch64")
1047 || cfg!(target_arch = "s390x")
1048 || cfg!(target_arch = "riscv64")
1049 || cfg!(target_arch = "arm")
1050 {
1051 24
1052 } else if cfg!(target_arch = "x86") {
1053 20
1054 } else {
1055 panic!("unsupported architecture")
1056 };
1057 assert_eq!(std::mem::size_of::<Ref>(), expected);
1058 }
1059
1060 #[test]
1061 #[should_panic]
1062 fn val_matches_ty_wrong_engine() {
1063 let e1 = Engine::default();
1064 let e2 = Engine::default();
1065
1066 let t1 = FuncType::new(&e1, None, None);
1067 let t2 = FuncType::new(&e2, None, None);
1068
1069 let mut s1 = Store::new(&e1, ());
1070 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1071
1072 let _ = Val::FuncRef(Some(f)).matches_ty(
1074 &s1,
1075 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1076 );
1077 }
1078
1079 #[test]
1080 #[should_panic]
1081 fn ref_matches_ty_wrong_engine() {
1082 let e1 = Engine::default();
1083 let e2 = Engine::default();
1084
1085 let t1 = FuncType::new(&e1, None, None);
1086 let t2 = FuncType::new(&e2, None, None);
1087
1088 let mut s1 = Store::new(&e1, ());
1089 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1090
1091 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1093 }
1094}