Path: blob/main/tests/all/component_model/resources.rs
3067 views
#![cfg(not(miri))]12use wasmtime::Result;3use wasmtime::component::*;4use wasmtime::{Store, Trap};56#[test]7fn host_resource_types() -> Result<()> {8let engine = super::engine();9let c = Component::new(10&engine,11r#"12(component13(import "t" (type $t (sub resource)))14(import "u" (type $u (sub resource)))1516(export "t1" (type $t))17(export "t2" (type $t))18(export "u1" (type $u))19(export "u2" (type $u))2021(component $c22(import "r" (type $r (sub resource)))23(export "r1" (type $r))24)25(instance $i1 (instantiate $c (with "r" (type $t))))26(instance $i2 (instantiate $c (with "r" (type $t))))27(export "t3" (type $i1 "r1"))28(export "t4" (type $i2 "r1"))29)30"#,31)?;3233struct T;34struct U;35assert!(ResourceType::host::<T>() != ResourceType::host::<U>());3637let mut store = Store::new(&engine, ());38let mut linker = Linker::new(&engine);39linker40.root()41.resource("t", ResourceType::host::<T>(), |_, _| Ok(()))?;42linker43.root()44.resource("u", ResourceType::host::<U>(), |_, _| Ok(()))?;45let i = linker.instantiate(&mut store, &c)?;46let t1 = i.get_resource(&mut store, "t1").unwrap();47let t2 = i.get_resource(&mut store, "t2").unwrap();48let t3 = i.get_resource(&mut store, "t3").unwrap();49let t4 = i.get_resource(&mut store, "t4").unwrap();50let u1 = i.get_resource(&mut store, "u1").unwrap();51let u2 = i.get_resource(&mut store, "u2").unwrap();5253assert_eq!(t1, ResourceType::host::<T>());54assert_eq!(t2, ResourceType::host::<T>());55assert_eq!(t3, ResourceType::host::<T>());56assert_eq!(t4, ResourceType::host::<T>());57assert_eq!(u1, ResourceType::host::<U>());58assert_eq!(u2, ResourceType::host::<U>());59Ok(())60}6162#[test]63fn guest_resource_types() -> Result<()> {64let engine = super::engine();65let c = Component::new(66&engine,67r#"68(component69(type $t (resource (rep i32)))70(type $u (resource (rep i32)))7172(export "t1" (type $t))73(export "t2" (type $t))74(export "u1" (type $u))75(export "u2" (type $u))7677(component $c78(import "r" (type $r (sub resource)))79(export "r1" (type $r))80)81(instance $i1 (instantiate $c (with "r" (type $t))))82(instance $i2 (instantiate $c (with "r" (type $t))))83(export "t3" (type $i1 "r1"))84(export "t4" (type $i2 "r1"))85)86"#,87)?;8889let mut store = Store::new(&engine, ());90let linker = Linker::new(&engine);91let i = linker.instantiate(&mut store, &c)?;92let t1 = i.get_resource(&mut store, "t1").unwrap();93let t2 = i.get_resource(&mut store, "t2").unwrap();94let t3 = i.get_resource(&mut store, "t3").unwrap();95let t4 = i.get_resource(&mut store, "t4").unwrap();96let u1 = i.get_resource(&mut store, "u1").unwrap();97let u2 = i.get_resource(&mut store, "u2").unwrap();9899assert_ne!(t1, u1);100assert_eq!(t1, t2);101assert_eq!(t1, t3);102assert_eq!(t1, t4);103assert_eq!(u1, u2);104Ok(())105}106107#[test]108fn resource_any() -> Result<()> {109let engine = super::engine();110let c = Component::new(111&engine,112r#"113(component114(type $t' (resource (rep i32)))115(type $u' (resource (rep i32)))116117(export $t "t" (type $t'))118(export $u "u" (type $u'))119120(core func $t_ctor (canon resource.new $t))121(core func $u_ctor (canon resource.new $u))122123(func (export "[constructor]t") (param "x" u32) (result (own $t))124(canon lift (core func $t_ctor)))125(func (export "[constructor]u") (param "x" u32) (result (own $u))126(canon lift (core func $u_ctor)))127128(core func $t_drop (canon resource.drop $t))129(core func $u_drop (canon resource.drop $u))130131(func (export "drop-t") (param "x" (own $t))132(canon lift (core func $t_drop)))133(func (export "drop-u") (param "x" (own $u))134(canon lift (core func $u_drop)))135)136"#,137)?;138139let linker = Linker::new(&engine);140{141let mut store = Store::new(&engine, ());142let i = linker.instantiate(&mut store, &c)?;143let t = i.get_resource(&mut store, "t").unwrap();144let u = i.get_resource(&mut store, "u").unwrap();145146assert_ne!(t, u);147148let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;149let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;150let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;151let u_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-u")?;152153let (t1,) = t_ctor.call(&mut store, (100,))?;154let (t2,) = t_ctor.call(&mut store, (200,))?;155let (u1,) = u_ctor.call(&mut store, (300,))?;156let (u2,) = u_ctor.call(&mut store, (400,))?;157158assert_eq!(t1.ty(), t);159assert_eq!(t2.ty(), t);160assert_eq!(u1.ty(), u);161assert_eq!(u2.ty(), u);162163u_dtor.call(&mut store, (u2,))?;164165u_dtor.call(&mut store, (u1,))?;166167t_dtor.call(&mut store, (t1,))?;168169t_dtor.call(&mut store, (t2,))?;170}171172{173let mut store = Store::new(&engine, ());174let i = linker.instantiate(&mut store, &c)?;175let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;176let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;177let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;178179// `t` is placed at host index 0180let (t,) = t_ctor.call(&mut store, (100,))?;181t_dtor.call(&mut store, (t,))?;182183// `u` is also placed at host index 0 since `t` was deallocated184let (_u,) = u_ctor.call(&mut store, (100,))?;185186// reuse of `t` should fail, despite it pointing to a valid resource187assert_eq!(188t_dtor.call(&mut store, (t,)).unwrap_err().to_string(),189"host-owned resource is being used with the wrong type"190);191}192193Ok(())194}195196#[test]197fn mismatch_intrinsics() -> Result<()> {198let engine = super::engine();199let c = Component::new(200&engine,201r#"202(component203(type $t' (resource (rep i32)))204(type $u' (resource (rep i32)))205206(export $t "t" (type $t'))207(export $u "u" (type $u'))208209;; note the mismatch where this is an intrinsic for `u` but210;; we're typing it as `t`211(core func $t_ctor (canon resource.new $u))212213(func (export "ctor") (param "x" u32) (result (own $t))214(canon lift (core func $t_ctor)))215)216"#,217)?;218219let mut store = Store::new(&engine, ());220let i = Linker::new(&engine).instantiate(&mut store, &c)?;221let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;222assert_eq!(223ctor.call(&mut store, (100,)).unwrap_err().to_string(),224"handle index 1 used with the wrong type, expected guest-defined \225resource but found a different guest-defined resource",226);227228Ok(())229}230231#[test]232fn mismatch_resource_types() -> Result<()> {233let engine = super::engine();234let c = Component::new(235&engine,236r#"237(component238(type $t' (resource (rep i32)))239(type $u' (resource (rep i32)))240241(export $t "t" (type $t'))242(export $u "u" (type $u'))243244(core func $t_ctor (canon resource.new $t))245(func (export "ctor") (param "x" u32) (result (own $t))246(canon lift (core func $t_ctor)))247248(core func $u_dtor (canon resource.drop $u))249(func (export "dtor") (param "x" (own $u))250(canon lift (core func $u_dtor)))251)252"#,253)?;254255let mut store = Store::new(&engine, ());256let i = Linker::new(&engine).instantiate(&mut store, &c)?;257let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;258let dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor")?;259260let (t,) = ctor.call(&mut store, (100,))?;261assert_eq!(262dtor.call(&mut store, (t,)).unwrap_err().to_string(),263"mismatched resource types"264);265266Ok(())267}268269#[test]270fn drop_in_different_places() -> Result<()> {271let engine = super::engine();272let c = Component::new(273&engine,274r#"275(component276(type $t' (resource (rep i32)))277278(export $t "t" (type $t'))279280(core func $ctor (canon resource.new $t))281(func (export "ctor") (param "x" u32) (result (own $t))282(canon lift (core func $ctor)))283284(core func $dtor (canon resource.drop $t))285(func (export "dtor1") (param "x" (own $t))286(canon lift (core func $dtor)))287288(component $c289(import "t" (type $t (sub resource)))290(core func $dtor (canon resource.drop $t))291(func (export "dtor") (param "x" (own $t))292(canon lift (core func $dtor)))293)294(instance $i1 (instantiate $c (with "t" (type $t))))295(instance $i2 (instantiate $c (with "t" (type $t))))296297(export "dtor2" (func $i1 "dtor"))298(export "dtor3" (func $i2 "dtor"))299)300"#,301)?;302303let mut store = Store::new(&engine, ());304let i = Linker::new(&engine).instantiate(&mut store, &c)?;305let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;306let dtor1 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor1")?;307let dtor2 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor2")?;308let dtor3 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor3")?;309310let (t,) = ctor.call(&mut store, (100,))?;311dtor1.call(&mut store, (t,))?;312313let (t,) = ctor.call(&mut store, (200,))?;314dtor2.call(&mut store, (t,))?;315316let (t,) = ctor.call(&mut store, (300,))?;317dtor3.call(&mut store, (t,))?;318319Ok(())320}321322#[test]323fn drop_guest_twice() -> Result<()> {324let engine = super::engine();325let c = Component::new(326&engine,327r#"328(component329(type $t' (resource (rep i32)))330331(export $t "t" (type $t'))332333(core func $ctor (canon resource.new $t))334(func (export "ctor") (param "x" u32) (result (own $t))335(canon lift (core func $ctor)))336337(core func $dtor (canon resource.drop $t))338(func (export "dtor") (param "x" (own $t))339(canon lift (core func $dtor)))340)341"#,342)?;343344let mut store = Store::new(&engine, ());345let i = Linker::new(&engine).instantiate(&mut store, &c)?;346let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;347let dtor = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "dtor")?;348349let (t,) = ctor.call(&mut store, (100,))?;350dtor.call(&mut store, (&t,))?;351352assert_eq!(353dtor.call(&mut store, (&t,)).unwrap_err().to_string(),354"unknown handle index 1"355);356357Ok(())358}359360#[test]361fn drop_host_twice() -> Result<()> {362let engine = super::engine();363let c = Component::new(364&engine,365r#"366(component367(import "t" (type $t (sub resource)))368369(core func $dtor (canon resource.drop $t))370(func (export "dtor") (param "x" (own $t))371(canon lift (core func $dtor)))372)373"#,374)?;375376struct MyType;377378let mut store = Store::new(&engine, ());379let mut linker = Linker::new(&engine);380linker381.root()382.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;383let i = linker.instantiate(&mut store, &c)?;384let dtor = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "dtor")?;385386let t = Resource::new_own(100);387dtor.call(&mut store, (&t,))?;388389assert_eq!(390dtor.call(&mut store, (&t,)).unwrap_err().to_string(),391"host resource already consumed"392);393394Ok(())395}396397#[test]398fn manually_destroy() -> Result<()> {399let engine = super::engine();400let c = Component::new(401&engine,402r#"403(component404(import "t1" (type $t1 (sub resource)))405406(core module $m407(global $drops (mut i32) i32.const 0)408(global $last-drop (mut i32) i32.const 0)409410(func (export "dtor") (param i32)411(global.set $drops (i32.add (global.get $drops) (i32.const 1)))412(global.set $last-drop (local.get 0))413)414(func (export "drops") (result i32) global.get $drops)415(func (export "last-drop") (result i32) global.get $last-drop)416(func (export "pass") (param i32) (result i32) local.get 0)417)418(core instance $i (instantiate $m))419(type $t2' (resource (rep i32) (dtor (func $i "dtor"))))420(export $t2 "t2" (type $t2'))421(core func $ctor (canon resource.new $t2))422(func (export "[constructor]t2") (param "rep" u32) (result (own $t2))423(canon lift (core func $ctor)))424(func (export "[static]t2.drops") (result u32)425(canon lift (core func $i "drops")))426(func (export "[static]t2.last-drop") (result u32)427(canon lift (core func $i "last-drop")))428429(func (export "t1-pass") (param "t" (own $t1)) (result (own $t1))430(canon lift (core func $i "pass")))431)432"#,433)?;434435struct MyType;436437#[derive(Default)]438struct Data {439drops: u32,440last_drop: Option<u32>,441}442443let mut store = Store::new(&engine, Data::default());444let mut linker = Linker::new(&engine);445linker446.root()447.resource("t1", ResourceType::host::<MyType>(), |mut cx, rep| {448let data: &mut Data = cx.data_mut();449data.drops += 1;450data.last_drop = Some(rep);451Ok(())452})?;453let i = linker.instantiate(&mut store, &c)?;454let t2_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t2")?;455let t2_drops = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.drops")?;456let t2_last_drop = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.last-drop")?;457let t1_pass = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "t1-pass")?;458459// Host resources can be destroyed through `resource_drop`460let t1 = Resource::new_own(100);461let (t1,) = t1_pass.call(&mut store, (t1,))?;462assert_eq!(store.data().drops, 0);463assert_eq!(store.data().last_drop, None);464t1.resource_drop(&mut store)?;465assert_eq!(store.data().drops, 1);466assert_eq!(store.data().last_drop, Some(100));467468// Guest resources can be destroyed through `resource_drop`469let (t2,) = t2_ctor.call(&mut store, (200,))?;470assert_eq!(t2_drops.call(&mut store, ())?, (0,));471assert_eq!(t2_last_drop.call(&mut store, ())?, (0,));472t2.resource_drop(&mut store)?;473assert_eq!(t2_drops.call(&mut store, ())?, (1,));474assert_eq!(t2_last_drop.call(&mut store, ())?, (200,));475476// Wires weren't crossed to drop more resources477assert_eq!(store.data().drops, 1);478assert_eq!(store.data().last_drop, Some(100));479480Ok(())481}482483#[test]484fn dynamic_type() -> Result<()> {485let engine = super::engine();486let c = Component::new(487&engine,488r#"489(component490(import "t1" (type $t1 (sub resource)))491(type $t2' (resource (rep i32)))492(export $t2 "t2" (type $t2'))493(core func $f (canon resource.drop $t2))494495(func (export "a") (param "x" (own $t1))496(canon lift (core func $f)))497(func (export "b") (param "x" (tuple (own $t2)))498(canon lift (core func $f)))499)500"#,501)?;502503struct MyType;504505let mut store = Store::new(&engine, ());506let mut linker = Linker::new(&engine);507linker508.root()509.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;510let i = linker.instantiate(&mut store, &c)?;511512let a = i.get_func(&mut store, "a").unwrap();513let b = i.get_func(&mut store, "b").unwrap();514let t2 = i.get_resource(&mut store, "t2").unwrap();515516let aty = a.ty(&store);517assert_eq!(518aty.params().next().unwrap(),519("x", Type::Own(ResourceType::host::<MyType>()))520);521let bty = b.ty(&store);522match bty.params().next().unwrap() {523(name, Type::Tuple(t)) => {524assert_eq!(name, "x");525assert_eq!(t.types().len(), 1);526let t0 = t.types().next().unwrap();527assert_eq!(t0, Type::Own(t2));528}529_ => unreachable!(),530}531532Ok(())533}534535#[test]536fn dynamic_val() -> Result<()> {537let engine = super::engine();538let c = Component::new(539&engine,540r#"541(component542(import "t1" (type $t1 (sub resource)))543(type $t2' (resource (rep i32)))544(export $t2 "t2" (type $t2'))545(core func $f (canon resource.new $t2))546547(core module $m548(func (export "pass") (param i32) (result i32)549(local.get 0)))550(core instance $i (instantiate $m))551552(func (export "a") (param "x" (own $t1)) (result (own $t1))553(canon lift (core func $i "pass")))554(func (export "b") (param "x" u32) (result (own $t2))555(canon lift (core func $f)))556)557"#,558)?;559560struct MyType;561562let mut store = Store::new(&engine, ());563let mut linker = Linker::new(&engine);564linker565.root()566.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;567let i_pre = linker.instantiate_pre(&c)?;568let i = i_pre.instantiate(&mut store)?;569570let a = i.get_func(&mut store, "a").unwrap();571let a_typed = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "a")?;572let a_typed_result =573i.get_typed_func::<(Resource<MyType>,), (Resource<MyType>,)>(&mut store, "a")?;574let b = i.get_func(&mut store, "b").unwrap();575let t2 = i.get_resource(&mut store, "t2").unwrap();576577let t1 = Resource::new_own(100);578let (t1,) = a_typed.call(&mut store, (t1,))?;579assert_eq!(t1.ty(), ResourceType::host::<MyType>());580581let mut results = [Val::Bool(false)];582a.call(&mut store, &[Val::Resource(t1)], &mut results)?;583match &results[0] {584Val::Resource(resource) => {585assert_eq!(resource.ty(), ResourceType::host::<MyType>());586assert!(resource.owned());587588let resource = resource.try_into_resource::<MyType>(&mut store)?;589assert_eq!(resource.rep(), 100);590assert!(resource.owned());591592let resource = resource.try_into_resource_any(&mut store)?;593assert_eq!(resource.ty(), ResourceType::host::<MyType>());594assert!(resource.owned());595}596_ => unreachable!(),597}598599let t1_any = Resource::<MyType>::new_own(100).try_into_resource_any(&mut store)?;600let mut results = [Val::Bool(false)];601a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;602match &results[0] {603Val::Resource(resource) => {604assert_eq!(resource.ty(), ResourceType::host::<MyType>());605assert!(resource.owned());606607let resource = resource.try_into_resource::<MyType>(&mut store)?;608assert_eq!(resource.rep(), 100);609assert!(resource.owned());610611let resource = resource.try_into_resource_any(&mut store)?;612assert_eq!(resource.ty(), ResourceType::host::<MyType>());613assert!(resource.owned());614}615_ => unreachable!(),616}617618let t1 = Resource::<MyType>::new_own(100)619.try_into_resource_any(&mut store)?620.try_into_resource(&mut store)?;621let (t1,) = a_typed_result.call(&mut store, (t1,))?;622assert_eq!(t1.rep(), 100);623assert!(t1.owned());624625let t1_any = t1626.try_into_resource_any(&mut store)?627.try_into_resource::<MyType>(&mut store)?628.try_into_resource_any(&mut store)?;629let mut results = [Val::Bool(false)];630a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;631match &results[0] {632Val::Resource(resource) => {633assert_eq!(resource.ty(), ResourceType::host::<MyType>());634assert!(resource.owned());635636let resource = resource.try_into_resource::<MyType>(&mut store)?;637assert_eq!(resource.rep(), 100);638assert!(resource.owned());639640let resource = resource.try_into_resource_any(&mut store)?;641assert_eq!(resource.ty(), ResourceType::host::<MyType>());642assert!(resource.owned());643}644_ => unreachable!(),645}646647b.call(&mut store, &[Val::U32(200)], &mut results)?;648match &results[0] {649Val::Resource(resource) => {650assert_eq!(resource.ty(), t2);651}652_ => unreachable!(),653}654655Ok(())656}657658#[test]659fn cannot_reenter_during_import() -> Result<()> {660let engine = super::engine();661let c = Component::new(662&engine,663r#"664(component665(import "f" (func $f))666667(core func $f (canon lower (func $f)))668669(core module $m670(import "" "f" (func $f))671(func (export "call") call $f)672(func (export "dtor") (param i32) unreachable)673)674675(core instance $i (instantiate $m676(with "" (instance677(export "f" (func $f))678))679))680681(type $t2' (resource (rep i32) (dtor (func $i "dtor"))))682(export $t2 "t" (type $t2'))683(core func $ctor (canon resource.new $t2))684(func (export "ctor") (param "x" u32) (result (own $t2))685(canon lift (core func $ctor)))686687(func (export "call") (canon lift (core func $i "call")))688)689"#,690)?;691692let mut store = Store::new(&engine, None);693let mut linker = Linker::new(&engine);694linker.root().func_wrap("f", |mut cx, ()| {695let data: &mut Option<ResourceAny> = cx.data_mut();696let err = data.take().unwrap().resource_drop(cx).unwrap_err();697assert_eq!(698err.downcast_ref(),699Some(&Trap::CannotEnterComponent),700"bad error: {err:?}"701);702Ok(())703})?;704let i = linker.instantiate(&mut store, &c)?;705706let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;707let call = i.get_typed_func::<(), ()>(&mut store, "call")?;708709let (resource,) = ctor.call(&mut store, (100,))?;710*store.data_mut() = Some(resource);711call.call(&mut store, ())?;712713Ok(())714}715716#[test]717fn active_borrows_at_end_of_call() -> Result<()> {718let engine = super::engine();719let c = Component::new(720&engine,721r#"722(component723(import "t" (type $t (sub resource)))724725(core module $m726(func (export "f") (param i32))727)728(core instance $i (instantiate $m))729730(func (export "f") (param "x" (borrow $t))731(canon lift (core func $i "f")))732)733"#,734)?;735736struct MyType;737738let mut store = Store::new(&engine, ());739let mut linker = Linker::new(&engine);740linker741.root()742.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;743let i = linker.instantiate(&mut store, &c)?;744745let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;746747let resource = Resource::new_own(1);748let err = f.call(&mut store, (&resource,)).unwrap_err();749assert_eq!(750err.to_string(),751"borrow handles still remain at the end of the call",752);753754Ok(())755}756757#[test]758fn thread_through_borrow() -> Result<()> {759let engine = super::engine();760let c = Component::new(761&engine,762r#"763(component764(import "t" (type $t (sub resource)))765(import "f" (func $f (param "x" (borrow $t))))766767(core func $f (canon lower (func $f)))768(core func $drop (canon resource.drop $t))769770(core module $m771(import "" "f" (func $f (param i32)))772(import "" "drop" (func $drop (param i32)))773(func (export "f2") (param i32)774(call $f (local.get 0))775(call $f (local.get 0))776(call $drop (local.get 0))777)778)779(core instance $i (instantiate $m780(with "" (instance781(export "f" (func $f))782(export "drop" (func $drop))783))784))785786(func (export "f2") (param "x" (borrow $t))787(canon lift (core func $i "f2")))788)789"#,790)?;791792struct MyType;793794let mut store = Store::new(&engine, ());795let mut linker = Linker::new(&engine);796linker797.root()798.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;799linker800.root()801.func_wrap("f", |_cx, (r,): (Resource<MyType>,)| {802assert!(!r.owned());803assert_eq!(r.rep(), 100);804Ok(())805})?;806let i = linker.instantiate(&mut store, &c)?;807808let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;809810let resource = Resource::new_own(100);811f.call(&mut store, (&resource,))?;812Ok(())813}814815#[test]816fn cannot_use_borrow_for_own() -> Result<()> {817let engine = super::engine();818let c = Component::new(819&engine,820r#"821(component822(import "t" (type $t (sub resource)))823824(core module $m825(func (export "f") (param i32) (result i32)826local.get 0827)828)829(core instance $i (instantiate $m))830831(func (export "f") (param "x" (borrow $t)) (result (own $t))832(canon lift (core func $i "f")))833)834"#,835)?;836837struct MyType;838839let mut store = Store::new(&engine, ());840let mut linker = Linker::new(&engine);841linker842.root()843.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;844let i = linker.instantiate(&mut store, &c)?;845846let f = i.get_typed_func::<(&Resource<MyType>,), (Resource<MyType>,)>(&mut store, "f")?;847848let resource = Resource::new_own(100);849let err = f.call(&mut store, (&resource,)).unwrap_err();850assert_eq!(err.to_string(), "cannot lift own resource from a borrow");851Ok(())852}853854#[test]855fn can_use_own_for_borrow() -> Result<()> {856let engine = super::engine();857let c = Component::new(858&engine,859r#"860(component861(import "t" (type $t (sub resource)))862863(core func $drop (canon resource.drop $t))864865(core module $m866(import "" "drop" (func $drop (param i32)))867(func (export "f") (param i32)868(call $drop (local.get 0))869)870)871(core instance $i (instantiate $m872(with "" (instance873(export "drop" (func $drop))874))875))876877(func (export "f") (param "x" (borrow $t))878(canon lift (core func $i "f")))879)880"#,881)?;882883struct MyType;884885let mut store = Store::new(&engine, ());886let mut linker = Linker::new(&engine);887linker888.root()889.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;890let i_pre = linker.instantiate_pre(&c)?;891let i = i_pre.instantiate(&mut store)?;892893let f = i.get_func(&mut store, "f").unwrap();894let f_typed = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;895896let resource = Resource::new_own(100);897f_typed.call(&mut store, (&resource,))?;898899let resource = Resource::new_borrow(200);900f_typed.call(&mut store, (&resource,))?;901902let resource = Resource::<MyType>::new_own(300).try_into_resource_any(&mut store)?;903f.call(&mut store, &[Val::Resource(resource)], &mut [])?;904resource.resource_drop(&mut store)?;905906// TODO: Enable once https://github.com/bytecodealliance/wasmtime/issues/7793 is fixed907//let resource =908// Resource::<MyType>::new_borrow(400).try_into_resource_any(&mut store, &i_pre, ty_idx)?;909//f.call(&mut store, &[Val::Resource(resource)], &mut [])?;910//resource.resource_drop(&mut store)?;911912Ok(())913}914915#[test]916fn passthrough_wrong_type() -> Result<()> {917let engine = super::engine();918let c = Component::new(919&engine,920r#"921(component922(import "t" (type $t (sub resource)))923(import "f" (func $f (param "a" (borrow $t)) (result (own $t))))924925(core func $f (canon lower (func $f)))926927(core module $m928(import "" "f" (func $f (param i32) (result i32)))929(func (export "f2") (param i32)930(drop (call $f (local.get 0)))931)932)933(core instance $i (instantiate $m934(with "" (instance935(export "f" (func $f))936))937))938939(func (export "f2") (param "x" (borrow $t))940(canon lift (core func $i "f2")))941)942"#,943)?;944945struct MyType;946947let mut store = Store::new(&engine, ());948let mut linker = Linker::new(&engine);949linker950.root()951.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;952linker953.root()954.func_wrap("f", |_cx, (r,): (Resource<MyType>,)| Ok((r,)))?;955let i = linker.instantiate(&mut store, &c)?;956957let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;958959let resource = Resource::new_own(100);960let err = f.call(&mut store, (&resource,)).unwrap_err();961assert!(962format!("{err:?}").contains("cannot lower a `borrow` resource into an `own`"),963"bad error: {err:?}"964);965Ok(())966}967968#[test]969fn pass_moved_resource() -> Result<()> {970let engine = super::engine();971let c = Component::new(972&engine,973r#"974(component975(import "t" (type $t (sub resource)))976(core module $m977(func (export "f") (param i32 i32))978)979(core instance $i (instantiate $m))980981(func (export "f") (param "x" (own $t)) (param "y" (borrow $t))982(canon lift (core func $i "f")))983)984"#,985)?;986987struct MyType;988989let mut store = Store::new(&engine, ());990let mut linker = Linker::new(&engine);991linker992.root()993.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;994let i = linker.instantiate(&mut store, &c)?;995996let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f")?;997998let resource = Resource::new_own(100);999let err = f.call(&mut store, (&resource, &resource)).unwrap_err();1000assert!(1001format!("{err:?}").contains("host resource already consumed"),1002"bad error: {err:?}"1003);1004Ok(())1005}10061007#[test]1008fn type_mismatch() -> Result<()> {1009let engine = super::engine();1010let c = Component::new(1011&engine,1012r#"1013(component1014(type $t' (resource (rep i32)))1015(export $t "t" (type $t'))10161017(core func $drop (canon resource.drop $t))10181019(func (export "f1") (param "x" (own $t))1020(canon lift (core func $drop)))1021(func (export "f2") (param "x" (borrow $t))1022(canon lift (core func $drop)))1023(func (export "f3") (param "x" u32)1024(canon lift (core func $drop)))1025)1026"#,1027)?;10281029struct MyType;10301031let mut store = Store::new(&engine, ());1032let i = Linker::new(&engine).instantiate(&mut store, &c)?;10331034assert!(1035i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f1")1036.is_err()1037);1038assert!(1039i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f1")1040.is_ok()1041);10421043assert!(1044i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")1045.is_err()1046);1047assert!(1048i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f2")1049.is_ok()1050);10511052assert!(1053i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f3")1054.is_err()1055);1056assert!(1057i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f3")1058.is_err()1059);1060assert!(i.get_typed_func::<(u32,), ()>(&mut store, "f3").is_ok());10611062Ok(())1063}10641065#[test]1066fn drop_no_dtor() -> Result<()> {1067let engine = super::engine();1068let c = Component::new(1069&engine,1070r#"1071(component1072(type $t' (resource (rep i32)))1073(export $t "t" (type $t'))10741075(core func $ctor (canon resource.new $t))10761077(func (export "ctor") (param "x" u32) (result (own $t))1078(canon lift (core func $ctor)))1079)1080"#,1081)?;10821083let mut store = Store::new(&engine, ());1084let i = Linker::new(&engine).instantiate(&mut store, &c)?;1085let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;1086let (resource,) = ctor.call(&mut store, (100,))?;1087resource.resource_drop(&mut store)?;10881089Ok(())1090}10911092#[test]1093fn host_borrow_as_resource_any() -> Result<()> {1094let engine = super::engine();1095let c = Component::new(1096&engine,1097r#"1098(component1099(import "t" (type $t (sub resource)))1100(import "f" (func $f (param "f" (borrow $t))))11011102(core func $f (canon lower (func $f)))1103(core func $drop (canon resource.drop $t))11041105(core module $m1106(import "" "f" (func $f (param i32)))1107(import "" "drop" (func $drop (param i32)))1108(func (export "f2") (param i32)1109(call $f (local.get 0))1110(call $drop (local.get 0))1111)1112)1113(core instance $i (instantiate $m1114(with "" (instance1115(export "f" (func $f))1116(export "drop" (func $drop))1117))1118))11191120(func (export "f2") (param "x" (borrow $t))1121(canon lift (core func $i "f2")))1122)1123"#,1124)?;11251126struct MyType;11271128let mut store = Store::new(&engine, ());11291130// First test the above component where the host properly drops the argument1131{1132let mut linker = Linker::new(&engine);1133linker1134.root()1135.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1136linker1137.root()1138.func_wrap("f", |mut cx, (r,): (ResourceAny,)| {1139r.resource_drop(&mut cx)?;1140Ok(())1141})?;1142let i = linker.instantiate(&mut store, &c)?;11431144let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;11451146let resource = Resource::new_own(100);1147f.call(&mut store, (&resource,))?;1148}11491150// Then also test the case where the host forgets a drop1151{1152let mut linker = Linker::new(&engine);1153linker1154.root()1155.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1156linker.root().func_wrap("f", |_cx, (_r,): (ResourceAny,)| {1157// ... no drop here1158Ok(())1159})?;1160let i = linker.instantiate(&mut store, &c)?;11611162let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;11631164let resource = Resource::new_own(100);1165let err = f.call(&mut store, (&resource,)).unwrap_err();1166assert!(1167format!("{err:?}").contains("borrow handles still remain at the end of the call"),1168"bad error: {err:?}"1169);1170}1171Ok(())1172}11731174#[test]1175fn pass_guest_back_as_borrow() -> Result<()> {1176let engine = super::engine();1177let c = Component::new(1178&engine,1179r#"1180(component1181(type $t' (resource (rep i32)))11821183(export $t "t" (type $t'))11841185(core func $new (canon resource.new $t))11861187(core module $m1188(import "" "new" (func $new (param i32) (result i32)))11891190(func (export "mk") (result i32)1191(call $new (i32.const 100))1192)11931194(func (export "take") (param i32)1195(if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))1196)1197)1198(core instance $i (instantiate $m1199(with "" (instance1200(export "new" (func $new))1201))1202))12031204(func (export "mk") (result (own $t))1205(canon lift (core func $i "mk")))1206(func (export "take") (param "x" (borrow $t))1207(canon lift (core func $i "take")))1208)1209"#,1210)?;12111212let mut store = Store::new(&engine, ());1213let i = Linker::new(&engine).instantiate(&mut store, &c)?;1214let mk = i.get_typed_func::<(), (ResourceAny,)>(&mut store, "mk")?;1215let take = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "take")?;12161217let (resource,) = mk.call(&mut store, ())?;1218take.call(&mut store, (&resource,))?;12191220resource.resource_drop(&mut store)?;12211222// Should not be valid to use `resource` again1223let err = take.call(&mut store, (&resource,)).unwrap_err();1224assert_eq!(err.to_string(), "unknown handle index 1");12251226Ok(())1227}12281229#[test]1230fn pass_host_borrow_to_guest() -> Result<()> {1231let engine = super::engine();1232let c = Component::new(1233&engine,1234r#"1235(component1236(import "t" (type $t (sub resource)))12371238(core func $drop (canon resource.drop $t))12391240(core module $m1241(import "" "drop" (func $drop (param i32)))1242(func (export "take") (param i32)1243(call $drop (local.get 0))1244)1245)1246(core instance $i (instantiate $m1247(with "" (instance1248(export "drop" (func $drop))1249))1250))12511252(func (export "take") (param "x" (borrow $t))1253(canon lift (core func $i "take")))1254)1255"#,1256)?;12571258struct MyType;12591260let mut store = Store::new(&engine, ());1261let mut linker = Linker::new(&engine);1262linker1263.root()1264.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1265let i = linker.instantiate(&mut store, &c)?;1266let take = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "take")?;12671268let resource = Resource::new_borrow(100);1269take.call(&mut store, (&resource,))?;12701271Ok(())1272}12731274#[tokio::test]1275async fn drop_on_owned_resource() -> Result<()> {1276let mut config = wasmtime::Config::new();1277config.wasm_component_model_async(true);1278let engine = &wasmtime::Engine::new(&config)?;1279let c = Component::new(1280&engine,1281r#"1282(component1283(import "t" (type $t (sub resource)))1284(import "[constructor]t" (func $ctor (result (own $t))))1285(import "[method]t.foo" (func $foo async (param "self" (borrow $t))))12861287(core func $ctor (canon lower (func $ctor)))1288(core func $drop (canon resource.drop $t))1289(core func $foo (canon lower (func $foo) async))12901291(core module $m1292(import "" "ctor" (func $ctor (result i32)))1293(import "" "foo" (func $foo (param i32) (result i32)))1294(import "" "drop" (func $drop (param i32)))12951296(func (export "f")1297(local $r i32)1298(local $status i32)1299(local.set $r (call $ctor))1300(local.set $status (call $foo (local.get $r)))1301(if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $status) (i32.const 0xf)))1302(then unreachable))1303(call $drop (local.get $r))1304(unreachable)1305)1306)1307(core instance $i (instantiate $m1308(with "" (instance1309(export "ctor" (func $ctor))1310(export "foo" (func $foo))1311(export "drop" (func $drop))1312))1313))1314(func (export "f") async (canon lift (core func $i "f")))1315)1316"#,1317)?;13181319struct MyType;13201321let mut store = Store::new(&engine, ());1322let mut linker = Linker::new(&engine);1323linker1324.root()1325.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1326linker.root().func_wrap("[constructor]t", |_, ()| {1327Ok((Resource::<MyType>::new_own(300),))1328})?;1329linker1330.root()1331.func_wrap_concurrent("[method]t.foo", |_cx, (r,): (Resource<MyType>,)| {1332assert!(!r.owned());1333Box::pin(core::future::pending::<Result<()>>())1334})?;1335let i = linker.instantiate_async(&mut store, &c).await?;1336let f = i.get_typed_func::<(), ()>(&mut store, "f")?;13371338let err = f.call_async(&mut store, ()).await.unwrap_err();1339assert!(1340format!("{err:?}").contains("cannot remove owned resource while borrowed"),1341"bad error: {err:?}"1342);13431344Ok(())1345}13461347#[test]1348fn guest_different_host_same() -> Result<()> {1349let engine = super::engine();1350let c = Component::new(1351&engine,1352r#"1353(component1354(import "t1" (type $t1 (sub resource)))1355(import "t2" (type $t2 (sub resource)))13561357(import "f" (func $f (param "a" (borrow $t1)) (param "b" (borrow $t2))))13581359(export $g1 "g1" (type $t1))1360(export $g2 "g2" (type $t2))13611362(core func $f (canon lower (func $f)))1363(core func $drop1 (canon resource.drop $t1))1364(core func $drop2 (canon resource.drop $t2))13651366(core module $m1367(import "" "f" (func $f (param i32 i32)))1368(import "" "drop1" (func $drop1 (param i32)))1369(import "" "drop2" (func $drop2 (param i32)))13701371(func (export "f") (param i32 i32)1372;; different types, but everything goes into the same1373;; handle index namespace1374(if (i32.ne (local.get 0) (i32.const 1)) (then (unreachable)))1375(if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable)))13761377;; host should end up getting the same resource1378(call $f (local.get 0) (local.get 1))13791380;; drop our borrows1381(call $drop1 (local.get 0))1382(call $drop2 (local.get 1))1383)1384)1385(core instance $i (instantiate $m1386(with "" (instance1387(export "f" (func $f))1388(export "drop1" (func $drop1))1389(export "drop2" (func $drop2))1390))1391))13921393(func (export "f2") (param "a" (borrow $g1)) (param "b" (borrow $g2))1394(canon lift (core func $i "f")))1395)1396"#,1397)?;13981399struct MyType;14001401let mut store = Store::new(&engine, ());1402let mut linker = Linker::new(&engine);1403linker1404.root()1405.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1406linker1407.root()1408.resource("t2", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1409linker.root().func_wrap(1410"f",1411|_cx, (r1, r2): (Resource<MyType>, Resource<MyType>)| {1412assert!(!r1.owned());1413assert!(!r2.owned());1414assert_eq!(r1.rep(), 100);1415assert_eq!(r2.rep(), 100);1416Ok(())1417},1418)?;1419let i = linker.instantiate(&mut store, &c)?;1420let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f2")?;14211422let t1 = i.get_resource(&mut store, "g1").unwrap();1423let t2 = i.get_resource(&mut store, "g2").unwrap();1424assert_eq!(t1, t2);1425assert_eq!(t1, ResourceType::host::<MyType>());14261427let resource = Resource::new_own(100);1428f.call(&mut store, (&resource, &resource))?;14291430Ok(())1431}14321433#[test]1434fn resource_any_to_typed_handles_borrow() -> Result<()> {1435let engine = super::engine();1436let c = Component::new(1437&engine,1438r#"1439(component1440(import "t" (type $t (sub resource)))14411442(import "f" (func $f (param "a" (borrow $t))))14431444(core func $f (canon lower (func $f)))14451446(core module $m1447(import "" "f" (func $f (param i32)))14481449(func (export "f") (param i32)1450(call $f (local.get 0))1451)1452)1453(core instance $i (instantiate $m1454(with "" (instance1455(export "f" (func $f))1456))1457))14581459(func (export "f") (param "a" (own $t))1460(canon lift (core func $i "f")))1461)1462"#,1463)?;14641465struct MyType;14661467let mut store = Store::new(&engine, ());1468let mut linker = Linker::new(&engine);1469linker1470.root()1471.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;1472linker1473.root()1474.func_wrap("f", |mut cx, (r,): (ResourceAny,)| {1475let r = r.try_into_resource::<MyType>(&mut cx).unwrap();1476assert_eq!(r.rep(), 100);1477assert!(!r.owned());1478Ok(())1479})?;1480let i = linker.instantiate(&mut store, &c)?;1481let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;14821483let resource = Resource::new_own(100);1484f.call(&mut store, (&resource,))?;14851486Ok(())1487}14881489#[test]1490fn resource_dynamic() -> Result<()> {1491let r = ResourceDynamic::new_own(1, 2);1492assert_eq!(r.rep(), 1);1493assert!(r.owned());1494assert_eq!(r.ty(), 2);14951496let engine = super::engine();1497let mut store = Store::new(&engine, ());14981499let r2 = r.try_into_resource_any(&mut store)?;1500assert_eq!(r2.ty(), ResourceType::host_dynamic(2));1501assert!(r2.owned());15021503let r3 = r2.try_into_resource_dynamic(&mut store)?;1504assert_eq!(r3.rep(), 1);1505assert_eq!(r3.ty(), 2);15061507let c = Component::new(1508&engine,1509r#"1510(component1511(import "t" (type $t (sub resource)))1512(import "u" (type $u (sub resource)))15131514(core func $t_drop (canon resource.drop $t))1515(core func $u_drop (canon resource.drop $u))15161517(func (export "drop-t") (param "x" (own $t))1518(canon lift (core func $t_drop)))1519(func (export "drop-u") (param "x" (own $u))1520(canon lift (core func $u_drop)))1521)1522"#,1523)?;1524let mut linker = Linker::new(&engine);1525linker1526.root()1527.resource("t", ResourceType::host_dynamic(2), |_, _| Ok(()))?;1528linker1529.root()1530.resource("u", ResourceType::host_dynamic(3), |_, _| Ok(()))?;1531let instance = linker.instantiate(&mut store, &c)?;15321533let drop_t = instance.get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-t")?;1534let drop_u = instance.get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-u")?;15351536drop_t.call(&mut store, (ResourceDynamic::new_own(1, 2),))?;15371538drop_u.call(&mut store, (ResourceDynamic::new_own(2, 3),))?;15391540assert!(1541drop_t1542.call(&mut store, (ResourceDynamic::new_own(1, 1),))1543.is_err()1544);15451546Ok(())1547}15481549#[test]1550fn resource_dynamic_not_static() -> Result<()> {1551let engine = super::engine();1552let mut store = Store::new(&engine, ());1553let c = Component::new(1554&engine,1555r#"1556(component1557(import "t" (type $t (sub resource)))1558(core func $t_drop (canon resource.drop $t))1559(func (export "drop-t") (param "x" (own $t))1560(canon lift (core func $t_drop)))1561)1562"#,1563)?;15641565struct T;15661567{1568let mut linker = Linker::new(&engine);1569linker1570.root()1571.resource("t", ResourceType::host_dynamic(2), |_, _| Ok(()))?;1572let instance = linker.instantiate(&mut store, &c)?;1573instance.get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-t")?;1574assert!(1575instance1576.get_typed_func::<(Resource<T>,), ()>(&mut store, "drop-t")1577.is_err()1578);1579}15801581{1582let mut linker = Linker::new(&engine);1583linker1584.root()1585.resource("t", ResourceType::host::<T>(), |_, _| Ok(()))?;1586let instance = linker.instantiate(&mut store, &c)?;1587assert!(1588instance1589.get_typed_func::<(ResourceDynamic,), ()>(&mut store, "drop-t")1590.is_err()1591);1592instance.get_typed_func::<(Resource<T>,), ()>(&mut store, "drop-t")?;1593}15941595Ok(())1596}15971598#[test]1599fn intrinsic_trampolines() -> Result<()> {1600let engine = super::engine();1601let mut store = Store::new(&engine, ());1602let linker = Linker::new(&engine);1603let c = Component::new(1604&engine,1605r#"1606(component1607(type $r' (resource (rep i32)))1608(export $r "r" (type $r'))16091610(core func $new (canon resource.new $r))1611(core func $rep (canon resource.rep $r))16121613(func (export "new") (param "x" u32) (result (own $r))1614(canon lift (core func $new)))1615(func (export "rep") (param "x" (borrow $r)) (result u32)1616(canon lift (core func $rep)))1617)1618"#,1619)?;1620let i = linker.instantiate(&mut store, &c)?;1621let new = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "new")?;1622let rep = i.get_typed_func::<(ResourceAny,), (u32,)>(&mut store, "rep")?;16231624let r = new.call(&mut store, (42,))?.0;1625assert!(rep.call(&mut store, (r,)).is_err());1626Ok(())1627}162816291630