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}