Path: blob/main/tests/all/component_model/bindgen.rs
1691 views
#![cfg(not(miri))]12use super::engine;3use anyhow::Result;4use wasmtime::{5Config, Engine, Store,6component::{Component, Linker},7};89mod ownership;10mod results;1112mod no_imports {13use super::*;14use std::rc::Rc;1516wasmtime::component::bindgen!({17inline: "18package foo:foo;1920world no-imports {21export foo: interface {22foo: func();23}2425export bar: func();26}27",28});2930#[test]31fn run() -> Result<()> {32let engine = engine();3334let component = Component::new(35&engine,36r#"37(component38(core module $m39(func (export ""))40)41(core instance $i (instantiate $m))4243(func $f (export "bar") (canon lift (core func $i "")))4445(instance $i (export "foo" (func $f)))46(export "foo" (instance $i))47)48"#,49)?;5051let linker = Linker::new(&engine);52let mut store = Store::new(&engine, ());53let no_imports = NoImports::instantiate(&mut store, &component, &linker)?;54no_imports.call_bar(&mut store)?;55no_imports.foo().call_foo(&mut store)?;5657let linker = Linker::new(&engine);58let mut non_send_store = Store::new(&engine, Rc::new(()));59let no_imports = NoImports::instantiate(&mut non_send_store, &component, &linker)?;60no_imports.call_bar(&mut non_send_store)?;61no_imports.foo().call_foo(&mut non_send_store)?;62Ok(())63}64}6566mod no_imports_concurrent {67use super::*;68use futures::{69FutureExt,70stream::{FuturesUnordered, TryStreamExt},71};7273wasmtime::component::bindgen!({74inline: "75package foo:foo;7677world no-imports {78export foo: interface {79foo: async func();80}8182export bar: async func();83}84",85});8687#[tokio::test]88async fn run() -> Result<()> {89let mut config = Config::new();90config.wasm_component_model_async(true);91config.async_support(true);92let engine = &Engine::new(&config)?;9394let component = Component::new(95&engine,96r#"97(component98(core module $m99(import "" "task.return" (func $task-return))100(func (export "bar") (result i32)101call $task-return102i32.const 0103)104(func (export "callback") (param i32 i32 i32) (result i32) unreachable)105)106(core func $task-return (canon task.return))107(core instance $i (instantiate $m108(with "" (instance (export "task.return" (func $task-return))))109))110111(func $f (export "[async]bar")112(canon lift (core func $i "bar") async (callback (func $i "callback")))113)114115(instance $i (export "[async]foo" (func $f)))116(export "foo" (instance $i))117)118"#,119)?;120121let linker = Linker::new(&engine);122let mut store = Store::new(&engine, ());123let instance = linker.instantiate_async(&mut store, &component).await?;124let no_imports = NoImports::new(&mut store, &instance)?;125instance126.run_concurrent(&mut store, async move |accessor| {127let mut futures = FuturesUnordered::new();128futures.push(no_imports.call_bar(accessor).boxed());129futures.push(no_imports.foo().call_foo(accessor).boxed());130assert!(futures.try_next().await?.is_some());131assert!(futures.try_next().await?.is_some());132Ok(())133})134.await?135}136}137138mod one_import {139use super::*;140use wasmtime::component::HasSelf;141142wasmtime::component::bindgen!({143inline: "144package foo:foo;145146world one-import {147import foo: interface {148foo: func();149}150151export bar: func();152}153",154});155156#[test]157fn run() -> Result<()> {158let engine = engine();159160let component = Component::new(161&engine,162r#"163(component164(import "foo" (instance $i165(export "foo" (func))166))167(core module $m168(import "" "" (func))169(export "" (func 0))170)171(core func $f (canon lower (func $i "foo")))172(core instance $i (instantiate $m173(with "" (instance (export "" (func $f))))174))175176(func $f (export "bar") (canon lift (core func $i "")))177)178"#,179)?;180181#[derive(Default)]182struct MyImports {183hit: bool,184}185186impl foo::Host for MyImports {187fn foo(&mut self) {188self.hit = true;189}190}191192let mut linker = Linker::new(&engine);193foo::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;194let mut store = Store::new(&engine, MyImports::default());195let one_import = OneImport::instantiate(&mut store, &component, &linker)?;196one_import.call_bar(&mut store)?;197assert!(store.data().hit);198Ok(())199}200}201202mod one_import_concurrent {203use super::*;204use wasmtime::component::{Accessor, HasData};205206wasmtime::component::bindgen!({207inline: "208package foo:foo;209210world no-imports {211import foo: interface {212foo: async func();213}214215export bar: async func();216}217",218});219220#[tokio::test]221async fn run() -> Result<()> {222let mut config = Config::new();223config.wasm_component_model_async(true);224config.async_support(true);225let engine = &Engine::new(&config)?;226227let component = Component::new(228&engine,229r#"230(component231(import "foo" (instance $foo-instance232(export "[async]foo" (func))233))234(core module $libc235(memory (export "memory") 1)236)237(core instance $libc-instance (instantiate $libc))238(core module $m239(import "" "foo" (func $foo (param) (result i32)))240(import "" "task.return" (func $task-return))241(func (export "bar") (result i32)242call $foo243drop244call $task-return245i32.const 0246)247(func (export "callback") (param i32 i32 i32) (result i32) unreachable)248)249(core func $foo (canon lower (func $foo-instance "[async]foo") async (memory $libc-instance "memory")))250(core func $task-return (canon task.return))251(core instance $i (instantiate $m252(with "" (instance253(export "task.return" (func $task-return))254(export "foo" (func $foo))255))256))257258(func $f (export "[async]bar")259(canon lift (core func $i "bar") async (callback (func $i "callback")))260)261262(instance $i (export "[async]foo" (func $f)))263(export "foo" (instance $i))264)265"#,266)?;267268#[derive(Default)]269struct MyImports {270hit: bool,271}272273impl HasData for MyImports {274type Data<'a> = &'a mut MyImports;275}276277impl foo::HostWithStore for MyImports {278async fn foo<T>(accessor: &Accessor<T, Self>) {279accessor.with(|mut view| view.get().hit = true);280}281}282283impl foo::Host for MyImports {}284285let mut linker = Linker::new(&engine);286foo::add_to_linker::<_, MyImports>(&mut linker, |x| x)?;287let mut store = Store::new(&engine, MyImports::default());288let instance = linker.instantiate_async(&mut store, &component).await?;289let no_imports = NoImports::new(&mut store, &instance)?;290instance291.run_concurrent(&mut store, async move |accessor| {292no_imports.call_bar(accessor).await293})294.await??;295assert!(store.data().hit);296Ok(())297}298}299300mod resources_at_world_level {301use super::*;302use wasmtime::component::{HasSelf, Resource};303304wasmtime::component::bindgen!({305inline: "306package foo:foo;307308world resources {309resource x {310constructor();311}312313export y: func(x: x);314}315",316});317318#[test]319fn run() -> Result<()> {320let engine = engine();321322let component = Component::new(323&engine,324r#"325(component326(import "x" (type $x (sub resource)))327(import "[constructor]x" (func $ctor (result (own $x))))328329(core func $dtor (canon resource.drop $x))330(core func $ctor (canon lower (func $ctor)))331332(core module $m333(import "" "ctor" (func $ctor (result i32)))334(import "" "dtor" (func $dtor (param i32)))335336(func (export "x") (param i32)337(call $dtor (local.get 0))338(call $dtor (call $ctor))339)340)341(core instance $i (instantiate $m342(with "" (instance343(export "ctor" (func $ctor))344(export "dtor" (func $dtor))345))346))347(func (export "y") (param "x" (own $x))348(canon lift (core func $i "x")))349)350"#,351)?;352353#[derive(Default)]354struct MyImports {355ctor_hit: bool,356drops: usize,357}358359impl HostX for MyImports {360fn new(&mut self) -> Resource<X> {361self.ctor_hit = true;362Resource::new_own(80)363}364365fn drop(&mut self, val: Resource<X>) -> Result<()> {366match self.drops {3670 => assert_eq!(val.rep(), 40),3681 => assert_eq!(val.rep(), 80),369_ => unreachable!(),370}371self.drops += 1;372Ok(())373}374}375376impl ResourcesImports for MyImports {}377378let mut linker = Linker::new(&engine);379Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;380let mut store = Store::new(&engine, MyImports::default());381let one_import = Resources::instantiate(&mut store, &component, &linker)?;382one_import.call_y(&mut store, Resource::new_own(40))?;383assert!(store.data().ctor_hit);384assert_eq!(store.data().drops, 2);385Ok(())386}387}388389mod resources_at_interface_level {390use super::*;391use wasmtime::component::{HasSelf, Resource};392393wasmtime::component::bindgen!({394inline: "395package foo:foo;396397interface def {398resource x {399constructor();400}401}402403interface user {404use def.{x};405406y: func(x: x);407}408409world resources {410export user;411}412",413});414415#[test]416fn run() -> Result<()> {417let engine = engine();418419let component = Component::new(420&engine,421r#"422(component423(import (interface "foo:foo/def") (instance $i424(export "x" (type $x (sub resource)))425(export "[constructor]x" (func (result (own $x))))426))427(alias export $i "x" (type $x))428(core func $dtor (canon resource.drop $x))429(core func $ctor (canon lower (func $i "[constructor]x")))430431(core module $m432(import "" "ctor" (func $ctor (result i32)))433(import "" "dtor" (func $dtor (param i32)))434435(func (export "x") (param i32)436(call $dtor (local.get 0))437(call $dtor (call $ctor))438)439)440(core instance $i (instantiate $m441(with "" (instance442(export "ctor" (func $ctor))443(export "dtor" (func $dtor))444))445))446(func $y (param "x" (own $x))447(canon lift (core func $i "x")))448449(instance (export (interface "foo:foo/user"))450(export "y" (func $y))451)452)453"#,454)?;455456#[derive(Default)]457struct MyImports {458ctor_hit: bool,459drops: usize,460}461462use foo::foo::def::X;463464impl foo::foo::def::HostX for MyImports {465fn new(&mut self) -> Resource<X> {466self.ctor_hit = true;467Resource::new_own(80)468}469470fn drop(&mut self, val: Resource<X>) -> Result<()> {471match self.drops {4720 => assert_eq!(val.rep(), 40),4731 => assert_eq!(val.rep(), 80),474_ => unreachable!(),475}476self.drops += 1;477Ok(())478}479}480481impl foo::foo::def::Host for MyImports {}482483let mut linker = Linker::new(&engine);484Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;485let mut store = Store::new(&engine, MyImports::default());486let one_import = Resources::instantiate(&mut store, &component, &linker)?;487one_import488.foo_foo_user()489.call_y(&mut store, Resource::new_own(40))?;490assert!(store.data().ctor_hit);491assert_eq!(store.data().drops, 2);492Ok(())493}494}495496mod async_config {497use super::*;498499wasmtime::component::bindgen!({500inline: "501package foo:foo;502503world t1 {504import foo: interface {505foo: func();506}507import x: func();508import y: func();509export z: func();510}511",512imports: { default: async },513exports: { default: async },514});515516#[expect(dead_code, reason = "just here for bindings")]517struct T;518519impl T1Imports for T {520async fn x(&mut self) {}521522async fn y(&mut self) {}523}524525async fn _test_t1(t1: &T1, store: &mut Store<()>) {526let _ = t1.call_z(&mut *store).await;527}528529wasmtime::component::bindgen!({530inline: "531package foo:foo;532533world t2 {534import x: func();535import y: func();536export z: func();537}538",539imports: {540"x": tracing,541default: async,542},543exports: { default: async },544});545546impl T2Imports for T {547fn x(&mut self) {}548549async fn y(&mut self) {}550}551552async fn _test_t2(t2: &T2, store: &mut Store<()>) {553let _ = t2.call_z(&mut *store).await;554}555556wasmtime::component::bindgen!({557inline: "558package foo:foo;559560world t3 {561import x: func();562import y: func();563export z: func();564}565",566imports: { "x": async },567exports: { default: async },568});569570impl T3Imports for T {571async fn x(&mut self) {}572573fn y(&mut self) {}574}575576async fn _test_t3(t3: &T3, store: &mut Store<()>) {577let _ = t3.call_z(&mut *store).await;578}579}580581mod exported_resources {582use super::*;583use std::mem;584use wasmtime::component::{HasSelf, Resource};585586wasmtime::component::bindgen!({587inline: "588package foo:foo;589590interface a {591resource x {592constructor();593}594}595596world resources {597export b: interface {598use a.{x as y};599600resource x {601constructor(y: y);602foo: func() -> u32;603}604}605606resource x;607608export f: func(x1: x, x2: x) -> x;609}610",611});612613#[derive(Default)]614struct MyImports {615hostcalls: Vec<Hostcall>,616next_a_x: u32,617}618619#[derive(PartialEq, Debug)]620enum Hostcall {621DropRootX(u32),622DropAX(u32),623NewA,624}625626use foo::foo::a;627628impl ResourcesImports for MyImports {}629630impl HostX for MyImports {631fn drop(&mut self, val: Resource<X>) -> Result<()> {632self.hostcalls.push(Hostcall::DropRootX(val.rep()));633Ok(())634}635}636637impl a::HostX for MyImports {638fn new(&mut self) -> Resource<a::X> {639let rep = self.next_a_x;640self.next_a_x += 1;641self.hostcalls.push(Hostcall::NewA);642Resource::new_own(rep)643}644645fn drop(&mut self, val: Resource<a::X>) -> Result<()> {646self.hostcalls.push(Hostcall::DropAX(val.rep()));647Ok(())648}649}650651impl foo::foo::a::Host for MyImports {}652653#[test]654fn run() -> Result<()> {655let engine = engine();656657let component = Component::new(658&engine,659r#"660(component661;; setup the `foo:foo/a` import662(import (interface "foo:foo/a") (instance $a663(export "x" (type $x (sub resource)))664(export "[constructor]x" (func (result (own $x))))665))666(alias export $a "x" (type $a-x))667(core func $a-x-drop (canon resource.drop $a-x))668(core func $a-x-ctor (canon lower (func $a "[constructor]x")))669670;; setup the root import of the `x` resource671(import "x" (type $x (sub resource)))672(core func $root-x-dtor (canon resource.drop $x))673674;; setup and declare the `x` resource for the `b` export.675(core module $indirect-dtor676(func (export "b-x-dtor") (param i32)677local.get 0678i32.const 0679call_indirect (param i32)680)681(table (export "$imports") 1 1 funcref)682)683(core instance $indirect-dtor (instantiate $indirect-dtor))684(type $b-x (resource (rep i32) (dtor (func $indirect-dtor "b-x-dtor"))))685(core func $b-x-drop (canon resource.drop $b-x))686(core func $b-x-rep (canon resource.rep $b-x))687(core func $b-x-new (canon resource.new $b-x))688689;; main module implementation690(core module $main691(import "foo:foo/a" "[constructor]x" (func $a-x-ctor (result i32)))692(import "foo:foo/a" "[resource-drop]x" (func $a-x-dtor (param i32)))693(import "$root" "[resource-drop]x" (func $x-dtor (param i32)))694(import "[export]b" "[resource-drop]x" (func $b-x-dtor (param i32)))695(import "[export]b" "[resource-new]x" (func $b-x-new (param i32) (result i32)))696(import "[export]b" "[resource-rep]x" (func $b-x-rep (param i32) (result i32)))697(func (export "b#[constructor]x") (param i32) (result i32)698(call $a-x-dtor (local.get 0))699(call $b-x-new (call $a-x-ctor))700)701(func (export "b#[method]x.foo") (param i32) (result i32)702local.get 0)703(func (export "b#[dtor]x") (param i32)704(call $a-x-dtor (local.get 0))705)706(func (export "f") (param i32 i32) (result i32)707(call $x-dtor (local.get 0))708local.get 1709)710)711(core instance $main (instantiate $main712(with "foo:foo/a" (instance713(export "[resource-drop]x" (func $a-x-drop))714(export "[constructor]x" (func $a-x-ctor))715))716(with "$root" (instance717(export "[resource-drop]x" (func $root-x-dtor))718))719(with "[export]b" (instance720(export "[resource-drop]x" (func $b-x-drop))721(export "[resource-rep]x" (func $b-x-rep))722(export "[resource-new]x" (func $b-x-new))723))724))725726;; fill in `$indirect-dtor`'s table with the actual destructor definition727;; now that it's available.728(core module $fixup729(import "" "b-x-dtor" (func $b-x-dtor (param i32)))730(import "" "$imports" (table 1 1 funcref))731(elem (i32.const 0) func $b-x-dtor)732)733(core instance (instantiate $fixup734(with "" (instance735(export "$imports" (table 0 "$imports"))736(export "b-x-dtor" (func $main "b#[dtor]x"))737))738))739740;; Create the `b` export through a subcomponent instantiation.741(func $b-x-ctor (param "y" (own $a-x)) (result (own $b-x))742(canon lift (core func $main "b#[constructor]x")))743(func $b-x-foo (param "self" (borrow $b-x)) (result u32)744(canon lift (core func $main "b#[method]x.foo")))745(component $b746(import "a-x" (type $y (sub resource)))747(import "b-x" (type $x' (sub resource)))748(import "ctor" (func $ctor (param "y" (own $y)) (result (own $x'))))749(import "foo" (func $foo (param "self" (borrow $x')) (result u32)))750(export $x "x" (type $x'))751(export "[constructor]x"752(func $ctor)753(func (param "y" (own $y)) (result (own $x))))754(export "[method]x.foo"755(func $foo)756(func (param "self" (borrow $x)) (result u32)))757)758(instance (export "b") (instantiate $b759(with "ctor" (func $b-x-ctor))760(with "foo" (func $b-x-foo))761(with "a-x" (type 0 "x"))762(with "b-x" (type $b-x))763))764765;; Create the `f` export which is a bare function766(func (export "f") (param "x1" (own $x)) (param "x2" (own $x)) (result (own $x))767(canon lift (core func $main "f")))768)769"#,770)?;771772let mut linker = Linker::new(&engine);773Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;774let mut store = Store::new(&engine, MyImports::default());775let i = Resources::instantiate(&mut store, &component, &linker)?;776777// call the root export `f` twice778let ret = i.call_f(&mut store, Resource::new_own(1), Resource::new_own(2))?;779assert_eq!(ret.rep(), 2);780assert_eq!(781mem::take(&mut store.data_mut().hostcalls),782[Hostcall::DropRootX(1)]783);784let ret = i.call_f(&mut store, Resource::new_own(3), Resource::new_own(4))?;785assert_eq!(ret.rep(), 4);786assert_eq!(787mem::take(&mut store.data_mut().hostcalls),788[Hostcall::DropRootX(3)]789);790791// interact with the `b` export792let b = i.b();793let b_x = b.x().call_constructor(&mut store, Resource::new_own(5))?;794assert_eq!(795mem::take(&mut store.data_mut().hostcalls),796[Hostcall::DropAX(5), Hostcall::NewA]797);798b.x().call_foo(&mut store, b_x)?;799assert_eq!(mem::take(&mut store.data_mut().hostcalls), []);800b_x.resource_drop(&mut store)?;801assert_eq!(802mem::take(&mut store.data_mut().hostcalls),803[Hostcall::DropAX(0)],804);805Ok(())806}807}808809mod unstable_import {810use super::*;811use wasmtime::component::HasSelf;812813wasmtime::component::bindgen!({814inline: "815package foo:foo;816817@unstable(feature = experimental-interface)818interface my-interface {819@unstable(feature = experimental-function)820my-function: func();821}822823world my-world {824@unstable(feature = experimental-import)825import my-interface;826827export bar: func();828}829",830});831832#[test]833fn run() -> Result<()> {834// In the example above, all features are required for `my-function` to be imported:835assert_success(836LinkOptions::default()837.experimental_interface(true)838.experimental_import(true)839.experimental_function(true),840);841842// And every other incomplete combination should fail:843assert_failure(&LinkOptions::default());844assert_failure(LinkOptions::default().experimental_function(true));845assert_failure(LinkOptions::default().experimental_interface(true));846assert_failure(847LinkOptions::default()848.experimental_interface(true)849.experimental_function(true),850);851assert_failure(852LinkOptions::default()853.experimental_interface(true)854.experimental_import(true),855);856assert_failure(LinkOptions::default().experimental_import(true));857assert_failure(858LinkOptions::default()859.experimental_import(true)860.experimental_function(true),861);862863Ok(())864}865866fn assert_success(link_options: &LinkOptions) {867run_with_options(link_options).unwrap();868}869fn assert_failure(link_options: &LinkOptions) {870let err = run_with_options(link_options).unwrap_err().to_string();871assert_eq!(872err,873"component imports instance `foo:foo/my-interface`, but a matching implementation was not found in the linker"874);875}876877fn run_with_options(link_options: &LinkOptions) -> Result<()> {878let engine = engine();879880let component = Component::new(881&engine,882r#"883(component884(import "foo:foo/my-interface" (instance $i885(export "my-function" (func))886))887(core module $m888(import "" "" (func))889(export "" (func 0))890)891(core func $f (canon lower (func $i "my-function")))892(core instance $r (instantiate $m893(with "" (instance (export "" (func $f))))894))895896(func $f (export "bar") (canon lift (core func $r "")))897)898"#,899)?;900901#[derive(Default)]902struct MyHost;903904impl foo::foo::my_interface::Host for MyHost {905fn my_function(&mut self) {}906}907908let mut linker = Linker::new(&engine);909MyWorld::add_to_linker::<_, HasSelf<_>>(&mut linker, link_options, |h| h)?;910let mut store = Store::new(&engine, MyHost::default());911let one_import = MyWorld::instantiate(&mut store, &component, &linker)?;912one_import.call_bar(&mut store)?;913Ok(())914}915}916917918