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 x: func(); 329 import y: func(); 330 export z: func(); 331 } 332 ", 333 async: true, 334 }); 335 336 struct T; 337 338 #[async_trait::async_trait] 339 impl T1Imports for T { 340 async fn x(&mut self) {} 341 342 async fn y(&mut self) {} 343 } 344 345 async fn _test_t1(t1: &T1, store: &mut Store<()>) { 346 let _ = t1.call_z(&mut *store).await; 347 } 348 349 wasmtime::component::bindgen!({ 350 inline: " 351 package foo:foo; 352 353 world t2 { 354 import x: func(); 355 import y: func(); 356 export z: func(); 357 } 358 ", 359 async: { 360 except_imports: ["x"], 361 }, 362 }); 363 364 #[async_trait::async_trait] 365 impl T2Imports for T { 366 fn x(&mut self) {} 367 368 async fn y(&mut self) {} 369 } 370 371 async fn _test_t2(t2: &T2, store: &mut Store<()>) { 372 let _ = t2.call_z(&mut *store).await; 373 } 374 375 wasmtime::component::bindgen!({ 376 inline: " 377 package foo:foo; 378 379 world t3 { 380 import x: func(); 381 import y: func(); 382 export z: func(); 383 } 384 ", 385 async: { 386 only_imports: ["x"], 387 }, 388 }); 389 390 #[async_trait::async_trait] 391 impl T3Imports for T { 392 async fn x(&mut self) {} 393 394 fn y(&mut self) {} 395 } 396 397 async fn _test_t3(t3: &T3, store: &mut Store<()>) { 398 let _ = t3.call_z(&mut *store).await; 399 } 400 } 401 402 mod exported_resources { 403 use super::*; 404 use std::mem; 405 use wasmtime::component::Resource; 406 407 wasmtime::component::bindgen!({ 408 inline: " 409 package foo:foo; 410 411 interface a { 412 resource x { 413 constructor(); 414 } 415 } 416 417 world resources { 418 export b: interface { 419 use a.{x as y}; 420 421 resource x { 422 constructor(y: y); 423 foo: func() -> u32; 424 } 425 } 426 427 resource x; 428 429 export f: func(x1: x, x2: x) -> x; 430 } 431 ", 432 }); 433 434 #[derive(Default)] 435 struct MyImports { 436 hostcalls: Vec<Hostcall>, 437 next_a_x: u32, 438 } 439 440 #[derive(PartialEq, Debug)] 441 enum Hostcall { 442 DropRootX(u32), 443 DropAX(u32), 444 NewA, 445 } 446 447 use foo::foo::a; 448 449 impl ResourcesImports for MyImports {} 450 451 impl HostX for MyImports { 452 fn drop(&mut self, val: Resource<X>) -> Result<()> { 453 self.hostcalls.push(Hostcall::DropRootX(val.rep())); 454 Ok(()) 455 } 456 } 457 458 impl a::HostX for MyImports { 459 fn new(&mut self) -> Resource<a::X> { 460 let rep = self.next_a_x; 461 self.next_a_x += 1; 462 self.hostcalls.push(Hostcall::NewA); 463 Resource::new_own(rep) 464 } 465 466 fn drop(&mut self, val: Resource<a::X>) -> Result<()> { 467 self.hostcalls.push(Hostcall::DropAX(val.rep())); 468 Ok(()) 469 } 470 } 471 472 impl foo::foo::a::Host for MyImports {} 473 474 #[test] 475 fn run() -> Result<()> { 476 let engine = engine(); 477 478 let component = Component::new( 479 &engine, 480 r#" 481 (component 482 ;; setup the `foo:foo/a` import 483 (import (interface "foo:foo/a") (instance $a 484 (export $x "x" (type (sub resource))) 485 (export "[constructor]x" (func (result (own $x)))) 486 )) 487 (alias export $a "x" (type $a-x)) 488 (core func $a-x-drop (canon resource.drop $a-x)) 489 (core func $a-x-ctor (canon lower (func $a "[constructor]x"))) 490 491 ;; setup the root import of the `x` resource 492 (import "x" (type $x (sub resource))) 493 (core func $root-x-dtor (canon resource.drop $x)) 494 495 ;; setup and declare the `x` resource for the `b` export. 496 (core module $indirect-dtor 497 (func (export "b-x-dtor") (param i32) 498 local.get 0 499 i32.const 0 500 call_indirect (param i32) 501 ) 502 (table (export "$imports") 1 1 funcref) 503 ) 504 (core instance $indirect-dtor (instantiate $indirect-dtor)) 505 (type $b-x (resource (rep i32) (dtor (func $indirect-dtor "b-x-dtor")))) 506 (core func $b-x-drop (canon resource.drop $b-x)) 507 (core func $b-x-rep (canon resource.rep $b-x)) 508 (core func $b-x-new (canon resource.new $b-x)) 509 510 ;; main module implementation 511 (core module $main 512 (import "foo:foo/a" "[constructor]x" (func $a-x-ctor (result i32))) 513 (import "foo:foo/a" "[resource-drop]x" (func $a-x-dtor (param i32))) 514 (import "$root" "[resource-drop]x" (func $x-dtor (param i32))) 515 (import "[export]b" "[resource-drop]x" (func $b-x-dtor (param i32))) 516 (import "[export]b" "[resource-new]x" (func $b-x-new (param i32) (result i32))) 517 (import "[export]b" "[resource-rep]x" (func $b-x-rep (param i32) (result i32))) 518 (func (export "b#[constructor]x") (param i32) (result i32) 519 (call $a-x-dtor (local.get 0)) 520 (call $b-x-new (call $a-x-ctor)) 521 ) 522 (func (export "b#[method]x.foo") (param i32) (result i32) 523 local.get 0) 524 (func (export "b#[dtor]x") (param i32) 525 (call $a-x-dtor (local.get 0)) 526 ) 527 (func (export "f") (param i32 i32) (result i32) 528 (call $x-dtor (local.get 0)) 529 local.get 1 530 ) 531 ) 532 (core instance $main (instantiate $main 533 (with "foo:foo/a" (instance 534 (export "[resource-drop]x" (func $a-x-drop)) 535 (export "[constructor]x" (func $a-x-ctor)) 536 )) 537 (with "$root" (instance 538 (export "[resource-drop]x" (func $root-x-dtor)) 539 )) 540 (with "[export]b" (instance 541 (export "[resource-drop]x" (func $b-x-drop)) 542 (export "[resource-rep]x" (func $b-x-rep)) 543 (export "[resource-new]x" (func $b-x-new)) 544 )) 545 )) 546 547 ;; fill in `$indirect-dtor`'s table with the actual destructor definition 548 ;; now that it's available. 549 (core module $fixup 550 (import "" "b-x-dtor" (func $b-x-dtor (param i32))) 551 (import "" "$imports" (table 1 1 funcref)) 552 (elem (i32.const 0) func $b-x-dtor) 553 ) 554 (core instance (instantiate $fixup 555 (with "" (instance 556 (export "$imports" (table 0 "$imports")) 557 (export "b-x-dtor" (func $main "b#[dtor]x")) 558 )) 559 )) 560 561 ;; Create the `b` export through a subcomponent instantiation. 562 (func $b-x-ctor (param "y" (own $a-x)) (result (own $b-x)) 563 (canon lift (core func $main "b#[constructor]x"))) 564 (func $b-x-foo (param "self" (borrow $b-x)) (result u32) 565 (canon lift (core func $main "b#[method]x.foo"))) 566 (component $b 567 (import "a-x" (type $y (sub resource))) 568 (import "b-x" (type $x' (sub resource))) 569 (import "ctor" (func $ctor (param "y" (own $y)) (result (own $x')))) 570 (import "foo" (func $foo (param "self" (borrow $x')) (result u32))) 571 (export $x "x" (type $x')) 572 (export "[constructor]x" 573 (func $ctor) 574 (func (param "y" (own $y)) (result (own $x)))) 575 (export "[method]x.foo" 576 (func $foo) 577 (func (param "self" (borrow $x)) (result u32))) 578 ) 579 (instance (export "b") (instantiate $b 580 (with "ctor" (func $b-x-ctor)) 581 (with "foo" (func $b-x-foo)) 582 (with "a-x" (type 0 "x")) 583 (with "b-x" (type $b-x)) 584 )) 585 586 ;; Create the `f` export which is a bare function 587 (func (export "f") (param "x1" (own $x)) (param "x2" (own $x)) (result (own $x)) 588 (canon lift (core func $main "f"))) 589 ) 590 "#, 591 )?; 592 593 let mut linker = Linker::new(&engine); 594 Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?; 595 let mut store = Store::new(&engine, MyImports::default()); 596 let (i, _) = Resources::instantiate(&mut store, &component, &linker)?; 597 598 // call the root export `f` twice 599 let ret = i.call_f(&mut store, Resource::new_own(1), Resource::new_own(2))?; 600 assert_eq!(ret.rep(), 2); 601 assert_eq!( 602 mem::take(&mut store.data_mut().hostcalls), 603 [Hostcall::DropRootX(1)] 604 ); 605 let ret = i.call_f(&mut store, Resource::new_own(3), Resource::new_own(4))?; 606 assert_eq!(ret.rep(), 4); 607 assert_eq!( 608 mem::take(&mut store.data_mut().hostcalls), 609 [Hostcall::DropRootX(3)] 610 ); 611 612 // interact with the `b` export 613 let b = i.b(); 614 let b_x = b.x().call_constructor(&mut store, Resource::new_own(5))?; 615 assert_eq!( 616 mem::take(&mut store.data_mut().hostcalls), 617 [Hostcall::DropAX(5), Hostcall::NewA] 618 ); 619 b.x().call_foo(&mut store, b_x.clone())?; 620 assert_eq!(mem::take(&mut store.data_mut().hostcalls), []); 621 b_x.resource_drop(&mut store)?; 622 assert_eq!( 623 mem::take(&mut store.data_mut().hostcalls), 624 [Hostcall::DropAX(0)], 625 ); 626 Ok(()) 627 } 628 } 629