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