wasmtime/runtime/gc/
noextern.rs

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