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 result = (|| {
50 let exn = unsafe {
51 exn.as_wasmtime()
52 .ok_or_else(|| wasmtime::format_err!("exnref is null"))?
53 };
54 exn.tag(&mut store)
55 })();
56 handle_result(result, |tag| {
57 *tag_ret = tag;
58 })
59}
60
61#[unsafe(no_mangle)]
62pub extern "C" fn wasmtime_exnref_field_count(
63 mut store: WasmtimeStoreContextMut<'_>,
64 exn: &wasmtime_exnref_t,
65) -> usize {
66 let mut scope = RootScope::new(&mut store);
67 let rooted = match unsafe { exn.as_wasmtime() } {
68 Some(e) => e.to_rooted(&mut scope),
69 None => return 0,
70 };
71 let ty = rooted.ty(&scope).unwrap();
72 ty.fields().len()
73}
74
75#[unsafe(no_mangle)]
76pub unsafe extern "C" fn wasmtime_exnref_field(
77 mut store: WasmtimeStoreContextMut<'_>,
78 exn: &wasmtime_exnref_t,
79 index: usize,
80 val_ret: &mut MaybeUninit<wasmtime_val_t>,
81) -> Option<Box<wasmtime_error_t>> {
82 let result = (|| {
83 let mut scope = RootScope::new(&mut store);
84 let exn = unsafe {
85 exn.as_wasmtime()
86 .ok_or_else(|| wasmtime::format_err!("exnref is null"))?
87 };
88 let field = exn.field(&mut scope, index)?;
89 Ok(wasmtime_val_t::from_val(&mut scope, field))
90 })();
91 handle_result(result, |val| {
92 val_ret.write(val);
93 })
94}
95
96#[unsafe(no_mangle)]
97pub unsafe extern "C" fn wasmtime_context_set_exception(
98 mut store: WasmtimeStoreContextMut<'_>,
99 exn: &wasmtime_exnref_t,
100) -> Option<Box<wasm_trap_t>> {
101 let mut scope = RootScope::new(&mut store);
102 let err = match exn.as_wasmtime() {
103 Some(e) => {
104 let rooted = e.to_rooted(&mut scope);
105 let Err(thrown) = scope
106 .as_context_mut()
107 .throw::<std::convert::Infallible>(rooted);
108 thrown
109 }
110 None => wasmtime::format_err!("exnref is null"),
111 };
112 Some(Box::new(wasm_trap_t::new(err)))
113}
114
115#[unsafe(no_mangle)]
116pub extern "C" fn wasmtime_context_take_exception(
117 mut store: WasmtimeStoreContextMut<'_>,
118 out: &mut MaybeUninit<wasmtime_exnref_t>,
119) -> bool {
120 match store.take_pending_exception() {
121 Some(rooted) => {
122 let owned = rooted.to_owned_rooted(&mut store).unwrap();
123 out.write(owned.into());
124 true
125 }
126 None => false,
127 }
128}
129
130#[unsafe(no_mangle)]
131pub extern "C" fn wasmtime_context_has_exception(store: WasmtimeStoreContextMut<'_>) -> bool {
132 store.has_pending_exception()
133}
134
135#[unsafe(no_mangle)]
136pub unsafe extern "C" fn wasmtime_exnref_type(
137 mut cx: WasmtimeStoreContextMut<'_>,
138 exnref: Option<&wasmtime_exnref_t>,
139) -> Option<Box<wasmtime_exn_type_t>> {
140 let exnref = exnref.and_then(|a| a.as_wasmtime())?;
141 let ty = exnref.ty(&mut cx).expect("should be rooted");
142 Some(Box::new(ty.into()))
143}