1 #![cfg(not(miri))] 2 3 use super::engine; 4 use anyhow::Result; 5 use wasmtime::{ 6 Config, Engine, Store, 7 component::{Component, Linker}, 8 }; 9 10 mod ownership; 11 mod results; 12 13 mod no_imports { 14 use super::*; 15 use std::rc::Rc; 16 17 wasmtime::component::bindgen!({ 18 inline: " 19 package foo:foo; 20 21 world no-imports { 22 export foo: interface { 23 foo: func(); 24 } 25 26 export bar: func(); 27 } 28 ", 29 }); 30 31 #[test] 32 fn run() -> Result<()> { 33 let engine = engine(); 34 35 let component = Component::new( 36 &engine, 37 r#" 38 (component 39 (core module $m 40 (func (export "")) 41 ) 42 (core instance $i (instantiate $m)) 43 44 (func $f (export "bar") (canon lift (core func $i ""))) 45 46 (instance $i (export "foo" (func $f))) 47 (export "foo" (instance $i)) 48 ) 49 "#, 50 )?; 51 52 let linker = Linker::new(&engine); 53 let mut store = Store::new(&engine, ()); 54 let no_imports = NoImports::instantiate(&mut store, &component, &linker)?; 55 no_imports.call_bar(&mut store)?; 56 no_imports.foo().call_foo(&mut store)?; 57 58 let linker = Linker::new(&engine); 59 let mut non_send_store = Store::new(&engine, Rc::new(())); 60 let no_imports = NoImports::instantiate(&mut non_send_store, &component, &linker)?; 61 no_imports.call_bar(&mut non_send_store)?; 62 no_imports.foo().call_foo(&mut non_send_store)?; 63 Ok(()) 64 } 65 } 66 67 mod no_imports_concurrent { 68 use super::*; 69 use futures::{ 70 FutureExt, 71 stream::{FuturesUnordered, TryStreamExt}, 72 }; 73 74 wasmtime::component::bindgen!({ 75 inline: " 76 package foo:foo; 77 78 world no-imports { 79 export foo: interface { 80 foo: async func(); 81 } 82 83 export bar: async func(); 84 } 85 ", 86 }); 87 88 #[tokio::test] 89 async fn run() -> Result<()> { 90 let mut config = Config::new(); 91 config.wasm_component_model_async(true); 92 config.async_support(true); 93 let engine = &Engine::new(&config)?; 94 95 let component = Component::new( 96 &engine, 97 r#" 98 (component 99 (core module $m 100 (import "" "task.return" (func $task-return)) 101 (func (export "bar") (result i32) 102 call $task-return 103 i32.const 0 104 ) 105 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 106 ) 107 (core func $task-return (canon task.return)) 108 (core instance $i (instantiate $m 109 (with "" (instance (export "task.return" (func $task-return)))) 110 )) 111 112 (func $f (export "bar") 113 (canon lift (core func $i "bar") async (callback (func $i "callback"))) 114 ) 115 116 (instance $i (export "foo" (func $f))) 117 (export "foo" (instance $i)) 118 ) 119 "#, 120 )?; 121 122 let linker = Linker::new(&engine); 123 let mut store = Store::new(&engine, ()); 124 let no_imports = NoImports::instantiate_async(&mut store, &component, &linker).await?; 125 store 126 .run_concurrent(async move |accessor| { 127 let mut futures = FuturesUnordered::new(); 128 futures.push(no_imports.call_bar(accessor).boxed()); 129 futures.push(no_imports.foo().call_foo(accessor).boxed()); 130 assert!(futures.try_next().await?.is_some()); 131 assert!(futures.try_next().await?.is_some()); 132 Ok(()) 133 }) 134 .await? 135 } 136 } 137 138 mod one_import { 139 use super::*; 140 use wasmtime::component::HasSelf; 141 142 wasmtime::component::bindgen!({ 143 inline: " 144 package foo:foo; 145 146 world one-import { 147 import foo: interface { 148 foo: func(); 149 } 150 151 export bar: func(); 152 } 153 ", 154 }); 155 156 #[test] 157 fn run() -> Result<()> { 158 let engine = engine(); 159 160 let component = Component::new( 161 &engine, 162 r#" 163 (component 164 (import "foo" (instance $i 165 (export "foo" (func)) 166 )) 167 (core module $m 168 (import "" "" (func)) 169 (export "" (func 0)) 170 ) 171 (core func $f (canon lower (func $i "foo"))) 172 (core instance $i (instantiate $m 173 (with "" (instance (export "" (func $f)))) 174 )) 175 176 (func $f (export "bar") (canon lift (core func $i ""))) 177 ) 178 "#, 179 )?; 180 181 #[derive(Default)] 182 struct MyImports { 183 hit: bool, 184 } 185 186 impl foo::Host for MyImports { 187 fn foo(&mut self) { 188 self.hit = true; 189 } 190 } 191 192 let mut linker = Linker::new(&engine); 193 foo::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?; 194 let mut store = Store::new(&engine, MyImports::default()); 195 let one_import = OneImport::instantiate(&mut store, &component, &linker)?; 196 one_import.call_bar(&mut store)?; 197 assert!(store.data().hit); 198 Ok(()) 199 } 200 } 201 202 mod one_import_concurrent { 203 use super::*; 204 use wasmtime::component::{Accessor, HasData}; 205 206 wasmtime::component::bindgen!({ 207 inline: " 208 package foo:foo; 209 210 world no-imports { 211 import foo: interface { 212 foo: async func(); 213 } 214 215 export bar: async func(); 216 } 217 " 218 }); 219 220 #[tokio::test] 221 async fn run() -> Result<()> { 222 let mut config = Config::new(); 223 config.wasm_component_model_async(true); 224 config.async_support(true); 225 let engine = &Engine::new(&config)?; 226 227 let component = Component::new( 228 &engine, 229 r#" 230 (component 231 (import "foo" (instance $foo-instance 232 (export "foo" (func async)) 233 )) 234 (core module $libc 235 (memory (export "memory") 1) 236 ) 237 (core instance $libc-instance (instantiate $libc)) 238 (core module $m 239 (import "" "foo" (func $foo (param) (result i32))) 240 (import "" "task.return" (func $task-return)) 241 (func (export "bar") (result i32) 242 call $foo 243 drop 244 call $task-return 245 i32.const 0 246 ) 247 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 248 ) 249 (core func $foo (canon lower (func $foo-instance "foo") async (memory $libc-instance "memory"))) 250 (core func $task-return (canon task.return)) 251 (core instance $i (instantiate $m 252 (with "" (instance 253 (export "task.return" (func $task-return)) 254 (export "foo" (func $foo)) 255 )) 256 )) 257 258 (func $f (export "bar") async 259 (canon lift (core func $i "bar") async (callback (func $i "callback"))) 260 ) 261 262 (instance $i (export "foo" (func $f))) 263 (export "foo" (instance $i)) 264 ) 265 "#, 266 )?; 267 268 #[derive(Default)] 269 struct MyImports { 270 hit: bool, 271 } 272 273 impl HasData for MyImports { 274 type Data<'a> = &'a mut MyImports; 275 } 276 277 impl foo::HostWithStore for MyImports { 278 async fn foo<T>(accessor: &Accessor<T, Self>) { 279 accessor.with(|mut view| view.get().hit = true); 280 } 281 } 282 283 impl foo::Host for MyImports {} 284 285 let mut linker = Linker::new(&engine); 286 foo::add_to_linker::<_, MyImports>(&mut linker, |x| x)?; 287 let mut store = Store::new(&engine, MyImports::default()); 288 let no_imports = NoImports::instantiate_async(&mut store, &component, &linker).await?; 289 store 290 .run_concurrent(async move |accessor| no_imports.call_bar(accessor).await) 291 .await??; 292 assert!(store.data().hit); 293 Ok(()) 294 } 295 } 296 297 mod resources_at_world_level { 298 use super::*; 299 use wasmtime::component::{HasSelf, Resource}; 300 301 wasmtime::component::bindgen!({ 302 inline: " 303 package foo:foo; 304 305 world resources { 306 resource x { 307 constructor(); 308 } 309 310 export y: func(x: x); 311 } 312 ", 313 }); 314 315 #[test] 316 fn run() -> Result<()> { 317 let engine = engine(); 318 319 let component = Component::new( 320 &engine, 321 r#" 322 (component 323 (import "x" (type $x (sub resource))) 324 (import "[constructor]x" (func $ctor (result (own $x)))) 325 326 (core func $dtor (canon resource.drop $x)) 327 (core func $ctor (canon lower (func $ctor))) 328 329 (core module $m 330 (import "" "ctor" (func $ctor (result i32))) 331 (import "" "dtor" (func $dtor (param i32))) 332 333 (func (export "x") (param i32) 334 (call $dtor (local.get 0)) 335 (call $dtor (call $ctor)) 336 ) 337 ) 338 (core instance $i (instantiate $m 339 (with "" (instance 340 (export "ctor" (func $ctor)) 341 (export "dtor" (func $dtor)) 342 )) 343 )) 344 (func (export "y") (param "x" (own $x)) 345 (canon lift (core func $i "x"))) 346 ) 347 "#, 348 )?; 349 350 #[derive(Default)] 351 struct MyImports { 352 ctor_hit: bool, 353 drops: usize, 354 } 355 356 impl HostX for MyImports { 357 fn new(&mut self) -> Resource<X> { 358 self.ctor_hit = true; 359 Resource::new_own(80) 360 } 361 362 fn drop(&mut self, val: Resource<X>) -> Result<()> { 363 match self.drops { 364 0 => assert_eq!(val.rep(), 40), 365 1 => assert_eq!(val.rep(), 80), 366 _ => unreachable!(), 367 } 368 self.drops += 1; 369 Ok(()) 370 } 371 } 372 373 impl ResourcesImports for MyImports {} 374 375 let mut linker = Linker::new(&engine); 376 Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?; 377 let mut store = Store::new(&engine, MyImports::default()); 378 let one_import = Resources::instantiate(&mut store, &component, &linker)?; 379 one_import.call_y(&mut store, Resource::new_own(40))?; 380 assert!(store.data().ctor_hit); 381 assert_eq!(store.data().drops, 2); 382 Ok(()) 383 } 384 } 385 386 mod resources_at_interface_level { 387 use super::*; 388 use wasmtime::component::{HasSelf, Resource}; 389 390 wasmtime::component::bindgen!({ 391 inline: " 392 package foo:foo; 393 394 interface def { 395 resource x { 396 constructor(); 397 } 398 } 399 400 interface user { 401 use def.{x}; 402 403 y: func(x: x); 404 } 405 406 world resources { 407 export user; 408 } 409 ", 410 }); 411 412 #[test] 413 fn run() -> Result<()> { 414 let engine = engine(); 415 416 let component = Component::new( 417 &engine, 418 r#" 419 (component 420 (import (interface "foo:foo/def") (instance $i 421 (export "x" (type $x (sub resource))) 422 (export "[constructor]x" (func (result (own $x)))) 423 )) 424 (alias export $i "x" (type $x)) 425 (core func $dtor (canon resource.drop $x)) 426 (core func $ctor (canon lower (func $i "[constructor]x"))) 427 428 (core module $m 429 (import "" "ctor" (func $ctor (result i32))) 430 (import "" "dtor" (func $dtor (param i32))) 431 432 (func (export "x") (param i32) 433 (call $dtor (local.get 0)) 434 (call $dtor (call $ctor)) 435 ) 436 ) 437 (core instance $i (instantiate $m 438 (with "" (instance 439 (export "ctor" (func $ctor)) 440 (export "dtor" (func $dtor)) 441 )) 442 )) 443 (func $y (param "x" (own $x)) 444 (canon lift (core func $i "x"))) 445 446 (instance (export (interface "foo:foo/user")) 447 (export "y" (func $y)) 448 ) 449 ) 450 "#, 451 )?; 452 453 #[derive(Default)] 454 struct MyImports { 455 ctor_hit: bool, 456 drops: usize, 457 } 458 459 use foo::foo::def::X; 460 461 impl foo::foo::def::HostX for MyImports { 462 fn new(&mut self) -> Resource<X> { 463 self.ctor_hit = true; 464 Resource::new_own(80) 465 } 466 467 fn drop(&mut self, val: Resource<X>) -> Result<()> { 468 match self.drops { 469 0 => assert_eq!(val.rep(), 40), 470 1 => assert_eq!(val.rep(), 80), 471 _ => unreachable!(), 472 } 473 self.drops += 1; 474 Ok(()) 475 } 476 } 477 478 impl foo::foo::def::Host for MyImports {} 479 480 let mut linker = Linker::new(&engine); 481 Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?; 482 let mut store = Store::new(&engine, MyImports::default()); 483 let one_import = Resources::instantiate(&mut store, &component, &linker)?; 484 one_import 485 .foo_foo_user() 486 .call_y(&mut store, Resource::new_own(40))?; 487 assert!(store.data().ctor_hit); 488 assert_eq!(store.data().drops, 2); 489 Ok(()) 490 } 491 } 492 493 mod async_config { 494 use super::*; 495 496 wasmtime::component::bindgen!({ 497 inline: " 498 package foo:foo; 499 500 world t1 { 501 import foo: interface { 502 foo: func(); 503 } 504 import x: func(); 505 import y: func(); 506 export z: func(); 507 } 508 ", 509 imports: { default: async }, 510 exports: { default: async }, 511 }); 512 513 #[expect(dead_code, reason = "just here for bindings")] 514 struct T; 515 516 impl T1Imports for T { 517 async fn x(&mut self) {} 518 519 async fn y(&mut self) {} 520 } 521 522 async fn _test_t1(t1: &T1, store: &mut Store<()>) { 523 let _ = t1.call_z(&mut *store).await; 524 } 525 526 wasmtime::component::bindgen!({ 527 inline: " 528 package foo:foo; 529 530 world t2 { 531 import x: func(); 532 import y: func(); 533 export z: func(); 534 } 535 ", 536 imports: { 537 "x": tracing, 538 default: async, 539 }, 540 exports: { default: async }, 541 }); 542 543 impl T2Imports for T { 544 fn x(&mut self) {} 545 546 async fn y(&mut self) {} 547 } 548 549 async fn _test_t2(t2: &T2, store: &mut Store<()>) { 550 let _ = t2.call_z(&mut *store).await; 551 } 552 553 wasmtime::component::bindgen!({ 554 inline: " 555 package foo:foo; 556 557 world t3 { 558 import x: func(); 559 import y: func(); 560 export z: func(); 561 } 562 ", 563 imports: { "x": async }, 564 exports: { default: async }, 565 }); 566 567 impl T3Imports for T { 568 async fn x(&mut self) {} 569 570 fn y(&mut self) {} 571 } 572 573 async fn _test_t3(t3: &T3, store: &mut Store<()>) { 574 let _ = t3.call_z(&mut *store).await; 575 } 576 } 577 578 mod exported_resources { 579 use super::*; 580 use std::mem; 581 use wasmtime::component::{HasSelf, Resource}; 582 583 wasmtime::component::bindgen!({ 584 inline: " 585 package foo:foo; 586 587 interface a { 588 resource x { 589 constructor(); 590 } 591 } 592 593 world resources { 594 export b: interface { 595 use a.{x as y}; 596 597 resource x { 598 constructor(y: y); 599 foo: func() -> u32; 600 } 601 } 602 603 resource x; 604 605 export f: func(x1: x, x2: x) -> x; 606 } 607 ", 608 }); 609 610 #[derive(Default)] 611 struct MyImports { 612 hostcalls: Vec<Hostcall>, 613 next_a_x: u32, 614 } 615 616 #[derive(PartialEq, Debug)] 617 enum Hostcall { 618 DropRootX(u32), 619 DropAX(u32), 620 NewA, 621 } 622 623 use foo::foo::a; 624 625 impl ResourcesImports for MyImports {} 626 627 impl HostX for MyImports { 628 fn drop(&mut self, val: Resource<X>) -> Result<()> { 629 self.hostcalls.push(Hostcall::DropRootX(val.rep())); 630 Ok(()) 631 } 632 } 633 634 impl a::HostX for MyImports { 635 fn new(&mut self) -> Resource<a::X> { 636 let rep = self.next_a_x; 637 self.next_a_x += 1; 638 self.hostcalls.push(Hostcall::NewA); 639 Resource::new_own(rep) 640 } 641 642 fn drop(&mut self, val: Resource<a::X>) -> Result<()> { 643 self.hostcalls.push(Hostcall::DropAX(val.rep())); 644 Ok(()) 645 } 646 } 647 648 impl foo::foo::a::Host for MyImports {} 649 650 #[test] 651 fn run() -> Result<()> { 652 let engine = engine(); 653 654 let component = Component::new( 655 &engine, 656 r#" 657 (component 658 ;; setup the `foo:foo/a` import 659 (import (interface "foo:foo/a") (instance $a 660 (export "x" (type $x (sub resource))) 661 (export "[constructor]x" (func (result (own $x)))) 662 )) 663 (alias export $a "x" (type $a-x)) 664 (core func $a-x-drop (canon resource.drop $a-x)) 665 (core func $a-x-ctor (canon lower (func $a "[constructor]x"))) 666 667 ;; setup the root import of the `x` resource 668 (import "x" (type $x (sub resource))) 669 (core func $root-x-dtor (canon resource.drop $x)) 670 671 ;; setup and declare the `x` resource for the `b` export. 672 (core module $indirect-dtor 673 (func (export "b-x-dtor") (param i32) 674 local.get 0 675 i32.const 0 676 call_indirect (param i32) 677 ) 678 (table (export "$imports") 1 1 funcref) 679 ) 680 (core instance $indirect-dtor (instantiate $indirect-dtor)) 681 (type $b-x (resource (rep i32) (dtor (func $indirect-dtor "b-x-dtor")))) 682 (core func $b-x-drop (canon resource.drop $b-x)) 683 (core func $b-x-rep (canon resource.rep $b-x)) 684 (core func $b-x-new (canon resource.new $b-x)) 685 686 ;; main module implementation 687 (core module $main 688 (import "foo:foo/a" "[constructor]x" (func $a-x-ctor (result i32))) 689 (import "foo:foo/a" "[resource-drop]x" (func $a-x-dtor (param i32))) 690 (import "$root" "[resource-drop]x" (func $x-dtor (param i32))) 691 (import "[export]b" "[resource-drop]x" (func $b-x-dtor (param i32))) 692 (import "[export]b" "[resource-new]x" (func $b-x-new (param i32) (result i32))) 693 (import "[export]b" "[resource-rep]x" (func $b-x-rep (param i32) (result i32))) 694 (func (export "b#[constructor]x") (param i32) (result i32) 695 (call $a-x-dtor (local.get 0)) 696 (call $b-x-new (call $a-x-ctor)) 697 ) 698 (func (export "b#[method]x.foo") (param i32) (result i32) 699 local.get 0) 700 (func (export "b#[dtor]x") (param i32) 701 (call $a-x-dtor (local.get 0)) 702 ) 703 (func (export "f") (param i32 i32) (result i32) 704 (call $x-dtor (local.get 0)) 705 local.get 1 706 ) 707 ) 708 (core instance $main (instantiate $main 709 (with "foo:foo/a" (instance 710 (export "[resource-drop]x" (func $a-x-drop)) 711 (export "[constructor]x" (func $a-x-ctor)) 712 )) 713 (with "$root" (instance 714 (export "[resource-drop]x" (func $root-x-dtor)) 715 )) 716 (with "[export]b" (instance 717 (export "[resource-drop]x" (func $b-x-drop)) 718 (export "[resource-rep]x" (func $b-x-rep)) 719 (export "[resource-new]x" (func $b-x-new)) 720 )) 721 )) 722 723 ;; fill in `$indirect-dtor`'s table with the actual destructor definition 724 ;; now that it's available. 725 (core module $fixup 726 (import "" "b-x-dtor" (func $b-x-dtor (param i32))) 727 (import "" "$imports" (table 1 1 funcref)) 728 (elem (i32.const 0) func $b-x-dtor) 729 ) 730 (core instance (instantiate $fixup 731 (with "" (instance 732 (export "$imports" (table 0 "$imports")) 733 (export "b-x-dtor" (func $main "b#[dtor]x")) 734 )) 735 )) 736 737 ;; Create the `b` export through a subcomponent instantiation. 738 (func $b-x-ctor (param "y" (own $a-x)) (result (own $b-x)) 739 (canon lift (core func $main "b#[constructor]x"))) 740 (func $b-x-foo (param "self" (borrow $b-x)) (result u32) 741 (canon lift (core func $main "b#[method]x.foo"))) 742 (component $b 743 (import "a-x" (type $y (sub resource))) 744 (import "b-x" (type $x' (sub resource))) 745 (import "ctor" (func $ctor (param "y" (own $y)) (result (own $x')))) 746 (import "foo" (func $foo (param "self" (borrow $x')) (result u32))) 747 (export $x "x" (type $x')) 748 (export "[constructor]x" 749 (func $ctor) 750 (func (param "y" (own $y)) (result (own $x)))) 751 (export "[method]x.foo" 752 (func $foo) 753 (func (param "self" (borrow $x)) (result u32))) 754 ) 755 (instance (export "b") (instantiate $b 756 (with "ctor" (func $b-x-ctor)) 757 (with "foo" (func $b-x-foo)) 758 (with "a-x" (type 0 "x")) 759 (with "b-x" (type $b-x)) 760 )) 761 762 ;; Create the `f` export which is a bare function 763 (func (export "f") (param "x1" (own $x)) (param "x2" (own $x)) (result (own $x)) 764 (canon lift (core func $main "f"))) 765 ) 766 "#, 767 )?; 768 769 let mut linker = Linker::new(&engine); 770 Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?; 771 let mut store = Store::new(&engine, MyImports::default()); 772 let i = Resources::instantiate(&mut store, &component, &linker)?; 773 774 // call the root export `f` twice 775 let ret = i.call_f(&mut store, Resource::new_own(1), Resource::new_own(2))?; 776 assert_eq!(ret.rep(), 2); 777 assert_eq!( 778 mem::take(&mut store.data_mut().hostcalls), 779 [Hostcall::DropRootX(1)] 780 ); 781 let ret = i.call_f(&mut store, Resource::new_own(3), Resource::new_own(4))?; 782 assert_eq!(ret.rep(), 4); 783 assert_eq!( 784 mem::take(&mut store.data_mut().hostcalls), 785 [Hostcall::DropRootX(3)] 786 ); 787 788 // interact with the `b` export 789 let b = i.b(); 790 let b_x = b.x().call_constructor(&mut store, Resource::new_own(5))?; 791 assert_eq!( 792 mem::take(&mut store.data_mut().hostcalls), 793 [Hostcall::DropAX(5), Hostcall::NewA] 794 ); 795 b.x().call_foo(&mut store, b_x)?; 796 assert_eq!(mem::take(&mut store.data_mut().hostcalls), []); 797 b_x.resource_drop(&mut store)?; 798 assert_eq!( 799 mem::take(&mut store.data_mut().hostcalls), 800 [Hostcall::DropAX(0)], 801 ); 802 Ok(()) 803 } 804 } 805 806 mod unstable_import { 807 use super::*; 808 use wasmtime::component::HasSelf; 809 810 wasmtime::component::bindgen!({ 811 inline: " 812 package foo:foo; 813 814 @unstable(feature = experimental-interface) 815 interface my-interface { 816 @unstable(feature = experimental-function) 817 my-function: func(); 818 } 819 820 world my-world { 821 @unstable(feature = experimental-import) 822 import my-interface; 823 824 export bar: func(); 825 } 826 ", 827 }); 828 829 #[test] 830 fn run() -> Result<()> { 831 // In the example above, all features are required for `my-function` to be imported: 832 assert_success( 833 LinkOptions::default() 834 .experimental_interface(true) 835 .experimental_import(true) 836 .experimental_function(true), 837 ); 838 839 // And every other incomplete combination should fail: 840 assert_failure(&LinkOptions::default()); 841 assert_failure(LinkOptions::default().experimental_function(true)); 842 assert_failure(LinkOptions::default().experimental_interface(true)); 843 assert_failure( 844 LinkOptions::default() 845 .experimental_interface(true) 846 .experimental_function(true), 847 ); 848 assert_failure( 849 LinkOptions::default() 850 .experimental_interface(true) 851 .experimental_import(true), 852 ); 853 assert_failure(LinkOptions::default().experimental_import(true)); 854 assert_failure( 855 LinkOptions::default() 856 .experimental_import(true) 857 .experimental_function(true), 858 ); 859 860 Ok(()) 861 } 862 863 fn assert_success(link_options: &LinkOptions) { 864 run_with_options(link_options).unwrap(); 865 } 866 fn assert_failure(link_options: &LinkOptions) { 867 let err = run_with_options(link_options).unwrap_err().to_string(); 868 assert_eq!( 869 err, 870 "component imports instance `foo:foo/my-interface`, but a matching implementation was not found in the linker" 871 ); 872 } 873 874 fn run_with_options(link_options: &LinkOptions) -> Result<()> { 875 let engine = engine(); 876 877 let component = Component::new( 878 &engine, 879 r#" 880 (component 881 (import "foo:foo/my-interface" (instance $i 882 (export "my-function" (func)) 883 )) 884 (core module $m 885 (import "" "" (func)) 886 (export "" (func 0)) 887 ) 888 (core func $f (canon lower (func $i "my-function"))) 889 (core instance $r (instantiate $m 890 (with "" (instance (export "" (func $f)))) 891 )) 892 893 (func $f (export "bar") (canon lift (core func $r ""))) 894 ) 895 "#, 896 )?; 897 898 #[derive(Default)] 899 struct MyHost; 900 901 impl foo::foo::my_interface::Host for MyHost { 902 fn my_function(&mut self) {} 903 } 904 905 let mut linker = Linker::new(&engine); 906 MyWorld::add_to_linker::<_, HasSelf<_>>(&mut linker, link_options, |h| h)?; 907 let mut store = Store::new(&engine, MyHost::default()); 908 let one_import = MyWorld::instantiate(&mut store, &component, &linker)?; 909 one_import.call_bar(&mut store)?; 910 Ok(()) 911 } 912 } 913