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