wasmtime/runtime/gc/
noextern.rs

1use crate::{
2    HeapType, Ref, RefType, Result, Val, ValRaw, ValType, WasmTy,
3    store::{AutoAssertNoGc, StoreOpaque},
4};
5use core::convert::Infallible;
6use 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)]
67pub struct NoExtern {
68    _inner: Infallible,
69}
70
71impl NoExtern {
72    /// Get the null `(ref null noextern)` (aka `nullexternref`) reference.
73    #[inline]
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]
81    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]
88    pub fn null_val() -> Val {
89        Val::ExternRef(None)
90    }
91}
92
93unsafe impl WasmTy for NoExtern {
94    #[inline]
95    fn valtype() -> ValType {
96        ValType::Ref(RefType::new(false, HeapType::NoExtern))
97    }
98
99    #[inline]
100    fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
101        match self._inner {}
102    }
103
104    #[inline]
105    fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()> {
106        match self._inner {}
107    }
108
109    #[inline]
110    fn is_vmgcref_and_points_to_object(&self) -> bool {
111        match self._inner {}
112    }
113
114    fn store(self, _store: &mut AutoAssertNoGc<'_>, _ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
115        match self._inner {}
116    }
117
118    unsafe fn load(_store: &mut AutoAssertNoGc<'_>, _ptr: &ValRaw) -> Self {
119        unreachable!("NoExtern is uninhabited")
120    }
121}
122
123unsafe impl WasmTy for Option<NoExtern> {
124    #[inline]
125    fn valtype() -> ValType {
126        ValType::Ref(RefType::new(true, HeapType::NoExtern))
127    }
128
129    #[inline]
130    fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
131        true
132    }
133
134    #[inline]
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]
145    fn store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
146        ptr.write(ValRaw::externref(0));
147        Ok(())
148    }
149
150    #[inline]
151    unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
152        debug_assert_eq!(ptr.get_externref(), 0);
153        None
154    }
155}