1 #![cfg(not(miri))] 2 #![allow(dead_code)] 3 4 use super::engine; 5 use anyhow::Result; 6 use wasmtime::{ 7 component::{Component, Linker}, 8 Store, 9 }; 10 11 mod ownership; 12 mod results; 13 14 mod no_imports { 15 use super::*; 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 Ok(()) 58 } 59 } 60 61 mod one_import { 62 use super::*; 63 64 wasmtime::component::bindgen!({ 65 inline: " 66 package foo:foo; 67 68 world one-import { 69 import foo: interface { 70 foo: func(); 71 } 72 73 export bar: func(); 74 } 75 ", 76 }); 77 78 #[test] 79 fn run() -> Result<()> { 80 let engine = engine(); 81 82 let component = Component::new( 83 &engine, 84 r#" 85 (component 86 (import "foo" (instance $i 87 (export "foo" (func)) 88 )) 89 (core module $m 90 (import "" "" (func)) 91 (export "" (func 0)) 92 ) 93 (core func $f (canon lower (func $i "foo"))) 94 (core instance $i (instantiate $m 95 (with "" (instance (export "" (func $f)))) 96 )) 97 98 (func $f (export "bar") (canon lift (core func $i ""))) 99 ) 100 "#, 101 )?; 102 103 #[derive(Default)] 104 struct MyImports { 105 hit: bool, 106 } 107 108 impl foo::Host for MyImports { 109 fn foo(&mut self) { 110 self.hit = true; 111 } 112 } 113 114 let mut linker = Linker::new(&engine); 115 foo::add_to_linker(&mut linker, |f: &mut MyImports| f)?; 116 let mut store = Store::new(&engine, MyImports::default()); 117 let one_import = OneImport::instantiate(&mut store, &component, &linker)?; 118 one_import.call_bar(&mut store)?; 119 assert!(store.data().hit); 120 Ok(()) 121 } 122 } 123 124 mod resources_at_world_level { 125 use super::*; 126 use wasmtime::component::Resource; 127 128 wasmtime::component::bindgen!({ 129 inline: " 130 package foo:foo; 131 132 world resources { 133 resource x { 134 constructor(); 135 } 136 137 export y: func(x: x); 138 } 139 ", 140 }); 141 142 #[test] 143 fn run() -> Result<()> { 144 let engine = engine(); 145 146 let component = Component::new( 147 &engine, 148 r#" 149 (component 150 (import "x" (type $x (sub resource))) 151 (import "[constructor]x" (func $ctor (result (own $x)))) 152 153 (core func $dtor (canon resource.drop $x)) 154 (core func $ctor (canon lower (func $ctor))) 155 156 (core module $m 157 (import "" "ctor" (func $ctor (result i32))) 158 (import "" "dtor" (func $dtor (param i32))) 159 160 (func (export "x") (param i32) 161 (call $dtor (local.get 0)) 162 (call $dtor (call $ctor)) 163 ) 164 ) 165 (core instance $i (instantiate $m 166 (with "" (instance 167 (export "ctor" (func $ctor)) 168 (export "dtor" (func $dtor)) 169 )) 170 )) 171 (func (export "y") (param "x" (own $x)) 172 (canon lift (core func $i "x"))) 173 ) 174 "#, 175 )?; 176 177 #[derive(Default)] 178 struct MyImports { 179 ctor_hit: bool, 180 drops: usize, 181 } 182 183 impl HostX for MyImports { 184 fn new(&mut self) -> Resource<X> { 185 self.ctor_hit = true; 186 Resource::new_own(80) 187 } 188 189 fn drop(&mut self, val: Resource<X>) -> Result<()> { 190 match self.drops { 191 0 => assert_eq!(val.rep(), 40), 192 1 => assert_eq!(val.rep(), 80), 193 _ => unreachable!(), 194 } 195 self.drops += 1; 196 Ok(()) 197 } 198 } 199 200 impl ResourcesImports for MyImports {} 201 202 let mut linker = Linker::new(&engine); 203 Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?; 204 let mut store = Store::new(&engine, MyImports::default()); 205 let one_import = Resources::instantiate(&mut store, &component, &linker)?; 206 one_import.call_y(&mut store, Resource::new_own(40))?; 207 assert!(store.data().ctor_hit); 208 assert_eq!(store.data().drops, 2); 209 Ok(()) 210 } 211 } 212 213 mod resources_at_interface_level { 214 use super::*; 215 use wasmtime::component::Resource; 216 217 wasmtime::component::bindgen!({ 218 inline: " 219 package foo:foo; 220 221 interface def { 222 resource x { 223 constructor(); 224 } 225 } 226 227 interface user { 228 use def.{x}; 229 230 y: func(x: x); 231 } 232 233 world resources { 234 export user; 235 } 236 ", 237 }); 238 239 #[test] 240 fn run() -> Result<()> { 241 let engine = engine(); 242 243 let component = Component::new( 244 &engine, 245 r#" 246 (component 247 (import (interface "foo:foo/def") (instance $i 248 (export $x "x" (type (sub resource))) 249 (export "[constructor]x" (func (result (own $x)))) 250 )) 251 (alias export $i "x" (type $x)) 252 (core func $dtor (canon resource.drop $x)) 253 (core func $ctor (canon lower (func $i "[constructor]x"))) 254 255 (core module $m 256 (import "" "ctor" (func $ctor (result i32))) 257 (import "" "dtor" (func $dtor (param i32))) 258 259 (func (export "x") (param i32) 260 (call $dtor (local.get 0)) 261 (call $dtor (call $ctor)) 262 ) 263 ) 264 (core instance $i (instantiate $m 265 (with "" (instance 266 (export "ctor" (func $ctor)) 267 (export "dtor" (func $dtor)) 268 )) 269 )) 270 (func $y (param "x" (own $x)) 271 (canon lift (core func $i "x"))) 272 273 (instance (export (interface "foo:foo/user")) 274 (export "y" (func $y)) 275 ) 276 ) 277 "#, 278 )?; 279 280 #[derive(Default)] 281 struct MyImports { 282 ctor_hit: bool, 283 drops: usize, 284 } 285 286 use foo::foo::def::X; 287 288 impl foo::foo::def::HostX for MyImports { 289 fn new(&mut self) -> Resource<X> { 290 self.ctor_hit = true; 291 Resource::new_own(80) 292 } 293 294 fn drop(&mut self, val: Resource<X>) -> Result<()> { 295 match self.drops { 296 0 => assert_eq!(val.rep(), 40), 297 1 => assert_eq!(val.rep(), 80), 298 _ => unreachable!(), 299 } 300 self.drops += 1; 301 Ok(()) 302 } 303 } 304 305 impl foo::foo::def::Host for MyImports {} 306 307 let mut linker = Linker::new(&engine); 308 Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?; 309 let mut store = Store::new(&engine, MyImports::default()); 310 let one_import = Resources::instantiate(&mut store, &component, &linker)?; 311 one_import 312 .foo_foo_user() 313 .call_y(&mut store, Resource::new_own(40))?; 314 assert!(store.data().ctor_hit); 315 assert_eq!(store.data().drops, 2); 316 Ok(()) 317 } 318 } 319 320 mod async_config { 321 use super::*; 322 323 wasmtime::component::bindgen!({ 324 inline: " 325 package foo:foo; 326 327 world t1 { 328 import foo: interface { 329 foo: func(); 330 } 331 import x: func(); 332 import y: func(); 333 export z: func(); 334 } 335 ", 336 async: true, 337 }); 338 339 struct T; 340 341 #[async_trait::async_trait] 342 impl T1Imports for T { 343 async fn x(&mut self) {} 344 345 async fn y(&mut self) {} 346 } 347 348 async fn _test_t1(t1: &T1, store: &mut Store<()>) { 349 let _ = t1.call_z(&mut *store).await; 350 } 351 352 wasmtime::component::bindgen!({ 353 inline: " 354 package foo:foo; 355 356 world t2 { 357 import x: func(); 358 import y: func(); 359 export z: func(); 360 } 361 ", 362 async: { 363 except_imports: ["x"], 364 }, 365 }); 366 367 #[async_trait::async_trait] 368 impl T2Imports for T { 369 fn x(&mut self) {} 370 371 async fn y(&mut self) {} 372 } 373 374 async fn _test_t2(t2: &T2, store: &mut Store<()>) { 375 let _ = t2.call_z(&mut *store).await; 376 } 377 378 wasmtime::component::bindgen!({ 379 inline: " 380 package foo:foo; 381 382 world t3 { 383 import x: func(); 384 import y: func(); 385 export z: func(); 386 } 387 ", 388 async: { 389 only_imports: ["x"], 390 }, 391 }); 392 393 #[async_trait::async_trait] 394 impl T3Imports for T { 395 async fn x(&mut self) {} 396 397 fn y(&mut self) {} 398 } 399 400 async fn _test_t3(t3: &T3, store: &mut Store<()>) { 401 let _ = t3.call_z(&mut *store).await; 402 } 403 } 404 405 mod exported_resources { 406 use super::*; 407 use std::mem; 408 use wasmtime::component::Resource; 409 410 wasmtime::component::bindgen!({ 411 inline: " 412 package foo:foo; 413 414 interface a { 415 resource x { 416 constructor(); 417 } 418 } 419 420 world resources { 421 export b: interface { 422 use a.{x as y}; 423 424 resource x { 425 constructor(y: y); 426 foo: func() -> u32; 427 } 428 } 429 430 resource x; 431 432 export f: func(x1: x, x2: x) -> x; 433 } 434 ", 435 }); 436 437 #[derive(Default)] 438 struct MyImports { 439 hostcalls: Vec<Hostcall>, 440 next_a_x: u32, 441 } 442 443 #[derive(PartialEq, Debug)] 444 enum Hostcall { 445 DropRootX(u32), 446 DropAX(u32), 447 NewA, 448 } 449 450 use foo::foo::a; 451 452 impl ResourcesImports for MyImports {} 453 454 impl HostX for MyImports { 455 fn drop(&mut self, val: Resource<X>) -> Result<()> { 456 self.hostcalls.push(Hostcall::DropRootX(val.rep())); 457 Ok(()) 458 } 459 } 460 461 impl a::HostX for MyImports { 462 fn new(&mut self) -> Resource<a::X> { 463 let rep = self.next_a_x; 464 self.next_a_x += 1; 465 self.hostcalls.push(Hostcall::NewA); 466 Resource::new_own(rep) 467 } 468 469 fn drop(&mut self, val: Resource<a::X>) -> Result<()> { 470 self.hostcalls.push(Hostcall::DropAX(val.rep())); 471 Ok(()) 472 } 473 } 474 475 impl foo::foo::a::Host for MyImports {} 476 477 #[test] 478 fn run() -> Result<()> { 479 let engine = engine(); 480 481 let component = Component::new( 482 &engine, 483 r#" 484 (component 485 ;; setup the `foo:foo/a` import 486 (import (interface "foo:foo/a") (instance $a 487 (export $x "x" (type (sub resource))) 488 (export "[constructor]x" (func (result (own $x)))) 489 )) 490 (alias export $a "x" (type $a-x)) 491 (core func $a-x-drop (canon resource.drop $a-x)) 492 (core func $a-x-ctor (canon lower (func $a "[constructor]x"))) 493 494 ;; setup the root import of the `x` resource 495 (import "x" (type $x (sub resource))) 496 (core func $root-x-dtor (canon resource.drop $x)) 497 498 ;; setup and declare the `x` resource for the `b` export. 499 (core module $indirect-dtor 500 (func (export "b-x-dtor") (param i32) 501 local.get 0 502 i32.const 0 503 call_indirect (param i32) 504 ) 505 (table (export "$imports") 1 1 funcref) 506 ) 507 (core instance $indirect-dtor (instantiate $indirect-dtor)) 508 (type $b-x (resource (rep i32) (dtor (func $indirect-dtor "b-x-dtor")))) 509 (core func $b-x-drop (canon resource.drop $b-x)) 510 (core func $b-x-rep (canon resource.rep $b-x)) 511 (core func $b-x-new (canon resource.new $b-x)) 512 513 ;; main module implementation 514 (core module $main 515 (import "foo:foo/a" "[constructor]x" (func $a-x-ctor (result i32))) 516 (import "foo:foo/a" "[resource-drop]x" (func $a-x-dtor (param i32))) 517 (import "$root" "[resource-drop]x" (func $x-dtor (param i32))) 518 (import "[export]b" "[resource-drop]x" (func $b-x-dtor (param i32))) 519 (import "[export]b" "[resource-new]x" (func $b-x-new (param i32) (result i32))) 520 (import "[export]b" "[resource-rep]x" (func $b-x-rep (param i32) (result i32))) 521 (func (export "b#[constructor]x") (param i32) (result i32) 522 (call $a-x-dtor (local.get 0)) 523 (call $b-x-new (call $a-x-ctor)) 524 ) 525 (func (export "b#[method]x.foo") (param i32) (result i32) 526 local.get 0) 527 (func (export "b#[dtor]x") (param i32) 528 (call $a-x-dtor (local.get 0)) 529 ) 530 (func (export "f") (param i32 i32) (result i32) 531 (call $x-dtor (local.get 0)) 532 local.get 1 533 ) 534 ) 535 (core instance $main (instantiate $main 536 (with "foo:foo/a" (instance 537 (export "[resource-drop]x" (func $a-x-drop)) 538 (export "[constructor]x" (func $a-x-ctor)) 539 )) 540 (with "$root" (instance 541 (export "[resource-drop]x" (func $root-x-dtor)) 542 )) 543 (with "[export]b" (instance 544 (export "[resource-drop]x" (func $b-x-drop)) 545 (export "[resource-rep]x" (func $b-x-rep)) 546 (export "[resource-new]x" (func $b-x-new)) 547 )) 548 )) 549 550 ;; fill in `$indirect-dtor`'s table with the actual destructor definition 551 ;; now that it's available. 552 (core module $fixup 553 (import "" "b-x-dtor" (func $b-x-dtor (param i32))) 554 (import "" "$imports" (table 1 1 funcref)) 555 (elem (i32.const 0) func $b-x-dtor) 556 ) 557 (core instance (instantiate $fixup 558 (with "" (instance 559 (export "$imports" (table 0 "$imports")) 560 (export "b-x-dtor" (func $main "b#[dtor]x")) 561 )) 562 )) 563 564 ;; Create the `b` export through a subcomponent instantiation. 565 (func $b-x-ctor (param "y" (own $a-x)) (result (own $b-x)) 566 (canon lift (core func $main "b#[constructor]x"))) 567 (func $b-x-foo (param "self" (borrow $b-x)) (result u32) 568 (canon lift (core func $main "b#[method]x.foo"))) 569 (component $b 570 (import "a-x" (type $y (sub resource))) 571 (import "b-x" (type $x' (sub resource))) 572 (import "ctor" (func $ctor (param "y" (own $y)) (result (own $x')))) 573 (import "foo" (func $foo (param "self" (borrow $x')) (result u32))) 574 (export $x "x" (type $x')) 575 (export "[constructor]x" 576 (func $ctor) 577 (func (param "y" (own $y)) (result (own $x)))) 578 (export "[method]x.foo" 579 (func $foo) 580 (func (param "self" (borrow $x)) (result u32))) 581 ) 582 (instance (export "b") (instantiate $b 583 (with "ctor" (func $b-x-ctor)) 584 (with "foo" (func $b-x-foo)) 585 (with "a-x" (type 0 "x")) 586 (with "b-x" (type $b-x)) 587 )) 588 589 ;; Create the `f` export which is a bare function 590 (func (export "f") (param "x1" (own $x)) (param "x2" (own $x)) (result (own $x)) 591 (canon lift (core func $main "f"))) 592 ) 593 "#, 594 )?; 595 596 let mut linker = Linker::new(&engine); 597 Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?; 598 let mut store = Store::new(&engine, MyImports::default()); 599 let i = Resources::instantiate(&mut store, &component, &linker)?; 600 601 // call the root export `f` twice 602 let ret = i.call_f(&mut store, Resource::new_own(1), Resource::new_own(2))?; 603 assert_eq!(ret.rep(), 2); 604 assert_eq!( 605 mem::take(&mut store.data_mut().hostcalls), 606 [Hostcall::DropRootX(1)] 607 ); 608 let ret = i.call_f(&mut store, Resource::new_own(3), Resource::new_own(4))?; 609 assert_eq!(ret.rep(), 4); 610 assert_eq!( 611 mem::take(&mut store.data_mut().hostcalls), 612 [Hostcall::DropRootX(3)] 613 ); 614 615 // interact with the `b` export 616 let b = i.b(); 617 let b_x = b.x().call_constructor(&mut store, Resource::new_own(5))?; 618 assert_eq!( 619 mem::take(&mut store.data_mut().hostcalls), 620 [Hostcall::DropAX(5), Hostcall::NewA] 621 ); 622 b.x().call_foo(&mut store, b_x.clone())?; 623 assert_eq!(mem::take(&mut store.data_mut().hostcalls), []); 624 b_x.resource_drop(&mut store)?; 625 assert_eq!( 626 mem::take(&mut store.data_mut().hostcalls), 627 [Hostcall::DropAX(0)], 628 ); 629 Ok(()) 630 } 631 } 632