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