1 #![cfg(not(miri))] 2 3 use super::make_echo_component; 4 use wasmtime::Result; 5 use wasmtime::component::{Component, ComponentType, Lift, Linker, Lower}; 6 use wasmtime::{Engine, Store}; 7 use wasmtime_test_macros::{add_variants, flags_test}; 8 9 #[test] 10 fn record_derive() -> Result<()> { 11 #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)] 12 #[component(record)] 13 struct Foo { 14 #[component(name = "foo-bar-baz")] 15 a: i32, 16 b: u32, 17 } 18 19 let engine = super::engine(); 20 let mut store = Store::new(&engine, ()); 21 22 // Happy path: component type matches field count, names, and types 23 24 let component = Component::new( 25 &engine, 26 make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" u32))"#, 8), 27 )?; 28 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 29 30 let input = Foo { a: -42, b: 73 }; 31 let output = instance 32 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")? 33 .call(&mut store, (input,))?; 34 35 assert_eq!((input,), output); 36 37 // Sad path: field count mismatch (too few) 38 39 let component = Component::new( 40 &engine, 41 make_echo_component(r#"(record (field "foo-bar-baz" s32))"#, 4), 42 )?; 43 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 44 45 assert!( 46 instance 47 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 48 .is_err() 49 ); 50 51 // Sad path: field count mismatch (too many) 52 53 let component = Component::new( 54 &engine, 55 make_echo_component( 56 r#"(record (field "foo-bar-baz" s32) (field "b" u32) (field "c" u32))"#, 57 12, 58 ), 59 )?; 60 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 61 62 assert!( 63 instance 64 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 65 .is_err() 66 ); 67 68 // Sad path: field name mismatch 69 70 let component = Component::new( 71 &engine, 72 make_echo_component(r#"(record (field "a" s32) (field "b" u32))"#, 8), 73 )?; 74 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 75 76 assert!( 77 instance 78 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 79 .is_err() 80 ); 81 82 // Sad path: field type mismatch 83 84 let component = Component::new( 85 &engine, 86 make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" s32))"#, 8), 87 )?; 88 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 89 90 assert!( 91 instance 92 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 93 .is_err() 94 ); 95 96 // Happy path redux, with generics this time 97 98 #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)] 99 #[component(record)] 100 struct Generic<A, B> { 101 #[component(name = "foo-bar-baz")] 102 a: A, 103 b: B, 104 } 105 106 let input = Generic { 107 a: -43_i32, 108 b: 74_u32, 109 }; 110 111 let component = Component::new( 112 &engine, 113 make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" u32))"#, 8), 114 )?; 115 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 116 117 let output = instance 118 .get_typed_func::<(Generic<i32, u32>,), (Generic<i32, u32>,)>(&mut store, "echo")? 119 .call(&mut store, (input,))?; 120 121 assert_eq!((input,), output); 122 123 Ok(()) 124 } 125 126 #[test] 127 fn variant_derive() -> Result<()> { 128 #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)] 129 #[component(variant)] 130 enum Foo { 131 #[component(name = "foo-bar-baz")] 132 A(i32), 133 B(u32), 134 C, 135 } 136 137 let engine = super::engine(); 138 let mut store = Store::new(&engine, ()); 139 140 // Happy path: component type matches case count, names, and types 141 142 let component = Component::new( 143 &engine, 144 make_echo_component( 145 r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C"))"#, 146 8, 147 ), 148 )?; 149 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 150 let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?; 151 152 for &input in &[Foo::A(-42), Foo::B(73), Foo::C] { 153 let output = func.call(&mut store, (input,))?; 154 155 assert_eq!((input,), output); 156 } 157 158 // Sad path: case count mismatch (too few) 159 160 let component = Component::new( 161 &engine, 162 make_echo_component(r#"(variant (case "foo-bar-baz" s32) (case "B" u32))"#, 8), 163 )?; 164 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 165 166 assert!( 167 instance 168 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 169 .is_err() 170 ); 171 172 // Sad path: case count mismatch (too many) 173 174 let component = Component::new( 175 &engine, 176 make_echo_component( 177 r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C") (case "D" u32))"#, 178 8, 179 ), 180 )?; 181 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 182 183 assert!( 184 instance 185 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 186 .is_err() 187 ); 188 189 // Sad path: case name mismatch 190 191 let component = Component::new( 192 &engine, 193 make_echo_component(r#"(variant (case "A" s32) (case "B" u32) (case "C"))"#, 8), 194 )?; 195 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 196 197 assert!( 198 instance 199 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 200 .is_err() 201 ); 202 203 // Sad path: case type mismatch 204 205 let component = Component::new( 206 &engine, 207 make_echo_component( 208 r#"(variant (case "foo-bar-baz" s32) (case "B" s32) (case "C"))"#, 209 8, 210 ), 211 )?; 212 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 213 214 assert!( 215 instance 216 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 217 .is_err() 218 ); 219 220 // Happy path redux, with generics this time 221 222 #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)] 223 #[component(variant)] 224 enum Generic<A, B> { 225 #[component(name = "foo-bar-baz")] 226 A(A), 227 B(B), 228 C, 229 } 230 231 let component = Component::new( 232 &engine, 233 make_echo_component( 234 r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C"))"#, 235 8, 236 ), 237 )?; 238 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 239 let func = instance 240 .get_typed_func::<(Generic<i32, u32>,), (Generic<i32, u32>,)>(&mut store, "echo")?; 241 242 for &input in &[Generic::<i32, u32>::A(-42), Generic::B(73), Generic::C] { 243 let output = func.call(&mut store, (input,))?; 244 245 assert_eq!((input,), output); 246 } 247 248 Ok(()) 249 } 250 251 #[test] 252 fn enum_derive() -> Result<()> { 253 #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)] 254 #[component(enum)] 255 #[repr(u8)] 256 enum Foo { 257 #[component(name = "foo-bar-baz")] 258 A, 259 B, 260 C, 261 } 262 263 let engine = super::engine(); 264 let mut store = Store::new(&engine, ()); 265 266 // Happy path: component type matches case count and names 267 268 let component = Component::new( 269 &engine, 270 make_echo_component(r#"(enum "foo-bar-baz" "B" "C")"#, 4), 271 )?; 272 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 273 let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?; 274 275 for &input in &[Foo::A, Foo::B, Foo::C] { 276 let output = func.call(&mut store, (input,))?; 277 278 assert_eq!((input,), output); 279 } 280 281 // Sad path: case count mismatch (too few) 282 283 let component = Component::new( 284 &engine, 285 make_echo_component(r#"(enum "foo-bar-baz" "B")"#, 4), 286 )?; 287 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 288 289 assert!( 290 instance 291 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 292 .is_err() 293 ); 294 295 // Sad path: case count mismatch (too many) 296 297 let component = Component::new( 298 &engine, 299 make_echo_component(r#"(enum "foo-bar-baz" "B" "C" "D")"#, 4), 300 )?; 301 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 302 303 assert!( 304 instance 305 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 306 .is_err() 307 ); 308 309 // Sad path: case name mismatch 310 311 let component = Component::new(&engine, make_echo_component(r#"(enum "A" "B" "C")"#, 4))?; 312 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 313 314 assert!( 315 instance 316 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 317 .is_err() 318 ); 319 320 // Happy path redux, with large enums (i.e. more than 2^8 cases) 321 322 #[add_variants(257)] 323 #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)] 324 #[component(enum)] 325 #[repr(u16)] 326 enum Many {} 327 328 let component = Component::new( 329 &engine, 330 make_echo_component( 331 &format!( 332 "(enum {})", 333 (0..257) 334 .map(|index| format!(r#""V{index}""#)) 335 .collect::<Vec<_>>() 336 .join(" ") 337 ), 338 4, 339 ), 340 )?; 341 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 342 let func = instance.get_typed_func::<(Many,), (Many,)>(&mut store, "echo")?; 343 344 for &input in &[Many::V0, Many::V1, Many::V254, Many::V255, Many::V256] { 345 let output = func.call(&mut store, (input,))?; 346 347 assert_eq!((input,), output); 348 } 349 350 // TODO: The following case takes forever (i.e. I gave up after 30 minutes) to compile; we'll need to profile 351 // the compiler to find out why, which may point the way to a more efficient option. On the other hand, this 352 // may not be worth spending time on. Enums with over 2^16 variants are rare enough. 353 354 // #[add_variants(65537)] 355 // #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)] 356 // #[component(enum)] 357 // #[repr(u32)] 358 // enum ManyMore {} 359 360 Ok(()) 361 } 362 363 #[test] 364 fn flags() -> Result<()> { 365 let config = wasmtime_test_util::component::config(); 366 let engine = Engine::new(&config)?; 367 let mut store = Store::new(&engine, ()); 368 369 // Simple 8-bit flags 370 wasmtime::component::flags! { 371 Foo { 372 #[component(name = "foo-bar-baz")] 373 const A; 374 const B; 375 const C; 376 } 377 } 378 379 assert_eq!(Foo::default(), (Foo::A | Foo::B) & Foo::C); 380 assert_eq!(Foo::B, (Foo::A | Foo::B) & Foo::B); 381 assert_eq!(Foo::A, (Foo::A | Foo::B) & Foo::A); 382 assert_eq!(Foo::A | Foo::B, Foo::A ^ Foo::B); 383 assert_eq!(Foo::default(), Foo::A ^ Foo::A); 384 assert_eq!(Foo::B | Foo::C, !Foo::A); 385 386 // Happy path: component type matches flag count and names 387 388 let component = Component::new( 389 &engine, 390 make_echo_component(r#"(flags "foo-bar-baz" "B" "C")"#, 4), 391 )?; 392 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 393 let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?; 394 395 for n in 0..8 { 396 let mut input = Foo::default(); 397 if (n & 1) != 0 { 398 input |= Foo::A; 399 } 400 if (n & 2) != 0 { 401 input |= Foo::B; 402 } 403 if (n & 4) != 0 { 404 input |= Foo::C; 405 } 406 407 let output = func.call(&mut store, (input,))?; 408 409 assert_eq!((input,), output); 410 } 411 412 // Sad path: flag count mismatch (too few) 413 414 let component = Component::new( 415 &engine, 416 make_echo_component(r#"(flags "foo-bar-baz" "B")"#, 4), 417 )?; 418 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 419 420 assert!( 421 instance 422 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 423 .is_err() 424 ); 425 426 // Sad path: flag count mismatch (too many) 427 428 let component = Component::new( 429 &engine, 430 make_echo_component(r#"(flags "foo-bar-baz" "B" "C" "D")"#, 4), 431 )?; 432 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 433 434 assert!( 435 instance 436 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 437 .is_err() 438 ); 439 440 // Sad path: flag name mismatch 441 442 let component = Component::new(&engine, make_echo_component(r#"(flags "A" "B" "C")"#, 4))?; 443 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 444 445 assert!( 446 instance 447 .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo") 448 .is_err() 449 ); 450 451 // Happy path redux, with large flag count (exactly 8) 452 453 flags_test!(Foo8Exact, 8); 454 455 assert_eq!( 456 Foo8Exact::default(), 457 (Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F7 458 ); 459 assert_eq!( 460 Foo8Exact::F6, 461 (Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F6 462 ); 463 assert_eq!( 464 Foo8Exact::F0, 465 (Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F0 466 ); 467 assert_eq!(Foo8Exact::F0 | Foo8Exact::F6, Foo8Exact::F0 ^ Foo8Exact::F6); 468 assert_eq!(Foo8Exact::default(), Foo8Exact::F0 ^ Foo8Exact::F0); 469 assert_eq!( 470 Foo8Exact::F1 471 | Foo8Exact::F2 472 | Foo8Exact::F3 473 | Foo8Exact::F4 474 | Foo8Exact::F5 475 | Foo8Exact::F6 476 | Foo8Exact::F7, 477 !Foo8Exact::F0 478 ); 479 480 let component = Component::new( 481 &engine, 482 make_echo_component( 483 &format!( 484 r#"(flags {})"#, 485 (0..8) 486 .map(|index| format!(r#""F{index}""#)) 487 .collect::<Vec<_>>() 488 .join(" ") 489 ), 490 4, 491 ), 492 )?; 493 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 494 let func = instance.get_typed_func::<(Foo8Exact,), (Foo8Exact,)>(&mut store, "echo")?; 495 496 for &input in &[ 497 Foo8Exact::F0, 498 Foo8Exact::F1, 499 Foo8Exact::F5, 500 Foo8Exact::F6, 501 Foo8Exact::F7, 502 ] { 503 let output = func.call(&mut store, (input,))?; 504 505 assert_eq!((input,), output); 506 } 507 508 // Happy path redux, with large flag count (more than 8) 509 510 flags_test!(Foo16, 9); 511 512 assert_eq!(Foo16::default(), (Foo16::F0 | Foo16::F7) & Foo16::F8); 513 assert_eq!(Foo16::F7, (Foo16::F0 | Foo16::F7) & Foo16::F7); 514 assert_eq!(Foo16::F0, (Foo16::F0 | Foo16::F7) & Foo16::F0); 515 assert_eq!(Foo16::F0 | Foo16::F7, Foo16::F0 ^ Foo16::F7); 516 assert_eq!(Foo16::default(), Foo16::F0 ^ Foo16::F0); 517 assert_eq!( 518 Foo16::F1 519 | Foo16::F2 520 | Foo16::F3 521 | Foo16::F4 522 | Foo16::F5 523 | Foo16::F6 524 | Foo16::F7 525 | Foo16::F8, 526 !Foo16::F0 527 ); 528 529 let component = Component::new( 530 &engine, 531 make_echo_component( 532 &format!( 533 "(flags {})", 534 (0..9) 535 .map(|index| format!(r#""F{index}""#)) 536 .collect::<Vec<_>>() 537 .join(" ") 538 ), 539 4, 540 ), 541 )?; 542 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 543 let func = instance.get_typed_func::<(Foo16,), (Foo16,)>(&mut store, "echo")?; 544 545 for &input in &[Foo16::F0, Foo16::F1, Foo16::F6, Foo16::F7, Foo16::F8] { 546 let output = func.call(&mut store, (input,))?; 547 548 assert_eq!((input,), output); 549 } 550 551 // Happy path redux, with large flag count (exactly 16) 552 553 flags_test!(Foo16Exact, 16); 554 555 assert_eq!( 556 Foo16Exact::default(), 557 (Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F5 558 ); 559 assert_eq!( 560 Foo16Exact::F14, 561 (Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F14 562 ); 563 assert_eq!( 564 Foo16Exact::F0, 565 (Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F0 566 ); 567 assert_eq!( 568 Foo16Exact::F0 | Foo16Exact::F14, 569 Foo16Exact::F0 ^ Foo16Exact::F14 570 ); 571 assert_eq!(Foo16Exact::default(), Foo16Exact::F0 ^ Foo16Exact::F0); 572 assert_eq!( 573 Foo16Exact::F0 | Foo16Exact::F15, 574 !((!Foo16Exact::F0) & (!Foo16Exact::F15)) 575 ); 576 577 let component = Component::new( 578 &engine, 579 make_echo_component( 580 &format!( 581 r#"(flags {})"#, 582 (0..16) 583 .map(|index| format!(r#""F{index}""#)) 584 .collect::<Vec<_>>() 585 .join(" ") 586 ), 587 4, 588 ), 589 )?; 590 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 591 let func = instance.get_typed_func::<(Foo16Exact,), (Foo16Exact,)>(&mut store, "echo")?; 592 593 for &input in &[ 594 Foo16Exact::F0, 595 Foo16Exact::F1, 596 Foo16Exact::F13, 597 Foo16Exact::F14, 598 Foo16Exact::F15, 599 ] { 600 let output = func.call(&mut store, (input,))?; 601 602 assert_eq!((input,), output); 603 } 604 605 // Happy path redux, with large flag count (more than 16) 606 607 flags_test!(Foo32, 17); 608 609 assert_eq!(Foo32::default(), (Foo32::F0 | Foo32::F15) & Foo32::F16); 610 assert_eq!(Foo32::F15, (Foo32::F0 | Foo32::F15) & Foo32::F15); 611 assert_eq!(Foo32::F0, (Foo32::F0 | Foo32::F15) & Foo32::F0); 612 assert_eq!(Foo32::F0 | Foo32::F15, Foo32::F0 ^ Foo32::F15); 613 assert_eq!(Foo32::default(), Foo32::F0 ^ Foo32::F0); 614 assert_eq!(Foo32::F0 | Foo32::F16, !((!Foo32::F0) & (!Foo32::F16))); 615 616 let component = Component::new( 617 &engine, 618 make_echo_component( 619 &format!( 620 "(flags {})", 621 (0..17) 622 .map(|index| format!(r#""F{index}""#)) 623 .collect::<Vec<_>>() 624 .join(" ") 625 ), 626 4, 627 ), 628 )?; 629 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 630 let func = instance.get_typed_func::<(Foo32,), (Foo32,)>(&mut store, "echo")?; 631 632 for &input in &[Foo32::F0, Foo32::F1, Foo32::F14, Foo32::F15, Foo32::F16] { 633 let output = func.call(&mut store, (input,))?; 634 635 assert_eq!((input,), output); 636 } 637 638 // Happy path redux, with large flag count (exactly 32) 639 640 flags_test!(Foo32Exact, 32); 641 642 assert_eq!( 643 Foo32Exact::default(), 644 (Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F31 645 ); 646 assert_eq!( 647 Foo32Exact::F30, 648 (Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F30 649 ); 650 assert_eq!( 651 Foo32Exact::F0, 652 (Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F0 653 ); 654 assert_eq!( 655 Foo32Exact::F0 | Foo32Exact::F30, 656 Foo32Exact::F0 ^ Foo32Exact::F30 657 ); 658 assert_eq!(Foo32Exact::default(), Foo32Exact::F0 ^ Foo32Exact::F0); 659 assert_eq!( 660 Foo32Exact::F0 | Foo32Exact::F15, 661 !((!Foo32Exact::F0) & (!Foo32Exact::F15)) 662 ); 663 664 let component = Component::new( 665 &engine, 666 make_echo_component( 667 &format!( 668 r#"(flags {})"#, 669 (0..32) 670 .map(|index| format!(r#""F{index}""#)) 671 .collect::<Vec<_>>() 672 .join(" ") 673 ), 674 4, 675 ), 676 )?; 677 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 678 let func = instance.get_typed_func::<(Foo32Exact,), (Foo32Exact,)>(&mut store, "echo")?; 679 680 for &input in &[ 681 Foo32Exact::F0, 682 Foo32Exact::F1, 683 Foo32Exact::F29, 684 Foo32Exact::F30, 685 Foo32Exact::F31, 686 ] { 687 let output = func.call(&mut store, (input,))?; 688 689 assert_eq!((input,), output); 690 } 691 692 Ok(()) 693 } 694