Skip to main content

scripting/
checked_ref.rs

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
5use wasmtime::{AnyRef, ArrayRef, AsContext, I31, Rooted, StructRef};
6
7pub 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
21impl CheckedAnyRef for Rooted<AnyRef> {
22    fn checked_i31(&self, store: impl AsContext) -> wasmtime::Result<I31> {
23        self.as_i31(store)?.ok_or_else(|| kind_mismatch("i31"))
24    }
25
26    fn checked_struct(&self, store: impl AsContext) -> wasmtime::Result<Rooted<StructRef>> {
27        self.as_struct(store)?
28            .ok_or_else(|| kind_mismatch("struct"))
29    }
30
31    fn checked_array(&self, store: impl AsContext) -> wasmtime::Result<Rooted<ArrayRef>> {
32        self.as_array(store)?.ok_or_else(|| kind_mismatch("array"))
33    }
34}
35
36fn kind_mismatch(expected: &str) -> wasmtime::Error {
37    wasmtime::Error::msg(format!("guest anyref is not the expected {expected} ref"))
38}
39
40#[cfg(test)]
41mod tests;