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