Skip to main content

wasmtime_c_api/
exn.rs

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
7/// An opaque type representing a WebAssembly exception object.
8pub 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}