1 use crate::{
2     HeapType, Ref, RefType, Result, Val, ValRaw, ValType, WasmTy,
3     store::{AutoAssertNoGc, StoreOpaque},
4 };
5 use core::convert::Infallible;
6 use core::mem::MaybeUninit;
7 
8 /// A reference to the abstract `noextern` heap value.
9 ///
10 /// The are no instances of `(ref noextern)`: it is an uninhabited type.
11 ///
12 /// There is precisely one instance of `(ref null noextern)`, aka `nullexternref`:
13 /// the null reference.
14 ///
15 /// This `NoExtern` Rust type's sole purpose is for use with
16 /// [`Func::wrap`][crate::Func::wrap]- and
17 /// [`Func::typed`][crate::Func::typed]-style APIs for statically typing a
18 /// function as taking or returning a `(ref null noextern)` (aka
19 /// `Option<NoExtern>`) which is always `None`.
20 ///
21 /// # Example
22 ///
23 /// ```
24 /// # use wasmtime::*;
25 /// # fn _foo() -> Result<()> {
26 /// let mut config = Config::new();
27 /// config.wasm_function_references(true);
28 /// config.wasm_gc(true);
29 /// let engine = Engine::new(&config)?;
30 ///
31 /// let module = Module::new(
32 ///     &engine,
33 ///     r#"
34 ///         (module
35 ///             (func (export "f") (param (ref null noextern))
36 ///                 ;; If the reference is null, return.
37 ///                 local.get 0
38 ///                 ref.is_null noextern
39 ///                 br_if 0
40 ///
41 ///                 ;; If the reference was not null (which is impossible)
42 ///                 ;; then raise a trap.
43 ///                 unreachable
44 ///             )
45 ///         )
46 ///     "#,
47 /// )?;
48 ///
49 /// let mut store = Store::new(&engine, ());
50 /// let instance = Instance::new(&mut store, &module, &[])?;
51 /// let f = instance.get_func(&mut store, "f").unwrap();
52 ///
53 /// // We can cast a `(ref null noextern)`-taking function into a typed function that
54 /// // takes an `Option<NoExtern>` via the `Func::typed` method.
55 /// let f = f.typed::<Option<NoExtern>, ()>(&store)?;
56 ///
57 /// // We can call the typed function, passing the null `noextern` reference.
58 /// let result = f.call(&mut store, NoExtern::null());
59 ///
60 /// // The function should not have trapped, because the reference we gave it was
61 /// // null (as it had to be, since `NoExtern` is uninhabited).
62 /// assert!(result.is_ok());
63 /// # Ok(())
64 /// # }
65 /// ```
66 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
67 pub struct NoExtern {
68     _inner: Infallible,
69 }
70 
71 impl NoExtern {
72     /// Get the null `(ref null noextern)` (aka `nullexternref`) reference.
73     #[inline]
null() -> Option<Self>74     pub fn null() -> Option<Self> {
75         None
76     }
77 
78     /// Get the null `(ref null noextern)` (aka `nullexternref`) reference as a
79     /// [`Ref`].
80     #[inline]
null_ref() -> Ref81     pub fn null_ref() -> Ref {
82         Ref::Extern(None)
83     }
84 
85     /// Get the null `(ref null noextern)` (aka `nullexternref`) reference as a
86     /// [`Val`].
87     #[inline]
null_val() -> Val88     pub fn null_val() -> Val {
89         Val::ExternRef(None)
90     }
91 }
92 
93 unsafe impl WasmTy for NoExtern {
94     #[inline]
valtype() -> ValType95     fn valtype() -> ValType {
96         ValType::Ref(RefType::new(false, HeapType::NoExtern))
97     }
98 
99     #[inline]
compatible_with_store(&self, _store: &StoreOpaque) -> bool100     fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
101         match self._inner {}
102     }
103 
104     #[inline]
dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()>105     fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()> {
106         match self._inner {}
107     }
108 
109     #[inline]
is_vmgcref_and_points_to_object(&self) -> bool110     fn is_vmgcref_and_points_to_object(&self) -> bool {
111         match self._inner {}
112     }
113 
store(self, _store: &mut AutoAssertNoGc<'_>, _ptr: &mut MaybeUninit<ValRaw>) -> Result<()>114     fn store(self, _store: &mut AutoAssertNoGc<'_>, _ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
115         match self._inner {}
116     }
117 
load(_store: &mut AutoAssertNoGc<'_>, _ptr: &ValRaw) -> Self118     unsafe fn load(_store: &mut AutoAssertNoGc<'_>, _ptr: &ValRaw) -> Self {
119         unreachable!("NoExtern is uninhabited")
120     }
121 }
122 
123 unsafe impl WasmTy for Option<NoExtern> {
124     #[inline]
valtype() -> ValType125     fn valtype() -> ValType {
126         ValType::Ref(RefType::new(true, HeapType::NoExtern))
127     }
128 
129     #[inline]
compatible_with_store(&self, _store: &StoreOpaque) -> bool130     fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
131         true
132     }
133 
134     #[inline]
dynamic_concrete_type_check( &self, _store: &StoreOpaque, _nullable: bool, _ty: &HeapType, ) -> Result<()>135     fn dynamic_concrete_type_check(
136         &self,
137         _store: &StoreOpaque,
138         _nullable: bool,
139         _ty: &HeapType,
140     ) -> Result<()> {
141         unreachable!()
142     }
143 
144     #[inline]
store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>145     fn store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
146         ptr.write(ValRaw::externref(0));
147         Ok(())
148     }
149 
150     #[inline]
load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self151     unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
152         debug_assert_eq!(ptr.get_externref(), 0);
153         None
154     }
155 }
156