1
//! Checked downcasts of a guest `anyref`. wasmtime's `unwrap_*` accessors
2
//! panic on a kind mismatch; a malformed guest value must surface as an error
3
//! instead of aborting the host.
4

            
5
use wasmtime::{AnyRef, ArrayRef, AsContext, I31, Rooted, StructRef};
6

            
7
pub trait CheckedAnyRef {
8
    /// # Errors
9
    /// Fails when the reference is unrooted or is not an `i31`.
10
    fn checked_i31(&self, store: impl AsContext) -> wasmtime::Result<I31>;
11

            
12
    /// # Errors
13
    /// Fails when the reference is unrooted or is not a struct.
14
    fn checked_struct(&self, store: impl AsContext) -> wasmtime::Result<Rooted<StructRef>>;
15

            
16
    /// # Errors
17
    /// Fails when the reference is unrooted or is not an array.
18
    fn checked_array(&self, store: impl AsContext) -> wasmtime::Result<Rooted<ArrayRef>>;
19
}
20

            
21
impl CheckedAnyRef for Rooted<AnyRef> {
22
81
    fn checked_i31(&self, store: impl AsContext) -> wasmtime::Result<I31> {
23
81
        self.as_i31(store)?.ok_or_else(|| kind_mismatch("i31"))
24
81
    }
25

            
26
5016
    fn checked_struct(&self, store: impl AsContext) -> wasmtime::Result<Rooted<StructRef>> {
27
5016
        self.as_struct(store)?
28
5016
            .ok_or_else(|| kind_mismatch("struct"))
29
5016
    }
30

            
31
1184
    fn checked_array(&self, store: impl AsContext) -> wasmtime::Result<Rooted<ArrayRef>> {
32
1184
        self.as_array(store)?.ok_or_else(|| kind_mismatch("array"))
33
1184
    }
34
}
35

            
36
2
fn kind_mismatch(expected: &str) -> wasmtime::Error {
37
2
    wasmtime::Error::msg(format!("guest anyref is not the expected {expected} ref"))
38
2
}
39

            
40
#[cfg(test)]
41
mod tests;