lunatic_error_api/
lib.rs

1use anyhow::Result;
2use hash_map_id::HashMapId;
3use lunatic_common_api::{get_memory, IntoTrap};
4use wasmtime::{Caller, Linker};
5
6pub type ErrorResource = HashMapId<anyhow::Error>;
7
8pub trait ErrorCtx {
9    fn error_resources(&self) -> &ErrorResource;
10    fn error_resources_mut(&mut self) -> &mut ErrorResource;
11}
12
13// Register the error APIs to the linker
14pub fn register<T: ErrorCtx + 'static>(linker: &mut Linker<T>) -> Result<()> {
15    linker.func_wrap("lunatic::error", "string_size", string_size)?;
16    linker.func_wrap("lunatic::error", "to_string", to_string)?;
17    linker.func_wrap("lunatic::error", "drop", drop)?;
18    Ok(())
19}
20
21// Returns the size of the string representation of the error.
22//
23// Traps:
24// * If the error ID doesn't exist.
25fn string_size<T: ErrorCtx>(caller: Caller<T>, error_id: u64) -> Result<u32> {
26    let error = caller
27        .data()
28        .error_resources()
29        .get(error_id)
30        .or_trap("lunatic::error::string_size")?;
31    Ok(error.to_string().len() as u32)
32}
33
34// Writes the string representation of the error to the guest memory.
35// `lunatic::error::string_size` can be used to get the string size.
36//
37// Traps:
38// * If the error ID doesn't exist.
39// * If any memory outside the guest heap space is referenced.
40fn to_string<T: ErrorCtx>(mut caller: Caller<T>, error_id: u64, error_str_ptr: u32) -> Result<()> {
41    let error = caller
42        .data()
43        .error_resources()
44        .get(error_id)
45        .or_trap("lunatic::error::string_size")?;
46    let error_str = error.to_string();
47    let memory = get_memory(&mut caller)?;
48    memory
49        .write(&mut caller, error_str_ptr as usize, error_str.as_ref())
50        .or_trap("lunatic::error::string_size")?;
51    Ok(())
52}
53
54// Drops the error resource.
55//
56// Traps:
57// * If the error ID doesn't exist.
58fn drop<T: ErrorCtx>(mut caller: Caller<T>, error_id: u64) -> Result<()> {
59    caller
60        .data_mut()
61        .error_resources_mut()
62        .remove(error_id)
63        .or_trap("lunatic::error::drop")?;
64    Ok(())
65}