Skip to main content

wasmtime_c_api/
exnref.rs

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}