1use crate::{
2 WasmtimeStoreContextMut, handle_result, wasm_trap_t, wasmtime_error_t, wasmtime_exn_type_t,
3 wasmtime_val_t,
4};
5use std::mem::MaybeUninit;
6use wasmtime::{AsContextMut, ExnRef, ExnRefPre, ExnType, RootScope, Tag};
7
8crate::anyref::ref_wrapper!({
9 wasmtime: ExnRef,
10 capi: wasmtime_exnref_t,
11 clone: wasmtime_exnref_clone,
12 unroot: wasmtime_exnref_unroot,
13 to_raw: wasmtime_exnref_to_raw,
14 from_raw: wasmtime_exnref_from_raw,
15});
16
17#[unsafe(no_mangle)]
18pub unsafe extern "C" fn wasmtime_exnref_new(
19 mut store: WasmtimeStoreContextMut<'_>,
20 tag: &Tag,
21 fields: *const wasmtime_val_t,
22 nfields: usize,
23 exn_ret: &mut MaybeUninit<wasmtime_exnref_t>,
24) -> Option<Box<wasmtime_error_t>> {
25 let mut scope = RootScope::new(&mut store);
26
27 let result = (|| {
28 let tag_ty = tag.ty(&scope);
29 let exn_type = ExnType::from_tag_type(&tag_ty)?;
30 let allocator = ExnRefPre::new(&mut scope, exn_type);
31 let raw_fields = crate::slice_from_raw_parts(fields, nfields);
32 let field_vals: Vec<wasmtime::Val> =
33 raw_fields.iter().map(|f| f.to_val(&mut scope)).collect();
34 ExnRef::new(&mut scope, &allocator, tag, &field_vals)
35 })();
36
37 handle_result(result, |rooted| {
38 let owned = rooted.to_owned_rooted(&mut scope).unwrap();
39 exn_ret.write(owned.into());
40 })
41}
42
43#[unsafe(no_mangle)]
44pub extern "C" fn wasmtime_exnref_tag(
45 mut store: WasmtimeStoreContextMut<'_>,
46 exn: &wasmtime_exnref_t,
47 tag_ret: &mut Tag,
48) -> Option<Box<wasmtime_error_t>> {
49 let mut scope = RootScope::new(&mut store);
50 let rooted = unsafe { exn.as_wasmtime()?.to_rooted(&mut scope) };
51 handle_result(rooted.tag(&mut scope), |tag| {
52 *tag_ret = tag;
53 })
54}
55
56#[unsafe(no_mangle)]
57pub extern "C" fn wasmtime_exnref_field_count(
58 mut store: WasmtimeStoreContextMut<'_>,
59 exn: &wasmtime_exnref_t,
60) -> usize {
61 let mut scope = RootScope::new(&mut store);
62 let rooted = match unsafe { exn.as_wasmtime() } {
63 Some(e) => e.to_rooted(&mut scope),
64 None => return 0,
65 };
66 let ty = rooted.ty(&scope).unwrap();
67 ty.fields().len()
68}
69
70#[unsafe(no_mangle)]
71pub unsafe extern "C" fn wasmtime_exnref_field(
72 mut store: WasmtimeStoreContextMut<'_>,
73 exn: &wasmtime_exnref_t,
74 index: usize,
75 val_ret: &mut MaybeUninit<wasmtime_val_t>,
76) -> Option<Box<wasmtime_error_t>> {
77 let mut scope = RootScope::new(&mut store);
78 let rooted = exn.as_wasmtime()?.to_rooted(&mut scope);
79 handle_result(rooted.field(&mut scope, index), |val| {
80 crate::initialize(val_ret, wasmtime_val_t::from_val(&mut scope, val));
81 })
82}
83
84#[unsafe(no_mangle)]
85pub unsafe extern "C" fn wasmtime_context_set_exception(
86 mut store: WasmtimeStoreContextMut<'_>,
87 exn: &wasmtime_exnref_t,
88) -> Option<Box<wasm_trap_t>> {
89 let mut scope = RootScope::new(&mut store);
90 let rooted = exn.as_wasmtime()?.to_rooted(&mut scope);
91 let Err(thrown) = scope
92 .as_context_mut()
93 .throw::<std::convert::Infallible>(rooted);
94 Some(Box::new(wasm_trap_t::new(thrown)))
95}
96
97#[unsafe(no_mangle)]
98pub extern "C" fn wasmtime_context_take_exception(
99 mut store: WasmtimeStoreContextMut<'_>,
100 out: &mut MaybeUninit<wasmtime_exnref_t>,
101) -> bool {
102 match store.take_pending_exception() {
103 Some(rooted) => {
104 let owned = rooted.to_owned_rooted(&mut store).unwrap();
105 out.write(owned.into());
106 true
107 }
108 None => false,
109 }
110}
111
112#[unsafe(no_mangle)]
113pub extern "C" fn wasmtime_context_has_exception(store: WasmtimeStoreContextMut<'_>) -> bool {
114 store.has_pending_exception()
115}
116
117#[unsafe(no_mangle)]
118pub unsafe extern "C" fn wasmtime_exnref_type(
119 mut cx: WasmtimeStoreContextMut<'_>,
120 exnref: Option<&wasmtime_exnref_t>,
121) -> Option<Box<wasmtime_exn_type_t>> {
122 let exnref = exnref.and_then(|a| a.as_wasmtime())?;
123 let ty = exnref.ty(&mut cx).expect("should be rooted");
124 Some(Box::new(ty.into()))
125}