Path: blob/main/tests/all/component_model/bindgen/results.rs
1692 views
use super::{super::REALLOC_AND_FREE, engine};1use anyhow::{Error, anyhow};2use wasmtime::{3Store,4component::{Component, Linker},5};67mod empty_error {8use super::*;9use wasmtime::component::HasSelf;1011wasmtime::component::bindgen!({12inline: "13package inline:inline;14world result-playground {15import imports: interface {16empty-error: func(a: f64) -> result<f64>;17}1819export empty-error: func(a: f64) -> result<f64>;20}",21imports: {default: trappable},22});2324#[test]25fn run() -> Result<(), Error> {26let engine = engine();27let component = Component::new(28&engine,29r#"30(component31(import "imports" (instance $i32(export "empty-error" (func (param "a" f64) (result (result f64))))33))34(core module $libc35(memory (export "memory") 1)36)37(core instance $libc (instantiate $libc))38(core module $m39(import "" "core_empty_error" (func $f (param f64 i32)))40(import "libc" "memory" (memory 0))41(func (export "core_empty_error_export") (param f64) (result i32)42(call $f (local.get 0) (i32.const 8))43(i32.const 8)44)45)46(core func $core_empty_error47(canon lower (func $i "empty-error") (memory $libc "memory"))48)49(core instance $i (instantiate $m50(with "" (instance (export "core_empty_error" (func $core_empty_error))))51(with "libc" (instance $libc))52))53(func $f_empty_error54(export "empty-error")55(param "a" f64)56(result (result f64))57(canon lift (core func $i "core_empty_error_export") (memory $libc "memory"))58)59)60"#,61)?;6263#[derive(Default)]64struct MyImports {}6566impl imports::Host for MyImports {67fn empty_error(&mut self, a: f64) -> Result<Result<f64, ()>, Error> {68if a == 0.0 {69Ok(Ok(a))70} else if a == 1.0 {71Ok(Err(()))72} else {73Err(anyhow!("empty_error: trap"))74}75}76}7778let mut linker = Linker::new(&engine);79imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;8081let mut store = Store::new(&engine, MyImports::default());82let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;8384assert_eq!(85results86.call_empty_error(&mut store, 0.0)87.expect("no trap")88.expect("no error returned"),890.090);9192results93.call_empty_error(&mut store, 1.0)94.expect("no trap")95.err()96.expect("() error returned");9798let e = results99.call_empty_error(&mut store, 2.0)100.err()101.expect("trap");102assert_eq!(103format!("{}", e.source().expect("trap message is stored in source")),104"empty_error: trap"105);106107Ok(())108}109}110111mod string_error {112use super::*;113use wasmtime::component::HasSelf;114115wasmtime::component::bindgen!({116inline: "117package inline:inline;118world result-playground {119import imports: interface {120string-error: func(a: f64) -> result<f64, string>;121}122123export string-error: func(a: f64) -> result<f64, string>;124}",125imports: { default: trappable },126});127128#[test]129fn run() -> Result<(), Error> {130let engine = engine();131let component = Component::new(132&engine,133format!(134r#"135(component136(import "imports" (instance $i137(export "string-error" (func (param "a" f64) (result (result f64 (error string)))))138))139(core module $libc140(memory (export "memory") 1)141{REALLOC_AND_FREE}142)143(core instance $libc (instantiate $libc))144(core module $m145(import "" "core_string_error" (func $f (param f64 i32)))146(import "libc" "memory" (memory 0))147(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))148(func (export "core_string_error_export") (param f64) (result i32)149(local $retptr i32)150(local.set $retptr151(call $realloc152(i32.const 0)153(i32.const 0)154(i32.const 4)155(i32.const 16)))156(call $f (local.get 0) (local.get $retptr))157(local.get $retptr)158)159)160(core func $core_string_error161(canon lower (func $i "string-error") (memory $libc "memory") (realloc (func $libc "realloc")))162)163(core instance $i (instantiate $m164(with "" (instance (export "core_string_error" (func $core_string_error))))165(with "libc" (instance $libc))166))167(func $f_string_error168(export "string-error")169(param "a" f64)170(result (result f64 (error string)))171(canon lift (core func $i "core_string_error_export") (memory $libc "memory"))172)173)174"#175),176)?;177178#[derive(Default)]179struct MyImports {}180181impl imports::Host for MyImports {182fn string_error(&mut self, a: f64) -> Result<Result<f64, String>, Error> {183if a == 0.0 {184Ok(Ok(a))185} else if a == 1.0 {186Ok(Err("string_error: error".to_owned()))187} else {188Err(anyhow!("string_error: trap"))189}190}191}192193let mut linker = Linker::new(&engine);194imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;195196let mut store = Store::new(&engine, MyImports::default());197let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;198199assert_eq!(200results201.call_string_error(&mut store, 0.0)202.expect("no trap")203.expect("no error returned"),2040.0205);206207let e = results208.call_string_error(&mut store, 1.0)209.expect("no trap")210.err()211.expect("error returned");212assert_eq!(e, "string_error: error");213214let e = results215.call_string_error(&mut store, 2.0)216.err()217.expect("trap");218assert_eq!(219format!("{}", e.source().expect("trap message is stored in source")),220"string_error: trap"221);222223Ok(())224}225}226227mod enum_error {228use super::*;229use exports::foo;230use inline::inline::imports;231use wasmtime::component::HasSelf;232233wasmtime::component::bindgen!({234inline: "235package inline:inline;236interface imports {237enum e1 { a, b, c }238enum-error: func(a: f64) -> result<f64, e1>;239}240world result-playground {241import imports;242export foo: interface {243enum e1 { a, b, c }244enum-error: func(a: f64) -> result<f64, e1>;245}246}",247trappable_error_type: { "inline:inline/imports/e1" => TrappableE1 },248imports: { default: trappable },249});250251// You can create concrete trap types which make it all the way out to the252// host caller, via downcast_ref below.253#[derive(Debug)]254pub struct MyTrap;255256impl std::fmt::Display for MyTrap {257fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {258write!(f, "{self:?}")259}260}261impl std::error::Error for MyTrap {}262263pub enum TrappableE1 {264Normal(imports::E1),265MyTrap(MyTrap),266}267268// It is possible to define From impls that target these generated trappable269// types. This allows you to integrate libraries with other error types, or270// use your own more descriptive error types, and use ? to convert them at271// their throw site.272impl From<MyTrap> for TrappableE1 {273fn from(t: MyTrap) -> TrappableE1 {274TrappableE1::MyTrap(t)275}276}277278impl From<imports::E1> for TrappableE1 {279fn from(t: imports::E1) -> TrappableE1 {280TrappableE1::Normal(t)281}282}283284#[test]285fn run() -> Result<(), Error> {286let engine = engine();287let component = Component::new(288&engine,289format!(290r#"291(component292(type $err' (enum "a" "b" "c"))293(import (interface "inline:inline/imports") (instance $i294(export "err" (type $err (eq $err')))295(export "enum-error" (func (param "a" f64) (result (result f64 (error $err)))))296))297(core module $libc298(memory (export "memory") 1)299{REALLOC_AND_FREE}300)301(core instance $libc (instantiate $libc))302(core module $m303(import "" "core_enum_error" (func $f (param f64 i32)))304(import "libc" "memory" (memory 0))305(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))306(func (export "core_enum_error_export") (param f64) (result i32)307(local $retptr i32)308(local.set $retptr309(call $realloc310(i32.const 0)311(i32.const 0)312(i32.const 4)313(i32.const 16)))314(call $f (local.get 0) (local.get $retptr))315(local.get $retptr)316)317)318(core func $core_enum_error319(canon lower (func $i "enum-error") (memory $libc "memory") (realloc (func $libc "realloc")))320)321(core instance $i (instantiate $m322(with "" (instance (export "core_enum_error" (func $core_enum_error))))323(with "libc" (instance $libc))324))325(func $f_enum_error326(param "a" f64)327(result (result f64 (error $err')))328(canon lift (core func $i "core_enum_error_export") (memory $libc "memory"))329)330331(component $nested332(import "f-err" (type $err (eq $err')))333(import "f" (func $f (param "a" f64) (result (result f64 (error $err)))))334(export $err2 "err" (type $err'))335(export "enum-error" (func $f) (func (param "a" f64) (result (result f64 (error $err2)))))336)337338(instance $n (instantiate $nested339(with "f-err" (type $err'))340(with "f" (func $f_enum_error))341))342(export "foo" (instance $n))343)344"#345),346)?;347348#[derive(Default)]349struct MyImports {}350351impl imports::Host for MyImports {352fn convert_e1(&mut self, err: TrappableE1) -> anyhow::Result<imports::E1> {353match err {354TrappableE1::Normal(e) => Ok(e),355TrappableE1::MyTrap(e) => Err(e.into()),356}357}358359fn enum_error(&mut self, a: f64) -> Result<f64, TrappableE1> {360if a == 0.0 {361Ok(a)362} else if a == 1.0 {363Err(imports::E1::A)?364} else {365Err(MyTrap)?366}367}368}369370let mut linker = Linker::new(&engine);371imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;372373let mut store = Store::new(&engine, MyImports::default());374let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;375376assert_eq!(377results378.foo()379.call_enum_error(&mut store, 0.0)380.expect("no trap")381.expect("no error returned"),3820.0383);384385let e = results386.foo()387.call_enum_error(&mut store, 1.0)388.expect("no trap")389.err()390.expect("error returned");391assert_eq!(e, foo::E1::A);392393let e = results394.foo()395.call_enum_error(&mut store, 2.0)396.err()397.expect("trap");398assert_eq!(399format!("{}", e.source().expect("trap message is stored in source")),400"MyTrap"401);402e.downcast_ref::<MyTrap>()403.expect("downcast trap to concrete MyTrap type");404405Ok(())406}407}408409mod record_error {410use super::*;411use exports::foo;412use inline::inline::imports;413use wasmtime::component::HasSelf;414415wasmtime::component::bindgen!({416inline: "417package inline:inline;418interface imports {419record e2 { line: u32, col: u32 }420record-error: func(a: f64) -> result<f64, e2>;421}422world result-playground {423import imports;424export foo: interface {425record e2 { line: u32, col: u32 }426record-error: func(a: f64) -> result<f64, e2>;427}428}",429trappable_error_type: { "inline:inline/imports/e2" => TrappableE2 },430imports: { default: trappable },431});432433pub enum TrappableE2 {434Normal(imports::E2),435Trap(anyhow::Error),436}437438impl From<imports::E2> for TrappableE2 {439fn from(t: imports::E2) -> TrappableE2 {440TrappableE2::Normal(t)441}442}443444#[test]445fn run() -> Result<(), Error> {446let engine = engine();447let component = Component::new(448&engine,449format!(450r#"451(component452(type $e2' (record453(field "line" u32)454(field "col" u32)455))456(import (interface "inline:inline/imports") (instance $i457(export "e2" (type $e2 (eq $e2')))458(type $result (result f64 (error $e2)))459(export "record-error" (func (param "a" f64) (result $result)))460))461(core module $libc462(memory (export "memory") 1)463{REALLOC_AND_FREE}464)465(core instance $libc (instantiate $libc))466(core module $m467(import "" "core_record_error" (func $f (param f64 i32)))468(import "libc" "memory" (memory 0))469(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))470(func (export "core_record_error_export") (param f64) (result i32)471(local $retptr i32)472(local.set $retptr473(call $realloc474(i32.const 0)475(i32.const 0)476(i32.const 4)477(i32.const 16)))478(call $f (local.get 0) (local.get $retptr))479(local.get $retptr)480)481)482(core func $core_record_error483(canon lower (func $i "record-error") (memory $libc "memory") (realloc (func $libc "realloc")))484)485(core instance $i (instantiate $m486(with "" (instance (export "core_record_error" (func $core_record_error))))487(with "libc" (instance $libc))488))489(func $f_record_error490(param "a" f64)491(result (result f64 (error (record (field "line" u32) (field "col" u32)))))492(canon lift (core func $i "core_record_error_export") (memory $libc "memory"))493)494495(component $nested496(import "f-e2" (type $f-e2 (eq $e2')))497(import "f" (func $f (param "a" f64) (result (result f64 (error $f-e2)))))498(export $e2 "e2" (type $e2'))499(export "record-error" (func $f) (func (param "a" f64) (result (result f64 (error $e2)))))500)501502(instance (export "foo") (instantiate $nested503(with "f-e2" (type $e2'))504(with "f" (func $f_record_error))505))506)507"#508),509)?;510511#[derive(Default)]512struct MyImports {}513514impl imports::Host for MyImports {515fn convert_e2(&mut self, err: TrappableE2) -> anyhow::Result<imports::E2> {516match err {517TrappableE2::Normal(e) => Ok(e),518TrappableE2::Trap(e) => Err(e),519}520}521fn record_error(&mut self, a: f64) -> Result<f64, TrappableE2> {522if a == 0.0 {523Ok(a)524} else if a == 1.0 {525Err(imports::E2 {526line: 420,527col: 1312,528})?529} else {530Err(TrappableE2::Trap(anyhow!("record_error: trap")))531}532}533}534535let mut linker = Linker::new(&engine);536imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;537538let mut store = Store::new(&engine, MyImports::default());539let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;540541assert_eq!(542results543.foo()544.call_record_error(&mut store, 0.0)545.expect("no trap")546.expect("no error returned"),5470.0548);549550let e = results551.foo()552.call_record_error(&mut store, 1.0)553.expect("no trap")554.err()555.expect("error returned");556assert!(matches!(557e,558record_error::foo::E2 {559line: 420,560col: 1312561}562));563564let e = results565.foo()566.call_record_error(&mut store, 2.0)567.err()568.expect("trap");569assert_eq!(570format!("{}", e.source().expect("trap message is stored in source")),571"record_error: trap"572);573574Ok(())575}576}577578mod variant_error {579use super::*;580use exports::foo;581use inline::inline::imports;582use wasmtime::component::HasSelf;583584wasmtime::component::bindgen!({585inline: "586package inline:inline;587interface imports {588enum e1 { a, b, c }589record e2 { line: u32, col: u32 }590variant e3 { E1(e1), E2(e2) }591variant-error: func(a: f64) -> result<f64, e3>;592}593world result-playground {594import imports;595export foo: interface {596enum e1 { a, b, c }597record e2 { line: u32, col: u32 }598variant e3 { E1(e1), E2(e2) }599variant-error: func(a: f64) -> result<f64, e3>;600}601}",602trappable_error_type: { "inline:inline/imports/e3" => TrappableE3 },603imports: { default: trappable },604});605606pub enum TrappableE3 {607Normal(imports::E3),608Trap(anyhow::Error),609}610611impl From<imports::E3> for TrappableE3 {612fn from(t: imports::E3) -> TrappableE3 {613TrappableE3::Normal(t)614}615}616617#[test]618fn run() -> Result<(), Error> {619let engine = engine();620let component = Component::new(621&engine,622format!(623r#"624(component625(type $e1' (enum "a" "b" "c"))626(type $e2' (record (field "line" u32) (field "col" u32)))627(type $e3' (variant628(case "E1" $e1')629(case "E2" $e2')630))631(import (interface "inline:inline/imports") (instance $i632(export "e1" (type $e1 (eq $e1')))633(export "e2" (type $e2 (eq $e2')))634(type $e3' (variant635(case "E1" $e1)636(case "E2" $e2)637))638(export "e3" (type $e3 (eq $e3')))639(type $result (result f64 (error $e3)))640(export "variant-error" (func (param "a" f64) (result $result)))641))642(core module $libc643(memory (export "memory") 1)644{REALLOC_AND_FREE}645)646(core instance $libc (instantiate $libc))647(core module $m648(import "" "core_variant_error" (func $f (param f64 i32)))649(import "libc" "memory" (memory 0))650(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))651(func (export "core_variant_error_export") (param f64) (result i32)652(local $retptr i32)653(local.set $retptr654(call $realloc655(i32.const 0)656(i32.const 0)657(i32.const 4)658(i32.const 16)))659(call $f (local.get 0) (local.get $retptr))660(local.get $retptr)661)662)663(core func $core_variant_error664(canon lower (func $i "variant-error") (memory $libc "memory") (realloc (func $libc "realloc")))665)666(core instance $i (instantiate $m667(with "" (instance (export "core_variant_error" (func $core_variant_error))))668(with "libc" (instance $libc))669))670(func $f_variant_error671(param "a" f64)672(result (result f64 (error $e3')))673(canon lift (core func $i "core_variant_error_export") (memory $libc "memory"))674)675676(component $nested677(import "f-e1" (type $e1i (eq $e1')))678(import "f-e2" (type $e2i (eq $e2')))679(type $e3i' (variant680(case "E1" $e1i)681(case "E2" $e2i)682))683(import "f-e3" (type $e3i (eq $e3i')))684(import "f" (func $f (param "a" f64) (result (result f64 (error $e3i)))))685(export $e1 "e1" (type $e1'))686(export $e2 "e2" (type $e2'))687(type $e3' (variant688(case "E1" $e1)689(case "E2" $e2)690))691(export $e3 "e3" (type $e3'))692(export "variant-error" (func $f)693(func (param "a" f64) (result (result f64 (error $e3)))))694)695696(instance (export "foo") (instantiate $nested697(with "f-e1" (type $e1'))698(with "f-e2" (type $e2'))699(with "f-e3" (type $e3'))700(with "f" (func $f_variant_error))701))702)703"#704),705)?;706707#[derive(Default)]708struct MyImports {}709710impl imports::Host for MyImports {711fn convert_e3(&mut self, err: TrappableE3) -> anyhow::Result<imports::E3> {712match err {713TrappableE3::Normal(e) => Ok(e),714TrappableE3::Trap(e) => Err(e),715}716}717fn variant_error(&mut self, a: f64) -> Result<f64, TrappableE3> {718if a == 0.0 {719Ok(a)720} else if a == 1.0 {721Err(imports::E3::E2(imports::E2 {722line: 420,723col: 1312,724}))?725} else {726Err(TrappableE3::Trap(anyhow!("variant_error: trap")))727}728}729}730731let mut linker = Linker::new(&engine);732imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;733734let mut store = Store::new(&engine, MyImports::default());735let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;736737assert_eq!(738results739.foo()740.call_variant_error(&mut store, 0.0)741.expect("no trap")742.expect("no error returned"),7430.0744);745746let e = results747.foo()748.call_variant_error(&mut store, 1.0)749.expect("no trap")750.err()751.expect("error returned");752assert!(matches!(753e,754variant_error::foo::E3::E2(variant_error::foo::E2 {755line: 420,756col: 1312757})758));759760let e = results761.foo()762.call_variant_error(&mut store, 2.0)763.err()764.expect("trap");765assert_eq!(766format!("{}", e.source().expect("trap message is stored in source")),767"variant_error: trap"768);769770Ok(())771}772}773774mod multiple_interfaces_error {775use super::*;776use exports::foo;777use inline::inline::imports;778use inline::inline::types;779use wasmtime::component::HasSelf;780781wasmtime::component::bindgen!({782inline: "783package inline:inline;784interface types {785enum e1 { a, b, c }786enum-error: func(a: f64) -> result<f64, e1>;787}788interface imports {789use types.{e1};790enum-error: func(a: f64) -> result<f64, e1>;791}792world result-playground {793import imports;794export foo: interface {795enum e1 { a, b, c }796enum-error: func(a: f64) -> result<f64, e1>;797}798}",799trappable_error_type: { "inline:inline/types/e1" => TrappableE1 },800imports: { default: trappable },801});802803pub enum TrappableE1 {804Normal(types::E1),805Trap(anyhow::Error),806}807808impl From<types::E1> for TrappableE1 {809fn from(t: imports::E1) -> TrappableE1 {810TrappableE1::Normal(t)811}812}813814#[test]815fn run() -> Result<(), Error> {816let engine = engine();817// NOTE: this component doesn't make use of a types import, and relies instead on818// subtyping.819let component = Component::new(820&engine,821format!(822r#"823(component824(type $err' (enum "a" "b" "c"))825(import (interface "inline:inline/imports") (instance $i826(export "e1" (type $e1 (eq $err')))827(export "enum-error" (func (param "a" f64) (result (result f64 (error $e1)))))828))829(core module $libc830(memory (export "memory") 1)831{REALLOC_AND_FREE}832)833(core instance $libc (instantiate $libc))834(core module $m835(import "" "core_enum_error" (func $f (param f64 i32)))836(import "libc" "memory" (memory 0))837(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))838(func (export "core_enum_error_export") (param f64) (result i32)839(local $retptr i32)840(local.set $retptr841(call $realloc842(i32.const 0)843(i32.const 0)844(i32.const 4)845(i32.const 16)))846(call $f (local.get 0) (local.get $retptr))847(local.get $retptr)848)849)850(core func $core_enum_error851(canon lower (func $i "enum-error") (memory $libc "memory") (realloc (func $libc "realloc")))852)853(core instance $i (instantiate $m854(with "" (instance (export "core_enum_error" (func $core_enum_error))))855(with "libc" (instance $libc))856))857(func $f_enum_error858(param "a" f64)859(result (result f64 (error $err')))860(canon lift (core func $i "core_enum_error_export") (memory $libc "memory"))861)862863(component $nested864(import "f-err" (type $err (eq $err')))865(import "f" (func $f (param "a" f64) (result (result f64 (error $err)))))866(export $err2 "err" (type $err'))867(export "enum-error" (func $f) (func (param "a" f64) (result (result f64 (error $err2)))))868)869870(instance $n (instantiate $nested871(with "f-err" (type $err'))872(with "f" (func $f_enum_error))873))874(export "foo" (instance $n))875)876"#877),878)?;879880// You can create concrete trap types which make it all the way out to the881// host caller, via downcast_ref below.882#[derive(Debug)]883struct MyTrap;884885impl std::fmt::Display for MyTrap {886fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {887write!(f, "{self:?}")888}889}890impl std::error::Error for MyTrap {}891892// It is possible to define From impls that target these generated trappable893// types. This allows you to integrate libraries with other error types, or894// use your own more descriptive error types, and use ? to convert them at895// their throw site.896impl From<MyTrap> for TrappableE1 {897fn from(t: MyTrap) -> TrappableE1 {898TrappableE1::Trap(anyhow!(t))899}900}901902#[derive(Default)]903struct MyImports {}904905impl types::Host for MyImports {906fn convert_e1(&mut self, err: TrappableE1) -> anyhow::Result<imports::E1> {907match err {908TrappableE1::Normal(e) => Ok(e),909TrappableE1::Trap(e) => Err(e),910}911}912fn enum_error(&mut self, a: f64) -> Result<f64, TrappableE1> {913if a == 0.0 {914Ok(a)915} else if a == 1.0 {916Err(imports::E1::A)?917} else {918Err(MyTrap)?919}920}921}922923impl imports::Host for MyImports {924fn enum_error(&mut self, a: f64) -> Result<f64, TrappableE1> {925if a == 0.0 {926Ok(a)927} else if a == 1.0 {928Err(imports::E1::A)?929} else {930Err(MyTrap)?931}932}933}934935let mut linker = Linker::new(&engine);936imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;937938let mut store = Store::new(&engine, MyImports::default());939let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;940941assert_eq!(942results943.foo()944.call_enum_error(&mut store, 0.0)945.expect("no trap")946.expect("no error returned"),9470.0948);949950let e = results951.foo()952.call_enum_error(&mut store, 1.0)953.expect("no trap")954.err()955.expect("error returned");956assert_eq!(e, foo::E1::A);957958let e = results959.foo()960.call_enum_error(&mut store, 2.0)961.err()962.expect("trap");963assert_eq!(964format!("{}", e.source().expect("trap message is stored in source")),965"MyTrap"966);967e.downcast_ref::<MyTrap>()968.expect("downcast trap to concrete MyTrap type");969970Ok(())971}972}973974mod with_remapping {975use super::*;976use wasmtime::component::HasSelf;977978mod interfaces {979wasmtime::component::bindgen!({980interfaces: "981import imports: interface {982empty-error: func(a: f64) -> result<f64>;983}",984imports: { default: trappable },985});986}987988wasmtime::component::bindgen!({989inline: "990package inline:inline;991world result-playground {992import imports: interface {993empty-error: func(a: f64) -> result<f64>;994}995996export empty-error: func(a: f64) -> result<f64>;997}",998with: {999"imports": interfaces::imports,1000},1001imports: { default: trappable },1002});10031004#[test]1005fn run() -> Result<(), Error> {1006let engine = engine();1007let component = Component::new(1008&engine,1009r#"1010(component1011(import "imports" (instance $i1012(export "empty-error" (func (param "a" f64) (result (result f64))))1013))1014(core module $libc1015(memory (export "memory") 1)1016)1017(core instance $libc (instantiate $libc))1018(core module $m1019(import "" "core_empty_error" (func $f (param f64 i32)))1020(import "libc" "memory" (memory 0))1021(func (export "core_empty_error_export") (param f64) (result i32)1022(call $f (local.get 0) (i32.const 8))1023(i32.const 8)1024)1025)1026(core func $core_empty_error1027(canon lower (func $i "empty-error") (memory $libc "memory"))1028)1029(core instance $i (instantiate $m1030(with "" (instance (export "core_empty_error" (func $core_empty_error))))1031(with "libc" (instance $libc))1032))1033(func $f_empty_error1034(export "empty-error")1035(param "a" f64)1036(result (result f64))1037(canon lift (core func $i "core_empty_error_export") (memory $libc "memory"))1038)1039)1040"#,1041)?;10421043#[derive(Default)]1044struct MyImports {}10451046impl interfaces::imports::Host for MyImports {1047fn empty_error(&mut self, a: f64) -> Result<Result<f64, ()>, Error> {1048if a == 0.0 {1049Ok(Ok(a))1050} else if a == 1.0 {1051Ok(Err(()))1052} else {1053Err(anyhow!("empty_error: trap"))1054}1055}1056}10571058let mut linker = Linker::new(&engine);1059interfaces::imports::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;10601061let mut store = Store::new(&engine, MyImports::default());1062let results = ResultPlayground::instantiate(&mut store, &component, &linker)?;10631064assert_eq!(1065results1066.call_empty_error(&mut store, 0.0)1067.expect("no trap")1068.expect("no error returned"),10690.01070);10711072results1073.call_empty_error(&mut store, 1.0)1074.expect("no trap")1075.err()1076.expect("() error returned");10771078let e = results1079.call_empty_error(&mut store, 2.0)1080.err()1081.expect("trap");1082assert_eq!(1083format!("{}", e.source().expect("trap message is stored in source")),1084"empty_error: trap"1085);10861087Ok(())1088}1089}109010911092