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}