1use crate::{
2 WasmtimeStoreContextMut, handle_result, wasm_trap_t, wasmtime_error_t, wasmtime_val_t,
3};
4use std::mem::MaybeUninit;
5use wasmtime::{AsContextMut, ExnRef, ExnRefPre, ExnType, RootScope, Tag};
6
7pub struct wasmtime_exn_t {
9 exn: wasmtime::OwnedRooted<ExnRef>,
10}
11
12wasmtime_c_api_macros::declare_own!(wasmtime_exn_t);
13
14#[unsafe(no_mangle)]
15pub unsafe extern "C" fn wasmtime_exn_new(
16 mut store: WasmtimeStoreContextMut<'_>,
17 tag: &Tag,
18 fields: *const wasmtime_val_t,
19 nfields: usize,
20 exn_ret: &mut *mut wasmtime_exn_t,
21) -> Option<Box<wasmtime_error_t>> {
22 let mut scope = RootScope::new(&mut store);
23
24 let result = (|| {
25 let tag_ty = tag.ty(&scope);
26 let exn_type = ExnType::from_tag_type(&tag_ty)?;
27 let allocator = ExnRefPre::new(&mut scope, exn_type);
28 let raw_fields = crate::slice_from_raw_parts(fields, nfields);
29 let field_vals: Vec<wasmtime::Val> =
30 raw_fields.iter().map(|f| f.to_val(&mut scope)).collect();
31 ExnRef::new(&mut scope, &allocator, tag, &field_vals)
32 })();
33
34 handle_result(result, |rooted| {
35 let owned = rooted.to_owned_rooted(&mut scope).unwrap();
36 *exn_ret = Box::into_raw(Box::new(wasmtime_exn_t { exn: owned }));
37 })
38}
39
40#[unsafe(no_mangle)]
41pub extern "C" fn wasmtime_exn_tag(
42 mut store: WasmtimeStoreContextMut<'_>,
43 exn: &wasmtime_exn_t,
44 tag_ret: &mut Tag,
45) -> Option<Box<wasmtime_error_t>> {
46 let mut scope = RootScope::new(&mut store);
47 let rooted = exn.exn.to_rooted(&mut scope);
48 handle_result(rooted.tag(&mut scope), |tag| {
49 *tag_ret = tag;
50 })
51}
52
53#[unsafe(no_mangle)]
54pub extern "C" fn wasmtime_exn_field_count(
55 mut store: WasmtimeStoreContextMut<'_>,
56 exn: &wasmtime_exn_t,
57) -> usize {
58 let mut scope = RootScope::new(&mut store);
59 let rooted = exn.exn.to_rooted(&mut scope);
60 let ty = rooted.ty(&scope).unwrap();
61 ty.fields().len()
62}
63
64#[unsafe(no_mangle)]
65pub unsafe extern "C" fn wasmtime_exn_field(
66 mut store: WasmtimeStoreContextMut<'_>,
67 exn: &wasmtime_exn_t,
68 index: usize,
69 val_ret: &mut MaybeUninit<wasmtime_val_t>,
70) -> Option<Box<wasmtime_error_t>> {
71 let mut scope = RootScope::new(&mut store);
72 let rooted = exn.exn.to_rooted(&mut scope);
73 handle_result(rooted.field(&mut scope, index), |val| {
74 crate::initialize(val_ret, wasmtime_val_t::from_val(&mut scope, val));
75 })
76}
77
78#[unsafe(no_mangle)]
79pub unsafe extern "C" fn wasmtime_context_set_exception(
80 mut store: WasmtimeStoreContextMut<'_>,
81 exn: Box<wasmtime_exn_t>,
82) -> Box<wasm_trap_t> {
83 let mut scope = RootScope::new(&mut store);
84 let rooted = exn.exn.to_rooted(&mut scope);
85 let thrown = scope.as_context_mut().throw::<()>(rooted).unwrap_err();
86 Box::new(wasm_trap_t::new(wasmtime::Error::new(thrown)))
87}
88
89#[unsafe(no_mangle)]
90pub extern "C" fn wasmtime_context_take_exception(
91 mut store: WasmtimeStoreContextMut<'_>,
92 exn_ret: &mut *mut wasmtime_exn_t,
93) -> bool {
94 match store.take_pending_exception() {
95 Some(rooted) => {
96 let owned = rooted.to_owned_rooted(&mut store).unwrap();
97 *exn_ret = Box::into_raw(Box::new(wasmtime_exn_t { exn: owned }));
98 true
99 }
100 None => false,
101 }
102}
103
104#[unsafe(no_mangle)]
105pub extern "C" fn wasmtime_context_has_exception(store: WasmtimeStoreContextMut<'_>) -> bool {
106 store.has_pending_exception()
107}