1use crate::{WasmtimeStoreContextMut, wasmtime_arrayref_t, wasmtime_eqref_t, wasmtime_structref_t};
2use std::mem::MaybeUninit;
3use wasmtime::{AnyRef, ArrayRef, EqRef, I31, OwnedRooted, RootScope, StructRef};
4
5macro_rules! ref_wrapper {
14 ({
15 wasmtime: $wasmtime:ident,
16 capi: $c:ident,
17 clone: $clone:ident,
18 unroot: $unroot:ident,
19 $(
20 to_raw: $to_raw:ident,
21 from_raw: $from_raw:ident,
22 )?
23 }) => {
24 pub struct $c {
25 store_id: u64,
26 a: u32,
27 b: u32,
28 c: *const (),
29 }
30
31 impl $c {
32 pub unsafe fn as_wasmtime(&self) -> Option<wasmtime::OwnedRooted<$wasmtime>> {
33 let store_id = std::num::NonZeroU64::new(self.store_id)?;
34 Some(wasmtime::OwnedRooted::from_borrowed_raw_parts_for_c_api(
35 store_id, self.a, self.b, self.c,
36 ))
37 }
38
39 pub unsafe fn into_wasmtime(self) -> Option<wasmtime::OwnedRooted<$wasmtime>> {
40 std::mem::ManuallyDrop::new(self).to_owned()
41 }
42
43 unsafe fn to_owned(&self) -> Option<wasmtime::OwnedRooted<$wasmtime>> {
44 let store_id = std::num::NonZeroU64::new(self.store_id)?;
45 Some(wasmtime::OwnedRooted::from_owned_raw_parts_for_c_api(
46 store_id, self.a, self.b, self.c,
47 ))
48 }
49 }
50
51 impl Drop for $c {
52 fn drop(&mut self) {
53 unsafe {
54 let _ = self.to_owned();
55 }
56 }
57 }
58
59 impl From<Option<wasmtime::OwnedRooted<$wasmtime>>> for $c {
60 fn from(rooted: Option<wasmtime::OwnedRooted<$wasmtime>>) -> $c {
61 let mut ret = $c {
62 store_id: 0,
63 a: 0,
64 b: 0,
65 c: core::ptr::null(),
66 };
67 if let Some(rooted) = rooted {
68 let (store_id, a, b, c) = rooted.into_parts_for_c_api();
69 ret.store_id = store_id.get();
70 ret.a = a;
71 ret.b = b;
72 ret.c = c;
73 }
74 ret
75 }
76 }
77
78 impl From<wasmtime::OwnedRooted<$wasmtime>> for $c {
79 fn from(rooted: wasmtime::OwnedRooted<$wasmtime>) -> $c {
80 Self::from(Some(rooted))
81 }
82 }
83
84 unsafe impl Send for $c {}
89 unsafe impl Sync for $c {}
90
91 #[unsafe(no_mangle)]
92 pub unsafe extern "C" fn $clone(anyref: Option<&$c>, out: &mut std::mem::MaybeUninit<$c>) {
93 let anyref = anyref.and_then(|a| a.as_wasmtime());
94 out.write(anyref.into());
95 }
96
97 #[unsafe(no_mangle)]
98 pub unsafe extern "C" fn $unroot(val: Option<&mut std::mem::ManuallyDrop<$c>>) {
99 if let Some(val) = val {
100 unsafe {
101 std::mem::ManuallyDrop::drop(val);
102 }
103 }
104 }
105
106 $(
107 #[unsafe(no_mangle)]
108 pub unsafe extern "C" fn $to_raw(
109 cx: crate::WasmtimeStoreContextMut<'_>,
110 val: Option<&$c>,
111 ) -> u32 {
112 val.and_then(|v| v.as_wasmtime())
113 .and_then(|e| e.to_raw(cx).ok())
114 .unwrap_or_default()
115 }
116
117 #[unsafe(no_mangle)]
118 pub unsafe extern "C" fn $from_raw(
119 cx: crate::WasmtimeStoreContextMut<'_>,
120 raw: u32,
121 val: &mut std::mem::MaybeUninit<$c>,
122 ) {
123 let mut scope = wasmtime::RootScope::new(cx);
124 let anyref = $wasmtime::from_raw(&mut scope, raw)
125 .map(|a| a.to_owned_rooted(&mut scope).expect("in scope"));
126 crate::initialize(val, anyref.into());
127 }
128 )?
129 };
130}
131pub(crate) use ref_wrapper;
132
133ref_wrapper!({
134 wasmtime: AnyRef,
135 capi: wasmtime_anyref_t,
136 clone: wasmtime_anyref_clone,
137 unroot: wasmtime_anyref_unroot,
138 to_raw: wasmtime_anyref_to_raw,
139 from_raw: wasmtime_anyref_from_raw,
140});
141
142#[unsafe(no_mangle)]
143pub extern "C" fn wasmtime_anyref_from_i31(
144 cx: WasmtimeStoreContextMut<'_>,
145 val: u32,
146 out: &mut MaybeUninit<wasmtime_anyref_t>,
147) {
148 let mut scope = RootScope::new(cx);
149 let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val));
150 let anyref = anyref.to_owned_rooted(&mut scope).expect("in scope");
151 crate::initialize(out, Some(anyref).into())
152}
153
154#[unsafe(no_mangle)]
155pub unsafe extern "C" fn wasmtime_anyref_is_i31(
156 cx: WasmtimeStoreContextMut<'_>,
157 anyref: Option<&wasmtime_anyref_t>,
158) -> bool {
159 match anyref.and_then(|a| a.as_wasmtime()) {
160 Some(anyref) => anyref.is_i31(&cx).expect("OwnedRooted always in scope"),
161 None => false,
162 }
163}
164
165#[unsafe(no_mangle)]
166pub unsafe extern "C" fn wasmtime_anyref_i31_get_u(
167 cx: WasmtimeStoreContextMut<'_>,
168 anyref: Option<&wasmtime_anyref_t>,
169 dst: &mut MaybeUninit<u32>,
170) -> bool {
171 match anyref.and_then(|a| a.as_wasmtime()) {
172 Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
173 let val = anyref
174 .unwrap_i31(&cx)
175 .expect("OwnedRooted always in scope")
176 .get_u32();
177 crate::initialize(dst, val);
178 true
179 }
180 _ => false,
181 }
182}
183
184#[unsafe(no_mangle)]
185pub unsafe extern "C" fn wasmtime_anyref_i31_get_s(
186 cx: WasmtimeStoreContextMut<'_>,
187 anyref: Option<&wasmtime_anyref_t>,
188 dst: &mut MaybeUninit<i32>,
189) -> bool {
190 match anyref.and_then(|a| a.as_wasmtime()) {
191 Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
192 let val = anyref
193 .unwrap_i31(&cx)
194 .expect("OwnedRooted always in scope")
195 .get_i32();
196 crate::initialize(dst, val);
197 true
198 }
199 _ => false,
200 }
201}
202
203#[unsafe(no_mangle)]
204pub unsafe extern "C" fn wasmtime_anyref_is_eqref(
205 cx: WasmtimeStoreContextMut<'_>,
206 anyref: Option<&wasmtime_anyref_t>,
207) -> bool {
208 match anyref.and_then(|a| a.as_wasmtime()) {
209 Some(anyref) => anyref.is_eqref(&cx).expect("OwnedRooted always in scope"),
210 None => false,
211 }
212}
213
214#[unsafe(no_mangle)]
215pub unsafe extern "C" fn wasmtime_anyref_as_eqref(
216 mut cx: WasmtimeStoreContextMut<'_>,
217 anyref: Option<&wasmtime_anyref_t>,
218 out: &mut MaybeUninit<wasmtime_eqref_t>,
219) -> bool {
220 if let Some(anyref) = anyref.and_then(|a| a.as_wasmtime()) {
221 let mut scope = RootScope::new(&mut cx);
222 let rooted = anyref.to_rooted(&mut scope);
223 if let Ok(Some(eqref)) = rooted.as_eqref(&mut scope) {
224 let owned = eqref.to_owned_rooted(&mut scope).expect("in scope");
225 crate::initialize(out, Some(owned).into());
226 return true;
227 }
228 }
229 crate::initialize(out, None::<OwnedRooted<EqRef>>.into());
230 false
231}
232
233#[unsafe(no_mangle)]
234pub unsafe extern "C" fn wasmtime_anyref_is_struct(
235 cx: WasmtimeStoreContextMut<'_>,
236 anyref: Option<&wasmtime_anyref_t>,
237) -> bool {
238 match anyref.and_then(|a| a.as_wasmtime()) {
239 Some(anyref) => anyref.is_struct(&cx).expect("OwnedRooted always in scope"),
240 None => false,
241 }
242}
243
244#[unsafe(no_mangle)]
245pub unsafe extern "C" fn wasmtime_anyref_as_struct(
246 mut cx: WasmtimeStoreContextMut<'_>,
247 anyref: Option<&wasmtime_anyref_t>,
248 out: &mut MaybeUninit<wasmtime_structref_t>,
249) -> bool {
250 if let Some(anyref) = anyref.and_then(|a| a.as_wasmtime()) {
251 let mut scope = RootScope::new(&mut cx);
252 let rooted = anyref.to_rooted(&mut scope);
253 if let Ok(Some(structref)) = rooted.as_struct(&scope) {
254 let owned = structref.to_owned_rooted(&mut scope).expect("in scope");
255 crate::initialize(out, Some(owned).into());
256 return true;
257 }
258 }
259 crate::initialize(out, None::<OwnedRooted<StructRef>>.into());
260 false
261}
262
263#[unsafe(no_mangle)]
264pub unsafe extern "C" fn wasmtime_anyref_is_array(
265 cx: WasmtimeStoreContextMut<'_>,
266 anyref: Option<&wasmtime_anyref_t>,
267) -> bool {
268 match anyref.and_then(|a| a.as_wasmtime()) {
269 Some(anyref) => anyref.is_array(&cx).expect("OwnedRooted always in scope"),
270 None => false,
271 }
272}
273
274#[unsafe(no_mangle)]
275pub unsafe extern "C" fn wasmtime_anyref_as_array(
276 mut cx: WasmtimeStoreContextMut<'_>,
277 anyref: Option<&wasmtime_anyref_t>,
278 out: &mut MaybeUninit<wasmtime_arrayref_t>,
279) -> bool {
280 if let Some(anyref) = anyref.and_then(|a| a.as_wasmtime()) {
281 let mut scope = RootScope::new(&mut cx);
282 let rooted = anyref.to_rooted(&mut scope);
283 if let Ok(Some(arrayref)) = rooted.as_array(&scope) {
284 let owned = arrayref.to_owned_rooted(&mut scope).expect("in scope");
285 crate::initialize(out, Some(owned).into());
286 return true;
287 }
288 }
289 crate::initialize(out, None::<OwnedRooted<ArrayRef>>.into());
290 false
291}