use super::{super::REALLOC_AND_FREE, engine};
use wasmtime::{
Error, Store,
component::{Component, Linker},
format_err,
};
mod empty_error {
use super::*;
use wasmtime::component::HasSelf;
wasmtime::component::bindgen!({
inline: "
package inline:inline;
world result-playground {
import imports: interface {
empty-error: func(a: f64) -> result<f64>;
}
export empty-error: func(a: f64) -> result<f64>;
}",
imports: {default: trappable},
});
#[test]
fn run() -> Result<(), Error> {
let engine = engine();
let component = Component::new(
&engine,
r#"
(component
(import "imports" (instance $i
(export "empty-error" (func (param "a" f64) (result (result f64))))
))
(core module $libc
(memory (export "memory") 1)
)
(core instance $libc (instantiate $libc))
(core module $m
(import "" "core_empty_error" (func $f (param f64 i32)))
(import "libc" "memory" (memory 0))
(func (export "core_empty_error_export") (param f64) (result i32)
(call $f (local.get 0) (i32.const 8))
(i32.const 8)
)
)
(core func $core_empty_error
(canon lower (func $i "empty-error") (memory $libc "memory"))
)
(core instance $i (instantiate $m
(with "" (instance (export "core_empty_error" (func $core_empty_error))))
(with "libc" (instance $libc))
))
(func $f_empty_error
(export "empty-error")
(param "a" f64)
(result (result f64))
(canon lift (core func $i "core_empty_error_export") (memory $libc "memory"))
)
)
"#,
)?;
#[derive(Default)]
struct MyImports {}
impl imports::Host for MyImports {
fn empty_error(&mut self, a: f64) -> Result<Result<f64, ()>, Error> {
if a == 0.0 {
Ok(Ok(a))
} else if a == 1.0 {
Ok(Err(()))
} else {
Err(format_err!("empty_error: trap"))
}
}
}
let mut linker = Linker::new(&engine);
imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
let mut store = Store::new(&engine, MyImports::default());
let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;
assert_eq!(
results
.call_empty_error(&mut store, 0.0)
.expect("no trap")
.expect("no error returned"),
0.0
);
results
.call_empty_error(&mut store, 1.0)
.expect("no trap")
.err()
.expect("() error returned");
let e = results
.call_empty_error(&mut store, 2.0)
.err()
.expect("trap");
assert_eq!(
format!("{}", e.source().expect("trap message is stored in source")),
"empty_error: trap"
);
Ok(())
}
}
mod string_error {
use super::*;
use wasmtime::component::HasSelf;
wasmtime::component::bindgen!({
inline: "
package inline:inline;
world result-playground {
import imports: interface {
string-error: func(a: f64) -> result<f64, string>;
}
export string-error: func(a: f64) -> result<f64, string>;
}",
imports: { default: trappable },
});
#[test]
fn run() -> Result<(), Error> {
let engine = engine();
let component = Component::new(
&engine,
format!(
r#"
(component
(import "imports" (instance $i
(export "string-error" (func (param "a" f64) (result (result f64 (error string)))))
))
(core module $libc
(memory (export "memory") 1)
{REALLOC_AND_FREE}
)
(core instance $libc (instantiate $libc))
(core module $m
(import "" "core_string_error" (func $f (param f64 i32)))
(import "libc" "memory" (memory 0))
(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
(func (export "core_string_error_export") (param f64) (result i32)
(local $retptr i32)
(local.set $retptr
(call $realloc
(i32.const 0)
(i32.const 0)
(i32.const 4)
(i32.const 16)))
(call $f (local.get 0) (local.get $retptr))
(local.get $retptr)
)
)
(core func $core_string_error
(canon lower (func $i "string-error") (memory $libc "memory") (realloc (func $libc "realloc")))
)
(core instance $i (instantiate $m
(with "" (instance (export "core_string_error" (func $core_string_error))))
(with "libc" (instance $libc))
))
(func $f_string_error
(export "string-error")
(param "a" f64)
(result (result f64 (error string)))
(canon lift (core func $i "core_string_error_export") (memory $libc "memory"))
)
)
"#
),
)?;
#[derive(Default)]
struct MyImports {}
impl imports::Host for MyImports {
fn string_error(&mut self, a: f64) -> Result<Result<f64, String>, Error> {
if a == 0.0 {
Ok(Ok(a))
} else if a == 1.0 {
Ok(Err("string_error: error".to_owned()))
} else {
Err(format_err!("string_error: trap"))
}
}
}
let mut linker = Linker::new(&engine);
imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
let mut store = Store::new(&engine, MyImports::default());
let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;
assert_eq!(
results
.call_string_error(&mut store, 0.0)
.expect("no trap")
.expect("no error returned"),
0.0
);
let e = results
.call_string_error(&mut store, 1.0)
.expect("no trap")
.err()
.expect("error returned");
assert_eq!(e, "string_error: error");
let e = results
.call_string_error(&mut store, 2.0)
.err()
.expect("trap");
assert_eq!(
format!("{}", e.source().expect("trap message is stored in source")),
"string_error: trap"
);
Ok(())
}
}
mod enum_error {
use super::*;
use exports::foo;
use inline::inline::imports;
use wasmtime::component::HasSelf;
wasmtime::component::bindgen!({
inline: "
package inline:inline;
interface imports {
enum e1 { a, b, c }
enum-error: func(a: f64) -> result<f64, e1>;
}
world result-playground {
import imports;
export foo: interface {
enum e1 { a, b, c }
enum-error: func(a: f64) -> result<f64, e1>;
}
}",
trappable_error_type: { "inline:inline/imports.e1" => TrappableE1 },
imports: { default: trappable },
});
#[derive(Debug)]
pub struct MyTrap;
impl std::fmt::Display for MyTrap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for MyTrap {}
pub enum TrappableE1 {
Normal(imports::E1),
MyTrap(MyTrap),
}
impl From<MyTrap> for TrappableE1 {
fn from(t: MyTrap) -> TrappableE1 {
TrappableE1::MyTrap(t)
}
}
impl From<imports::E1> for TrappableE1 {
fn from(t: imports::E1) -> TrappableE1 {
TrappableE1::Normal(t)
}
}
#[test]
fn run() -> Result<(), Error> {
let engine = engine();
let component = Component::new(
&engine,
format!(
r#"
(component
(type $err' (enum "a" "b" "c"))
(import (interface "inline:inline/imports") (instance $i
(export "err" (type $err (eq $err')))
(export "enum-error" (func (param "a" f64) (result (result f64 (error $err)))))
))
(core module $libc
(memory (export "memory") 1)
{REALLOC_AND_FREE}
)
(core instance $libc (instantiate $libc))
(core module $m
(import "" "core_enum_error" (func $f (param f64 i32)))
(import "libc" "memory" (memory 0))
(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
(func (export "core_enum_error_export") (param f64) (result i32)
(local $retptr i32)
(local.set $retptr
(call $realloc
(i32.const 0)
(i32.const 0)
(i32.const 4)
(i32.const 16)))
(call $f (local.get 0) (local.get $retptr))
(local.get $retptr)
)
)
(core func $core_enum_error
(canon lower (func $i "enum-error") (memory $libc "memory") (realloc (func $libc "realloc")))
)
(core instance $i (instantiate $m
(with "" (instance (export "core_enum_error" (func $core_enum_error))))
(with "libc" (instance $libc))
))
(func $f_enum_error
(param "a" f64)
(result (result f64 (error $err')))
(canon lift (core func $i "core_enum_error_export") (memory $libc "memory"))
)
(component $nested
(import "f-err" (type $err (eq $err')))
(import "f" (func $f (param "a" f64) (result (result f64 (error $err)))))
(export $err2 "err" (type $err'))
(export "enum-error" (func $f) (func (param "a" f64) (result (result f64 (error $err2)))))
)
(instance $n (instantiate $nested
(with "f-err" (type $err'))
(with "f" (func $f_enum_error))
))
(export "foo" (instance $n))
)
"#
),
)?;
#[derive(Default)]
struct MyImports {}
impl imports::Host for MyImports {
fn convert_e1(&mut self, err: TrappableE1) -> wasmtime::Result<imports::E1> {
match err {
TrappableE1::Normal(e) => Ok(e),
TrappableE1::MyTrap(e) => Err(e.into()),
}
}
fn enum_error(&mut self, a: f64) -> Result<f64, TrappableE1> {
if a == 0.0 {
Ok(a)
} else if a == 1.0 {
Err(imports::E1::A)?
} else {
Err(MyTrap)?
}
}
}
let mut linker = Linker::new(&engine);
imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
let mut store = Store::new(&engine, MyImports::default());
let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;
assert_eq!(
results
.foo()
.call_enum_error(&mut store, 0.0)
.expect("no trap")
.expect("no error returned"),
0.0
);
let e = results
.foo()
.call_enum_error(&mut store, 1.0)
.expect("no trap")
.err()
.expect("error returned");
assert_eq!(e, foo::E1::A);
let e = results
.foo()
.call_enum_error(&mut store, 2.0)
.err()
.expect("trap");
assert_eq!(
format!("{}", e.source().expect("trap message is stored in source")),
"MyTrap"
);
e.downcast_ref::<MyTrap>()
.expect("downcast trap to concrete MyTrap type");
Ok(())
}
}
mod record_error {
use super::*;
use exports::foo;
use inline::inline::imports;
use wasmtime::component::HasSelf;
wasmtime::component::bindgen!({
inline: "
package inline:inline;
interface imports {
record e2 { line: u32, col: u32 }
record-error: func(a: f64) -> result<f64, e2>;
}
world result-playground {
import imports;
export foo: interface {
record e2 { line: u32, col: u32 }
record-error: func(a: f64) -> result<f64, e2>;
}
}",
trappable_error_type: { "inline:inline/imports.e2" => TrappableE2 },
imports: { default: trappable },
});
pub enum TrappableE2 {
Normal(imports::E2),
Trap(wasmtime::Error),
}
impl From<imports::E2> for TrappableE2 {
fn from(t: imports::E2) -> TrappableE2 {
TrappableE2::Normal(t)
}
}
#[test]
fn run() -> Result<(), Error> {
let engine = engine();
let component = Component::new(
&engine,
format!(
r#"
(component
(type $e2' (record
(field "line" u32)
(field "col" u32)
))
(import (interface "inline:inline/imports") (instance $i
(export "e2" (type $e2 (eq $e2')))
(type $result (result f64 (error $e2)))
(export "record-error" (func (param "a" f64) (result $result)))
))
(core module $libc
(memory (export "memory") 1)
{REALLOC_AND_FREE}
)
(core instance $libc (instantiate $libc))
(core module $m
(import "" "core_record_error" (func $f (param f64 i32)))
(import "libc" "memory" (memory 0))
(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
(func (export "core_record_error_export") (param f64) (result i32)
(local $retptr i32)
(local.set $retptr
(call $realloc
(i32.const 0)
(i32.const 0)
(i32.const 4)
(i32.const 16)))
(call $f (local.get 0) (local.get $retptr))
(local.get $retptr)
)
)
(core func $core_record_error
(canon lower (func $i "record-error") (memory $libc "memory") (realloc (func $libc "realloc")))
)
(core instance $i (instantiate $m
(with "" (instance (export "core_record_error" (func $core_record_error))))
(with "libc" (instance $libc))
))
(func $f_record_error
(param "a" f64)
(result (result f64 (error (record (field "line" u32) (field "col" u32)))))
(canon lift (core func $i "core_record_error_export") (memory $libc "memory"))
)
(component $nested
(import "f-e2" (type $f-e2 (eq $e2')))
(import "f" (func $f (param "a" f64) (result (result f64 (error $f-e2)))))
(export $e2 "e2" (type $e2'))
(export "record-error" (func $f) (func (param "a" f64) (result (result f64 (error $e2)))))
)
(instance (export "foo") (instantiate $nested
(with "f-e2" (type $e2'))
(with "f" (func $f_record_error))
))
)
"#
),
)?;
#[derive(Default)]
struct MyImports {}
impl imports::Host for MyImports {
fn convert_e2(&mut self, err: TrappableE2) -> wasmtime::Result<imports::E2> {
match err {
TrappableE2::Normal(e) => Ok(e),
TrappableE2::Trap(e) => Err(e),
}
}
fn record_error(&mut self, a: f64) -> Result<f64, TrappableE2> {
if a == 0.0 {
Ok(a)
} else if a == 1.0 {
Err(imports::E2 {
line: 420,
col: 1312,
})?
} else {
Err(TrappableE2::Trap(format_err!("record_error: trap")))
}
}
}
let mut linker = Linker::new(&engine);
imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
let mut store = Store::new(&engine, MyImports::default());
let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;
assert_eq!(
results
.foo()
.call_record_error(&mut store, 0.0)
.expect("no trap")
.expect("no error returned"),
0.0
);
let e = results
.foo()
.call_record_error(&mut store, 1.0)
.expect("no trap")
.err()
.expect("error returned");
assert!(matches!(
e,
record_error::foo::E2 {
line: 420,
col: 1312
}
));
let e = results
.foo()
.call_record_error(&mut store, 2.0)
.err()
.expect("trap");
assert_eq!(
format!("{}", e.source().expect("trap message is stored in source")),
"record_error: trap"
);
Ok(())
}
}
mod variant_error {
use super::*;
use exports::foo;
use inline::inline::imports;
use wasmtime::component::HasSelf;
wasmtime::component::bindgen!({
inline: "
package inline:inline;
interface imports {
enum e1 { a, b, c }
record e2 { line: u32, col: u32 }
variant e3 { E1(e1), E2(e2) }
variant-error: func(a: f64) -> result<f64, e3>;
}
world result-playground {
import imports;
export foo: interface {
enum e1 { a, b, c }
record e2 { line: u32, col: u32 }
variant e3 { E1(e1), E2(e2) }
variant-error: func(a: f64) -> result<f64, e3>;
}
}",
trappable_error_type: { "inline:inline/imports.e3" => TrappableE3 },
imports: { default: trappable },
});
pub enum TrappableE3 {
Normal(imports::E3),
Trap(wasmtime::Error),
}
impl From<imports::E3> for TrappableE3 {
fn from(t: imports::E3) -> TrappableE3 {
TrappableE3::Normal(t)
}
}
#[test]
fn run() -> Result<(), Error> {
let engine = engine();
let component = Component::new(
&engine,
format!(
r#"
(component
(type $e1' (enum "a" "b" "c"))
(type $e2' (record (field "line" u32) (field "col" u32)))
(type $e3' (variant
(case "E1" $e1')
(case "E2" $e2')
))
(import (interface "inline:inline/imports") (instance $i
(export "e1" (type $e1 (eq $e1')))
(export "e2" (type $e2 (eq $e2')))
(type $e3' (variant
(case "E1" $e1)
(case "E2" $e2)
))
(export "e3" (type $e3 (eq $e3')))
(type $result (result f64 (error $e3)))
(export "variant-error" (func (param "a" f64) (result $result)))
))
(core module $libc
(memory (export "memory") 1)
{REALLOC_AND_FREE}
)
(core instance $libc (instantiate $libc))
(core module $m
(import "" "core_variant_error" (func $f (param f64 i32)))
(import "libc" "memory" (memory 0))
(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
(func (export "core_variant_error_export") (param f64) (result i32)
(local $retptr i32)
(local.set $retptr
(call $realloc
(i32.const 0)
(i32.const 0)
(i32.const 4)
(i32.const 16)))
(call $f (local.get 0) (local.get $retptr))
(local.get $retptr)
)
)
(core func $core_variant_error
(canon lower (func $i "variant-error") (memory $libc "memory") (realloc (func $libc "realloc")))
)
(core instance $i (instantiate $m
(with "" (instance (export "core_variant_error" (func $core_variant_error))))
(with "libc" (instance $libc))
))
(func $f_variant_error
(param "a" f64)
(result (result f64 (error $e3')))
(canon lift (core func $i "core_variant_error_export") (memory $libc "memory"))
)
(component $nested
(import "f-e1" (type $e1i (eq $e1')))
(import "f-e2" (type $e2i (eq $e2')))
(type $e3i' (variant
(case "E1" $e1i)
(case "E2" $e2i)
))
(import "f-e3" (type $e3i (eq $e3i')))
(import "f" (func $f (param "a" f64) (result (result f64 (error $e3i)))))
(export $e1 "e1" (type $e1'))
(export $e2 "e2" (type $e2'))
(type $e3' (variant
(case "E1" $e1)
(case "E2" $e2)
))
(export $e3 "e3" (type $e3'))
(export "variant-error" (func $f)
(func (param "a" f64) (result (result f64 (error $e3)))))
)
(instance (export "foo") (instantiate $nested
(with "f-e1" (type $e1'))
(with "f-e2" (type $e2'))
(with "f-e3" (type $e3'))
(with "f" (func $f_variant_error))
))
)
"#
),
)?;
#[derive(Default)]
struct MyImports {}
impl imports::Host for MyImports {
fn convert_e3(&mut self, err: TrappableE3) -> wasmtime::Result<imports::E3> {
match err {
TrappableE3::Normal(e) => Ok(e),
TrappableE3::Trap(e) => Err(e),
}
}
fn variant_error(&mut self, a: f64) -> Result<f64, TrappableE3> {
if a == 0.0 {
Ok(a)
} else if a == 1.0 {
Err(imports::E3::E2(imports::E2 {
line: 420,
col: 1312,
}))?
} else {
Err(TrappableE3::Trap(format_err!("variant_error: trap")))
}
}
}
let mut linker = Linker::new(&engine);
imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
let mut store = Store::new(&engine, MyImports::default());
let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;
assert_eq!(
results
.foo()
.call_variant_error(&mut store, 0.0)
.expect("no trap")
.expect("no error returned"),
0.0
);
let e = results
.foo()
.call_variant_error(&mut store, 1.0)
.expect("no trap")
.err()
.expect("error returned");
assert!(matches!(
e,
variant_error::foo::E3::E2(variant_error::foo::E2 {
line: 420,
col: 1312
})
));
let e = results
.foo()
.call_variant_error(&mut store, 2.0)
.err()
.expect("trap");
assert_eq!(
format!("{}", e.source().expect("trap message is stored in source")),
"variant_error: trap"
);
Ok(())
}
}
mod multiple_interfaces_error {
use super::*;
use exports::foo;
use inline::inline::imports;
use inline::inline::types;
use wasmtime::component::HasSelf;
wasmtime::component::bindgen!({
inline: "
package inline:inline;
interface types {
enum e1 { a, b, c }
enum-error: func(a: f64) -> result<f64, e1>;
}
interface imports {
use types.{e1};
enum-error: func(a: f64) -> result<f64, e1>;
}
world result-playground {
import imports;
export foo: interface {
enum e1 { a, b, c }
enum-error: func(a: f64) -> result<f64, e1>;
}
}",
trappable_error_type: { "inline:inline/types.e1" => TrappableE1 },
imports: { default: trappable },
});
pub enum TrappableE1 {
Normal(types::E1),
Trap(wasmtime::Error),
}
impl From<types::E1> for TrappableE1 {
fn from(t: imports::E1) -> TrappableE1 {
TrappableE1::Normal(t)
}
}
#[test]
fn run() -> Result<(), Error> {
let engine = engine();
let component = Component::new(
&engine,
format!(
r#"
(component
(type $err' (enum "a" "b" "c"))
(import (interface "inline:inline/imports") (instance $i
(export "e1" (type $e1 (eq $err')))
(export "enum-error" (func (param "a" f64) (result (result f64 (error $e1)))))
))
(core module $libc
(memory (export "memory") 1)
{REALLOC_AND_FREE}
)
(core instance $libc (instantiate $libc))
(core module $m
(import "" "core_enum_error" (func $f (param f64 i32)))
(import "libc" "memory" (memory 0))
(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
(func (export "core_enum_error_export") (param f64) (result i32)
(local $retptr i32)
(local.set $retptr
(call $realloc
(i32.const 0)
(i32.const 0)
(i32.const 4)
(i32.const 16)))
(call $f (local.get 0) (local.get $retptr))
(local.get $retptr)
)
)
(core func $core_enum_error
(canon lower (func $i "enum-error") (memory $libc "memory") (realloc (func $libc "realloc")))
)
(core instance $i (instantiate $m
(with "" (instance (export "core_enum_error" (func $core_enum_error))))
(with "libc" (instance $libc))
))
(func $f_enum_error
(param "a" f64)
(result (result f64 (error $err')))
(canon lift (core func $i "core_enum_error_export") (memory $libc "memory"))
)
(component $nested
(import "f-err" (type $err (eq $err')))
(import "f" (func $f (param "a" f64) (result (result f64 (error $err)))))
(export $err2 "err" (type $err'))
(export "enum-error" (func $f) (func (param "a" f64) (result (result f64 (error $err2)))))
)
(instance $n (instantiate $nested
(with "f-err" (type $err'))
(with "f" (func $f_enum_error))
))
(export "foo" (instance $n))
)
"#
),
)?;
#[derive(Debug)]
struct MyTrap;
impl std::fmt::Display for MyTrap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for MyTrap {}
impl From<MyTrap> for TrappableE1 {
fn from(t: MyTrap) -> TrappableE1 {
TrappableE1::Trap(format_err!(t))
}
}
#[derive(Default)]
struct MyImports {}
impl types::Host for MyImports {
fn convert_e1(&mut self, err: TrappableE1) -> wasmtime::Result<imports::E1> {
match err {
TrappableE1::Normal(e) => Ok(e),
TrappableE1::Trap(e) => Err(e),
}
}
fn enum_error(&mut self, a: f64) -> Result<f64, TrappableE1> {
if a == 0.0 {
Ok(a)
} else if a == 1.0 {
Err(imports::E1::A)?
} else {
Err(MyTrap)?
}
}
}
impl imports::Host for MyImports {
fn enum_error(&mut self, a: f64) -> Result<f64, TrappableE1> {
if a == 0.0 {
Ok(a)
} else if a == 1.0 {
Err(imports::E1::A)?
} else {
Err(MyTrap)?
}
}
}
let mut linker = Linker::new(&engine);
imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
let mut store = Store::new(&engine, MyImports::default());
let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;
assert_eq!(
results
.foo()
.call_enum_error(&mut store, 0.0)
.expect("no trap")
.expect("no error returned"),
0.0
);
let e = results
.foo()
.call_enum_error(&mut store, 1.0)
.expect("no trap")
.err()
.expect("error returned");
assert_eq!(e, foo::E1::A);
let e = results
.foo()
.call_enum_error(&mut store, 2.0)
.err()
.expect("trap");
assert_eq!(
format!("{}", e.source().expect("trap message is stored in source")),
"MyTrap"
);
e.downcast_ref::<MyTrap>()
.expect("downcast trap to concrete MyTrap type");
Ok(())
}
}
mod with_remapping {
use super::*;
use wasmtime::component::HasSelf;
mod interfaces {
wasmtime::component::bindgen!({
interfaces: "
import imports: interface {
empty-error: func(a: f64) -> result<f64>;
}",
imports: { default: trappable },
});
}
wasmtime::component::bindgen!({
inline: "
package inline:inline;
world result-playground {
import imports: interface {
empty-error: func(a: f64) -> result<f64>;
}
export empty-error: func(a: f64) -> result<f64>;
}",
with: {
"imports": interfaces::imports,
},
imports: { default: trappable },
});
#[test]
fn run() -> Result<(), Error> {
let engine = engine();
let component = Component::new(
&engine,
r#"
(component
(import "imports" (instance $i
(export "empty-error" (func (param "a" f64) (result (result f64))))
))
(core module $libc
(memory (export "memory") 1)
)
(core instance $libc (instantiate $libc))
(core module $m
(import "" "core_empty_error" (func $f (param f64 i32)))
(import "libc" "memory" (memory 0))
(func (export "core_empty_error_export") (param f64) (result i32)
(call $f (local.get 0) (i32.const 8))
(i32.const 8)
)
)
(core func $core_empty_error
(canon lower (func $i "empty-error") (memory $libc "memory"))
)
(core instance $i (instantiate $m
(with "" (instance (export "core_empty_error" (func $core_empty_error))))
(with "libc" (instance $libc))
))
(func $f_empty_error
(export "empty-error")
(param "a" f64)
(result (result f64))
(canon lift (core func $i "core_empty_error_export") (memory $libc "memory"))
)
)
"#,
)?;
#[derive(Default)]
struct MyImports {}
impl interfaces::imports::Host for MyImports {
fn empty_error(&mut self, a: f64) -> Result<Result<f64, ()>, Error> {
if a == 0.0 {
Ok(Ok(a))
} else if a == 1.0 {
Ok(Err(()))
} else {
Err(format_err!("empty_error: trap"))
}
}
}
let mut linker = Linker::new(&engine);
interfaces::imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
let mut store = Store::new(&engine, MyImports::default());
let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;
assert_eq!(
results
.call_empty_error(&mut store, 0.0)
.expect("no trap")
.expect("no error returned"),
0.0
);
results
.call_empty_error(&mut store, 1.0)
.expect("no trap")
.err()
.expect("() error returned");
let e = results
.call_empty_error(&mut store, 2.0)
.err()
.expect("trap");
assert_eq!(
format!("{}", e.source().expect("trap message is stored in source")),
"empty_error: trap"
);
Ok(())
}
}