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 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}