1 use crate::rust::{to_rust_ident, to_rust_upper_camel_case, RustGenerator, TypeMode}; 2 use crate::types::{TypeInfo, Types}; 3 use anyhow::bail; 4 use heck::*; 5 use indexmap::{IndexMap, IndexSet}; 6 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; 7 use std::fmt::Write as _; 8 use std::io::{Read, Write}; 9 use std::mem; 10 use std::process::{Command, Stdio}; 11 use wit_parser::*; 12 13 macro_rules! uwrite { 14 ($dst:expr, $($arg:tt)*) => { 15 write!($dst, $($arg)*).unwrap() 16 }; 17 } 18 19 macro_rules! uwriteln { 20 ($dst:expr, $($arg:tt)*) => { 21 writeln!($dst, $($arg)*).unwrap() 22 }; 23 } 24 25 mod rust; 26 mod source; 27 mod types; 28 use source::Source; 29 30 #[derive(Clone)] 31 enum InterfaceName { 32 /// This interface was remapped using `with` to some other Rust code. 33 Remapped { 34 /// This is the `::`-separated string which is the path to the mapped 35 /// item relative to the root of the `bindgen!` macro invocation. 36 /// 37 /// This path currently starts with `__with_name$N` and will then 38 /// optionally have `::` projections through to the actual item 39 /// depending on how `with` was configured. 40 name_at_root: String, 41 42 /// This is currently only used for exports and is the relative path to 43 /// where this mapped name would be located if `with` were not 44 /// specified. Basically it's the same as the `Path` variant of this 45 /// enum if the mapping weren't present. 46 local_path: Vec<String>, 47 }, 48 49 /// This interface is generated in the module hierarchy specified. 50 /// 51 /// The path listed here is the path, from the root of the `bindgen!` macro, 52 /// to where this interface is generated. 53 Path(Vec<String>), 54 } 55 56 #[derive(Default)] 57 struct Wasmtime { 58 src: Source, 59 opts: Opts, 60 /// A list of all interfaces which were imported by this world. 61 /// 62 /// The first value here is the contents of the module that this interface 63 /// generated. The second value is the name of the interface as also present 64 /// in `self.interface_names`. 65 import_interfaces: Vec<(String, InterfaceName)>, 66 import_functions: Vec<ImportFunction>, 67 exports: Exports, 68 types: Types, 69 sizes: SizeAlign, 70 interface_names: HashMap<InterfaceId, InterfaceName>, 71 interface_last_seen_as_import: HashMap<InterfaceId, bool>, 72 trappable_errors: IndexMap<TypeId, String>, 73 // Track the with options that were used. Remapped interfaces provided via `with` 74 // are required to be used. 75 used_with_opts: HashSet<String>, 76 } 77 78 struct ImportFunction { 79 func: Function, 80 add_to_linker: String, 81 sig: Option<String>, 82 } 83 84 #[derive(Default)] 85 struct Exports { 86 fields: BTreeMap<String, ExportField>, 87 modules: Vec<(String, InterfaceName)>, 88 funcs: Vec<String>, 89 } 90 91 struct ExportField { 92 ty: String, 93 ty_pre: String, 94 getter: String, 95 getter_pre: String, 96 } 97 98 #[derive(Default, Debug, Clone, Copy)] 99 pub enum Ownership { 100 /// Generated types will be composed entirely of owning fields, regardless 101 /// of whether they are used as parameters to guest exports or not. 102 #[default] 103 Owning, 104 105 /// Generated types used as parameters to guest exports will be "deeply 106 /// borrowing", i.e. contain references rather than owned values when 107 /// applicable. 108 Borrowing { 109 /// Whether or not to generate "duplicate" type definitions for a single 110 /// WIT type if necessary, for example if it's used as both an import 111 /// and an export, or if it's used both as a parameter to an export and 112 /// a return value from an export. 113 duplicate_if_necessary: bool, 114 }, 115 } 116 117 #[derive(Default, Debug, Clone)] 118 pub struct Opts { 119 /// Whether or not `rustfmt` is executed to format generated code. 120 pub rustfmt: bool, 121 122 /// Whether or not to emit `tracing` macro calls on function entry/exit. 123 pub tracing: bool, 124 125 /// Whether or not to use async rust functions and traits. 126 pub async_: AsyncConfig, 127 128 /// A list of "trappable errors" which are used to replace the `E` in 129 /// `result<T, E>` found in WIT. 130 pub trappable_error_type: Vec<TrappableError>, 131 132 /// Whether to generate owning or borrowing type definitions. 133 pub ownership: Ownership, 134 135 /// Whether or not to generate code for only the interfaces of this wit file or not. 136 pub only_interfaces: bool, 137 138 /// Configuration of which imports are allowed to generate a trap. 139 pub trappable_imports: TrappableImports, 140 141 /// Remapping of interface names to rust module names. 142 /// TODO: is there a better type to use for the value of this map? 143 pub with: HashMap<String, String>, 144 145 /// Additional derive attributes to add to generated types. If using in a CLI, this flag can be 146 /// specified multiple times to add multiple attributes. 147 /// 148 /// These derive attributes will be added to any generated structs or enums 149 pub additional_derive_attributes: Vec<String>, 150 151 /// Evaluate to a string literal containing the generated code rather than the generated tokens 152 /// themselves. Mostly useful for Wasmtime internal debugging and development. 153 pub stringify: bool, 154 155 /// Temporary option to skip `impl<T: Trait> Trait for &mut T` for the 156 /// `wasmtime-wasi` crate while that's given a chance to update its b 157 /// indings. 158 pub skip_mut_forwarding_impls: bool, 159 160 /// Indicates that the `T` in `Store<T>` should be send even if async is not 161 /// enabled. 162 /// 163 /// This is helpful when sync bindings depend on generated functions from 164 /// async bindings as is the case with WASI in-tree. 165 pub require_store_data_send: bool, 166 167 /// Path to the `wasmtime` crate if it's not the default path. 168 pub wasmtime_crate: Option<String>, 169 } 170 171 #[derive(Debug, Clone)] 172 pub struct TrappableError { 173 /// Full path to the error, such as `wasi:io/streams/error`. 174 pub wit_path: String, 175 176 /// The name, in Rust, of the error type to generate. 177 pub rust_type_name: String, 178 } 179 180 #[derive(Default, Debug, Clone)] 181 pub enum AsyncConfig { 182 /// No functions are `async`. 183 #[default] 184 None, 185 /// All generated functions should be `async`. 186 All, 187 /// These imported functions should not be async, but everything else is. 188 AllExceptImports(HashSet<String>), 189 /// These functions are the only imports that are async, all other imports 190 /// are sync. 191 /// 192 /// Note that all exports are still async in this situation. 193 OnlyImports(HashSet<String>), 194 } 195 196 impl AsyncConfig { 197 pub fn is_import_async(&self, f: &str) -> bool { 198 match self { 199 AsyncConfig::None => false, 200 AsyncConfig::All => true, 201 AsyncConfig::AllExceptImports(set) => !set.contains(f), 202 AsyncConfig::OnlyImports(set) => set.contains(f), 203 } 204 } 205 206 pub fn maybe_async(&self) -> bool { 207 match self { 208 AsyncConfig::None => false, 209 AsyncConfig::All | AsyncConfig::AllExceptImports(_) | AsyncConfig::OnlyImports(_) => { 210 true 211 } 212 } 213 } 214 } 215 216 #[derive(Default, Debug, Clone)] 217 pub enum TrappableImports { 218 /// No imports are allowed to trap. 219 #[default] 220 None, 221 /// All imports may trap. 222 All, 223 /// Only the specified set of functions may trap. 224 Only(HashSet<String>), 225 } 226 227 impl TrappableImports { 228 fn can_trap(&self, f: &Function) -> bool { 229 match self { 230 TrappableImports::None => false, 231 TrappableImports::All => true, 232 TrappableImports::Only(set) => set.contains(&f.name), 233 } 234 } 235 } 236 237 impl Opts { 238 pub fn generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> { 239 let mut r = Wasmtime::default(); 240 r.sizes.fill(resolve); 241 r.opts = self.clone(); 242 r.generate(resolve, world) 243 } 244 245 fn is_store_data_send(&self) -> bool { 246 self.async_.maybe_async() || self.require_store_data_send 247 } 248 } 249 250 impl Wasmtime { 251 fn name_interface( 252 &mut self, 253 resolve: &Resolve, 254 id: InterfaceId, 255 name: &WorldKey, 256 is_export: bool, 257 ) -> bool { 258 let mut path = Vec::new(); 259 if is_export { 260 path.push("exports".to_string()); 261 } 262 match name { 263 WorldKey::Name(name) => { 264 path.push(name.to_snake_case()); 265 } 266 WorldKey::Interface(_) => { 267 let iface = &resolve.interfaces[id]; 268 let pkgname = &resolve.packages[iface.package.unwrap()].name; 269 path.push(pkgname.namespace.to_snake_case()); 270 path.push(self.name_package_module(resolve, iface.package.unwrap())); 271 path.push(to_rust_ident(iface.name.as_ref().unwrap())); 272 } 273 } 274 let entry = if let Some(name_at_root) = self.lookup_replacement(resolve, name, None) { 275 InterfaceName::Remapped { 276 name_at_root, 277 local_path: path, 278 } 279 } else { 280 InterfaceName::Path(path) 281 }; 282 283 let remapped = matches!(entry, InterfaceName::Remapped { .. }); 284 self.interface_names.insert(id, entry); 285 remapped 286 } 287 288 /// If the package `id` is the only package with its namespace/name combo 289 /// then pass through the name unmodified. If, however, there are multiple 290 /// versions of this package then the package module is going to get version 291 /// information. 292 fn name_package_module(&self, resolve: &Resolve, id: PackageId) -> String { 293 let pkg = &resolve.packages[id]; 294 let versions_with_same_name = resolve 295 .packages 296 .iter() 297 .filter_map(|(_, p)| { 298 if p.name.namespace == pkg.name.namespace && p.name.name == pkg.name.name { 299 Some(&p.name.version) 300 } else { 301 None 302 } 303 }) 304 .collect::<Vec<_>>(); 305 let base = pkg.name.name.to_snake_case(); 306 if versions_with_same_name.len() == 1 { 307 return base; 308 } 309 310 let version = match &pkg.name.version { 311 Some(version) => version, 312 // If this package didn't have a version then don't mangle its name 313 // and other packages with the same name but with versions present 314 // will have their names mangled. 315 None => return base, 316 }; 317 318 // Here there's multiple packages with the same name that differ only in 319 // version, so the version needs to be mangled into the Rust module name 320 // that we're generating. This in theory could look at all of 321 // `versions_with_same_name` and produce a minimal diff, e.g. for 0.1.0 322 // and 0.2.0 this could generate "foo1" and "foo2", but for now 323 // a simpler path is chosen to generate "foo0_1_0" and "foo0_2_0". 324 let version = version 325 .to_string() 326 .replace('.', "_") 327 .replace('-', "_") 328 .replace('+', "_") 329 .to_snake_case(); 330 format!("{base}{version}") 331 } 332 333 fn generate(&mut self, resolve: &Resolve, id: WorldId) -> anyhow::Result<String> { 334 self.types.analyze(resolve, id); 335 336 // Resolve the `trappable_error_type` configuration values to `TypeId` 337 // values. This is done by iterating over each `trappable_error_type` 338 // and then locating the interface that it corresponds to as well as the 339 // type within that interface. 340 // 341 // Note that `LookupItem::InterfaceNoPop` is used here as the full 342 // hierarchical behavior of `lookup_keys` isn't used as the interface 343 // must be named here. 344 'outer: for (i, te) in self.opts.trappable_error_type.iter().enumerate() { 345 let error_name = format!("_TrappableError{i}"); 346 for (id, iface) in resolve.interfaces.iter() { 347 for (key, projection) in lookup_keys( 348 resolve, 349 &WorldKey::Interface(id), 350 LookupItem::InterfaceNoPop, 351 ) { 352 assert!(projection.is_empty()); 353 354 // If `wit_path` looks like `{key}/{type_name}` where 355 // `type_name` is a type within `iface` then we've found a 356 // match. Otherwise continue to the next lookup key if there 357 // is one, and failing that continue to the next interface. 358 let suffix = match te.wit_path.strip_prefix(&key) { 359 Some(s) => s, 360 None => continue, 361 }; 362 let suffix = match suffix.strip_prefix('/') { 363 Some(s) => s, 364 None => continue, 365 }; 366 if let Some(id) = iface.types.get(suffix) { 367 uwriteln!(self.src, "type {error_name} = {};", te.rust_type_name); 368 let prev = self.trappable_errors.insert(*id, error_name); 369 assert!(prev.is_none()); 370 continue 'outer; 371 } 372 } 373 } 374 375 bail!( 376 "failed to locate a WIT error type corresponding to the \ 377 `trappable_error_type` name `{}` provided", 378 te.wit_path 379 ) 380 } 381 382 // Convert all entries in `with` as relative to the root of where the 383 // macro itself is invoked. This emits a `pub use` to bring the name 384 // into scope under an "anonymous name" which then replaces the `with` 385 // map entry. 386 let mut with = self.opts.with.iter_mut().collect::<Vec<_>>(); 387 with.sort(); 388 for (i, (_k, v)) in with.into_iter().enumerate() { 389 let name = format!("__with_name{i}"); 390 uwriteln!(self.src, "#[doc(hidden)]\npub use {v} as {name};"); 391 *v = name; 392 } 393 394 let world = &resolve.worlds[id]; 395 for (name, import) in world.imports.iter() { 396 if !self.opts.only_interfaces || matches!(import, WorldItem::Interface { .. }) { 397 self.import(resolve, id, name, import); 398 } 399 } 400 401 for (name, export) in world.exports.iter() { 402 if !self.opts.only_interfaces || matches!(export, WorldItem::Interface { .. }) { 403 self.export(resolve, name, export); 404 } 405 } 406 self.finish(resolve, id) 407 } 408 409 fn import(&mut self, resolve: &Resolve, world: WorldId, name: &WorldKey, item: &WorldItem) { 410 let mut gen = InterfaceGenerator::new(self, resolve); 411 match item { 412 WorldItem::Function(func) => { 413 // Only generate a trait signature for free functions since 414 // resource-related functions get their trait signatures 415 // during `type_resource`. 416 let sig = if let FunctionKind::Freestanding = func.kind { 417 gen.generate_function_trait_sig(func); 418 Some(mem::take(&mut gen.src).into()) 419 } else { 420 None 421 }; 422 gen.generate_add_function_to_linker(TypeOwner::World(world), func, "linker"); 423 let add_to_linker = gen.src.into(); 424 self.import_functions.push(ImportFunction { 425 func: func.clone(), 426 sig, 427 add_to_linker, 428 }); 429 } 430 WorldItem::Interface { id, .. } => { 431 gen.gen.interface_last_seen_as_import.insert(*id, true); 432 gen.current_interface = Some((*id, name, false)); 433 let snake = match name { 434 WorldKey::Name(s) => s.to_snake_case(), 435 WorldKey::Interface(id) => resolve.interfaces[*id] 436 .name 437 .as_ref() 438 .unwrap() 439 .to_snake_case(), 440 }; 441 let module = if gen.gen.name_interface(resolve, *id, name, false) { 442 // If this interface is remapped then that means that it was 443 // provided via the `with` key in the bindgen configuration. 444 // That means that bindings generation is skipped here. To 445 // accomodate future bindgens depending on this bindgen 446 // though we still generate a module which reexports the 447 // original module. This helps maintain the same output 448 // structure regardless of whether `with` is used. 449 let name_at_root = match &gen.gen.interface_names[id] { 450 InterfaceName::Remapped { name_at_root, .. } => name_at_root, 451 InterfaceName::Path(_) => unreachable!(), 452 }; 453 let path_to_root = gen.path_to_root(); 454 format!( 455 " 456 pub mod {snake} {{ 457 #[allow(unused_imports)] 458 pub use {path_to_root}{name_at_root}::*; 459 }} 460 " 461 ) 462 } else { 463 // If this interface is not remapped then it's time to 464 // actually generate bindings here. 465 gen.types(*id); 466 let key_name = resolve.name_world_key(name); 467 gen.generate_add_to_linker(*id, &key_name); 468 469 let module = &gen.src[..]; 470 let wt = gen.gen.wasmtime_path(); 471 472 format!( 473 " 474 #[allow(clippy::all)] 475 pub mod {snake} {{ 476 #[allow(unused_imports)] 477 use {wt}::component::__internal::anyhow; 478 479 {module} 480 }} 481 " 482 ) 483 }; 484 self.import_interfaces 485 .push((module, self.interface_names[id].clone())); 486 } 487 WorldItem::Type(ty) => { 488 let name = match name { 489 WorldKey::Name(name) => name, 490 WorldKey::Interface(_) => unreachable!(), 491 }; 492 gen.define_type(name, *ty); 493 let body = mem::take(&mut gen.src); 494 self.src.push_str(&body); 495 } 496 }; 497 } 498 499 fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) { 500 let wt = self.wasmtime_path(); 501 let mut gen = InterfaceGenerator::new(self, resolve); 502 let field; 503 let ty; 504 let ty_pre; 505 let getter; 506 let getter_pre; 507 match item { 508 WorldItem::Function(func) => { 509 gen.define_rust_guest_export(resolve, None, func); 510 let body = mem::take(&mut gen.src).into(); 511 getter = gen.extract_typed_function(func).1; 512 assert!(gen.src.is_empty()); 513 self.exports.funcs.push(body); 514 ty_pre = format!("{wt}::component::ComponentExportIndex"); 515 field = func_field_name(resolve, func); 516 ty = format!("{wt}::component::Func"); 517 getter_pre = format!( 518 "_component.export_index(None, \"{}\") 519 .ok_or_else(|| anyhow::anyhow!(\"no function export `{0}` found\"))?.1", 520 func.name 521 ); 522 } 523 WorldItem::Type(_) => unreachable!(), 524 WorldItem::Interface { id, .. } => { 525 gen.gen.interface_last_seen_as_import.insert(*id, false); 526 gen.gen.name_interface(resolve, *id, name, true); 527 gen.current_interface = Some((*id, name, true)); 528 gen.types(*id); 529 let struct_name = "Guest"; 530 let iface = &resolve.interfaces[*id]; 531 let iface_name = match name { 532 WorldKey::Name(name) => name, 533 WorldKey::Interface(_) => iface.name.as_ref().unwrap(), 534 }; 535 uwriteln!(gen.src, "pub struct {struct_name} {{"); 536 for (_, func) in iface.functions.iter() { 537 uwriteln!( 538 gen.src, 539 "{}: {wt}::component::Func,", 540 func_field_name(resolve, func) 541 ); 542 } 543 uwriteln!(gen.src, "}}"); 544 545 uwriteln!(gen.src, "#[derive(Clone)]"); 546 uwriteln!(gen.src, "pub struct {struct_name}Pre {{"); 547 for (_, func) in iface.functions.iter() { 548 uwriteln!( 549 gen.src, 550 "{}: {wt}::component::ComponentExportIndex,", 551 func_field_name(resolve, func) 552 ); 553 } 554 uwriteln!(gen.src, "}}"); 555 556 uwriteln!(gen.src, "impl {struct_name}Pre {{"); 557 let instance_name = resolve.name_world_key(name); 558 uwrite!( 559 gen.src, 560 " 561 pub fn new( 562 component: &{wt}::component::Component, 563 ) -> {wt}::Result<{struct_name}Pre> {{ 564 let _component = component; 565 let (_, instance) = component.export_index(None, \"{instance_name}\") 566 .ok_or_else(|| anyhow::anyhow!(\"no exported instance named `{instance_name}`\"))?; 567 let _lookup = |name: &str| {{ 568 _component.export_index(Some(&instance), name) 569 .map(|p| p.1) 570 .ok_or_else(|| {{ 571 anyhow::anyhow!( 572 \"instance export `{instance_name}` does \\ 573 not have export `{{name}}`\" 574 ) 575 }}) 576 }}; 577 " 578 ); 579 let mut fields = Vec::new(); 580 for (_, func) in iface.functions.iter() { 581 let name = func_field_name(resolve, func); 582 uwriteln!(gen.src, "let {name} = _lookup(\"{}\")?;", func.name); 583 fields.push(name); 584 } 585 uwriteln!(gen.src, "Ok({struct_name}Pre {{"); 586 for name in fields { 587 uwriteln!(gen.src, "{name},"); 588 } 589 uwriteln!(gen.src, "}})"); 590 uwriteln!(gen.src, "}}"); 591 592 uwrite!( 593 gen.src, 594 " 595 pub fn load( 596 &self, 597 mut store: impl {wt}::AsContextMut, 598 instance: &{wt}::component::Instance, 599 ) -> {wt}::Result<{struct_name}> {{ 600 let mut store = store.as_context_mut(); 601 let _ = &mut store; 602 let _instance = instance; 603 " 604 ); 605 let mut fields = Vec::new(); 606 for (_, func) in iface.functions.iter() { 607 let (name, getter) = gen.extract_typed_function(func); 608 uwriteln!(gen.src, "let {name} = {getter};"); 609 fields.push(name); 610 } 611 uwriteln!(gen.src, "Ok({struct_name} {{"); 612 for name in fields { 613 uwriteln!(gen.src, "{name},"); 614 } 615 uwriteln!(gen.src, "}})"); 616 uwriteln!(gen.src, "}}"); // end `fn new` 617 uwriteln!(gen.src, "}}"); // end `impl {struct_name}Pre` 618 619 uwriteln!(gen.src, "impl {struct_name} {{"); 620 let mut resource_methods = IndexMap::new(); 621 622 for (_, func) in iface.functions.iter() { 623 match func.kind { 624 FunctionKind::Freestanding => { 625 gen.define_rust_guest_export(resolve, Some(name), func); 626 } 627 FunctionKind::Method(id) 628 | FunctionKind::Constructor(id) 629 | FunctionKind::Static(id) => { 630 resource_methods.entry(id).or_insert(Vec::new()).push(func); 631 } 632 } 633 } 634 635 for (id, _) in resource_methods.iter() { 636 let name = resolve.types[*id].name.as_ref().unwrap(); 637 let snake = name.to_snake_case(); 638 let camel = name.to_upper_camel_case(); 639 uwriteln!( 640 gen.src, 641 "pub fn {snake}(&self) -> Guest{camel}<'_> {{ 642 Guest{camel} {{ funcs: self }} 643 }}" 644 ); 645 } 646 647 uwriteln!(gen.src, "}}"); 648 649 for (id, methods) in resource_methods { 650 let resource_name = resolve.types[id].name.as_ref().unwrap(); 651 let camel = resource_name.to_upper_camel_case(); 652 uwriteln!(gen.src, "impl Guest{camel}<'_> {{"); 653 for method in methods { 654 gen.define_rust_guest_export(resolve, Some(name), method); 655 } 656 uwriteln!(gen.src, "}}"); 657 } 658 659 let module = &gen.src[..]; 660 let snake = to_rust_ident(iface_name); 661 662 let module = format!( 663 " 664 #[allow(clippy::all)] 665 pub mod {snake} {{ 666 #[allow(unused_imports)] 667 use {wt}::component::__internal::anyhow; 668 669 {module} 670 }} 671 " 672 ); 673 let pkgname = match name { 674 WorldKey::Name(_) => None, 675 WorldKey::Interface(_) => { 676 Some(resolve.packages[iface.package.unwrap()].name.clone()) 677 } 678 }; 679 self.exports 680 .modules 681 .push((module, self.interface_names[id].clone())); 682 683 let (path, method_name) = match pkgname { 684 Some(pkgname) => ( 685 format!( 686 "exports::{}::{}::{snake}::{struct_name}", 687 pkgname.namespace.to_snake_case(), 688 self.name_package_module(resolve, iface.package.unwrap()), 689 ), 690 format!( 691 "{}_{}_{snake}", 692 pkgname.namespace.to_snake_case(), 693 self.name_package_module(resolve, iface.package.unwrap()) 694 ), 695 ), 696 None => (format!("exports::{snake}::{struct_name}"), snake.clone()), 697 }; 698 field = format!("interface{}", self.exports.fields.len()); 699 getter = format!("self.{field}.load(&mut store, &_instance)?"); 700 self.exports.funcs.push(format!( 701 " 702 pub fn {method_name}(&self) -> &{path} {{ 703 &self.{field} 704 }} 705 ", 706 )); 707 ty_pre = format!("{path}Pre"); 708 ty = path; 709 getter_pre = format!("{ty_pre}::new(_component)?"); 710 } 711 } 712 let prev = self.exports.fields.insert( 713 field, 714 ExportField { 715 ty, 716 ty_pre, 717 getter, 718 getter_pre, 719 }, 720 ); 721 assert!(prev.is_none()); 722 } 723 724 fn build_world_struct(&mut self, resolve: &Resolve, world: WorldId) { 725 let wt = self.wasmtime_path(); 726 let world_name = &resolve.worlds[world].name; 727 let camel = to_rust_upper_camel_case(&world_name); 728 let (async_, async__, where_clause, await_) = if self.opts.async_.maybe_async() { 729 ("async", "_async", "where _T: Send", ".await") 730 } else { 731 ("", "", "", "") 732 }; 733 uwriteln!( 734 self.src, 735 " 736 /// Auto-generated bindings for a pre-instantiated version of a 737 /// copmonent which implements the world `{world_name}`. 738 /// 739 /// This structure is created through [`{camel}Pre::new`] which 740 /// takes a [`InstancePre`]({wt}::component::InstancePre) that 741 /// has been created through a [`Linker`]({wt}::component::Linker). 742 pub struct {camel}Pre<T> {{" 743 ); 744 uwriteln!(self.src, "instance_pre: {wt}::component::InstancePre<T>,"); 745 for (name, field) in self.exports.fields.iter() { 746 uwriteln!(self.src, "{name}: {},", field.ty_pre); 747 } 748 self.src.push_str("}\n"); 749 750 uwriteln!(self.src, "impl<T> Clone for {camel}Pre<T> {{"); 751 uwriteln!(self.src, "fn clone(&self) -> Self {{"); 752 uwriteln!(self.src, "Self {{ instance_pre: self.instance_pre.clone(),"); 753 for (name, _field) in self.exports.fields.iter() { 754 uwriteln!(self.src, "{name}: self.{name}.clone(),"); 755 } 756 uwriteln!(self.src, "}}"); // `Self ... 757 uwriteln!(self.src, "}}"); // `fn clone` 758 uwriteln!(self.src, "}}"); // `impl Clone` 759 760 uwriteln!( 761 self.src, 762 " 763 /// Auto-generated bindings for an instance a component which 764 /// implements the world `{world_name}`. 765 /// 766 /// This structure is created through either 767 /// [`{camel}::instantiate{async__}`] or by first creating 768 /// a [`{camel}Pre`] followed by using 769 /// [`{camel}Pre::instantiate{async__}`]. 770 pub struct {camel} {{" 771 ); 772 for (name, field) in self.exports.fields.iter() { 773 uwriteln!(self.src, "{name}: {},", field.ty); 774 } 775 self.src.push_str("}\n"); 776 777 self.world_imports_trait(resolve, world); 778 779 uwriteln!(self.src, "const _: () = {{"); 780 uwriteln!( 781 self.src, 782 " 783 #[allow(unused_imports)] 784 use {wt}::component::__internal::anyhow; 785 " 786 ); 787 788 uwriteln!( 789 self.src, 790 "impl<_T> {camel}Pre<_T> {{ 791 /// Creates a new copy of `{camel}Pre` bindings which can then 792 /// be used to instantiate into a particular store. 793 /// 794 /// This method may fail if the compoennt behind `instance_pre` 795 /// does not have the required exports. 796 pub fn new( 797 instance_pre: {wt}::component::InstancePre<_T>, 798 ) -> {wt}::Result<Self> {{ 799 let _component = instance_pre.component(); 800 ", 801 ); 802 for (name, field) in self.exports.fields.iter() { 803 uwriteln!(self.src, "let {name} = {};", field.getter_pre); 804 } 805 uwriteln!(self.src, "Ok({camel}Pre {{"); 806 uwriteln!(self.src, "instance_pre,"); 807 for (name, _) in self.exports.fields.iter() { 808 uwriteln!(self.src, "{name},"); 809 } 810 uwriteln!(self.src, "}})"); 811 uwriteln!(self.src, "}}"); // close `fn new` 812 813 uwriteln!( 814 self.src, 815 " 816 /// Instantiates a new instance of [`{camel}`] within the 817 /// `store` provided. 818 /// 819 /// This function will use `self` as the pre-instantiated 820 /// instance to perform instantiation. Afterwards the preloaded 821 /// indices in `self` are used to lookup all exports on the 822 /// resulting instance. 823 pub {async_} fn instantiate{async__}( 824 &self, 825 mut store: impl {wt}::AsContextMut<Data = _T>, 826 ) -> {wt}::Result<{camel}> 827 {where_clause} 828 {{ 829 let mut store = store.as_context_mut(); 830 let _instance = self.instance_pre.instantiate{async__}(&mut store){await_}?; 831 ", 832 ); 833 for (name, field) in self.exports.fields.iter() { 834 uwriteln!(self.src, "let {name} = {};", field.getter); 835 } 836 uwriteln!(self.src, "Ok({camel} {{"); 837 for (name, _) in self.exports.fields.iter() { 838 uwriteln!(self.src, "{name},"); 839 } 840 uwriteln!(self.src, "}})"); 841 uwriteln!(self.src, "}}"); // close `fn new` 842 uwriteln!( 843 self.src, 844 " 845 pub fn engine(&self) -> &{wt}::Engine {{ 846 self.instance_pre.engine() 847 }} 848 849 pub fn instance_pre(&self) -> &{wt}::component::InstancePre<_T> {{ 850 &self.instance_pre 851 }} 852 ", 853 ); 854 855 uwriteln!(self.src, "}}"); 856 857 uwriteln!( 858 self.src, 859 "impl {camel} {{ 860 /// Convenience wrapper around [`{camel}Pre::new`] and 861 /// [`{camel}Pre::instantiate{async__}`]. 862 pub {async_} fn instantiate{async__}<_T>( 863 mut store: impl {wt}::AsContextMut<Data = _T>, 864 component: &{wt}::component::Component, 865 linker: &{wt}::component::Linker<_T>, 866 ) -> {wt}::Result<{camel}> 867 {where_clause} 868 {{ 869 let pre = linker.instantiate_pre(component)?; 870 {camel}Pre::new(pre)?.instantiate{async__}(store){await_} 871 }} 872 ", 873 ); 874 self.world_add_to_linker(resolve, world); 875 876 for func in self.exports.funcs.iter() { 877 self.src.push_str(func); 878 } 879 880 uwriteln!(self.src, "}}"); // close `impl {camel}` 881 882 uwriteln!(self.src, "}};"); // close `const _: () = ... 883 } 884 885 fn finish(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> { 886 let remapping_keys = self.opts.with.keys().cloned().collect::<HashSet<String>>(); 887 888 let mut unused_keys = remapping_keys 889 .difference(&self.used_with_opts) 890 .map(|s| s.as_str()) 891 .collect::<Vec<&str>>(); 892 893 unused_keys.sort(); 894 895 if !unused_keys.is_empty() { 896 anyhow::bail!("interfaces were specified in the `with` config option but are not referenced in the target world: {unused_keys:?}"); 897 } 898 899 if !self.opts.only_interfaces { 900 self.build_world_struct(resolve, world) 901 } 902 903 let imports = mem::take(&mut self.import_interfaces); 904 self.emit_modules(imports); 905 906 let exports = mem::take(&mut self.exports.modules); 907 self.emit_modules(exports); 908 909 let mut src = mem::take(&mut self.src); 910 if self.opts.rustfmt { 911 let mut child = Command::new("rustfmt") 912 .arg("--edition=2018") 913 .stdin(Stdio::piped()) 914 .stdout(Stdio::piped()) 915 .spawn() 916 .expect("failed to spawn `rustfmt`"); 917 child 918 .stdin 919 .take() 920 .unwrap() 921 .write_all(src.as_bytes()) 922 .unwrap(); 923 src.as_mut_string().truncate(0); 924 child 925 .stdout 926 .take() 927 .unwrap() 928 .read_to_string(src.as_mut_string()) 929 .unwrap(); 930 let status = child.wait().unwrap(); 931 assert!(status.success()); 932 } 933 934 Ok(src.into()) 935 } 936 937 fn emit_modules(&mut self, modules: Vec<(String, InterfaceName)>) { 938 #[derive(Default)] 939 struct Module { 940 submodules: BTreeMap<String, Module>, 941 contents: Vec<String>, 942 } 943 let mut map = Module::default(); 944 for (module, name) in modules { 945 let path = match name { 946 InterfaceName::Remapped { local_path, .. } => local_path, 947 InterfaceName::Path(path) => path, 948 }; 949 let mut cur = &mut map; 950 for name in path[..path.len() - 1].iter() { 951 cur = cur 952 .submodules 953 .entry(name.clone()) 954 .or_insert(Module::default()); 955 } 956 cur.contents.push(module); 957 } 958 959 emit(&mut self.src, map); 960 961 fn emit(me: &mut Source, module: Module) { 962 for (name, submodule) in module.submodules { 963 uwriteln!(me, "pub mod {name} {{"); 964 emit(me, submodule); 965 uwriteln!(me, "}}"); 966 } 967 for submodule in module.contents { 968 uwriteln!(me, "{submodule}"); 969 } 970 } 971 } 972 973 /// Attempts to find the `key`, possibly with the resource projection 974 /// `item`, within the `with` map provided to bindings configuration. 975 fn lookup_replacement( 976 &mut self, 977 resolve: &Resolve, 978 key: &WorldKey, 979 item: Option<&str>, 980 ) -> Option<String> { 981 let item = match item { 982 Some(item) => LookupItem::Name(item), 983 None => LookupItem::None, 984 }; 985 986 for (lookup, mut projection) in lookup_keys(resolve, key, item) { 987 if let Some(renamed) = self.opts.with.get(&lookup) { 988 projection.push(renamed.clone()); 989 projection.reverse(); 990 self.used_with_opts.insert(lookup); 991 return Some(projection.join("::")); 992 } 993 } 994 995 None 996 } 997 998 fn wasmtime_path(&self) -> String { 999 self.opts 1000 .wasmtime_crate 1001 .clone() 1002 .unwrap_or("wasmtime".to_string()) 1003 } 1004 } 1005 1006 enum LookupItem<'a> { 1007 None, 1008 Name(&'a str), 1009 InterfaceNoPop, 1010 } 1011 1012 fn lookup_keys( 1013 resolve: &Resolve, 1014 key: &WorldKey, 1015 item: LookupItem<'_>, 1016 ) -> Vec<(String, Vec<String>)> { 1017 struct Name<'a> { 1018 prefix: Prefix, 1019 item: Option<&'a str>, 1020 } 1021 1022 #[derive(Copy, Clone)] 1023 enum Prefix { 1024 Namespace(PackageId), 1025 UnversionedPackage(PackageId), 1026 VersionedPackage(PackageId), 1027 UnversionedInterface(InterfaceId), 1028 VersionedInterface(InterfaceId), 1029 } 1030 1031 let prefix = match key { 1032 WorldKey::Interface(id) => Prefix::VersionedInterface(*id), 1033 1034 // Non-interface-keyed names don't get the lookup logic below, 1035 // they're relatively uncommon so only lookup the precise key here. 1036 WorldKey::Name(key) => { 1037 let to_lookup = match item { 1038 LookupItem::Name(item) => format!("{key}/{item}"), 1039 LookupItem::None | LookupItem::InterfaceNoPop => key.to_string(), 1040 }; 1041 return vec![(to_lookup, Vec::new())]; 1042 } 1043 }; 1044 1045 // Here names are iteratively attempted as `key` + `item` is "walked to 1046 // its root" and each attempt is consulted in `self.opts.with`. This 1047 // loop will start at the leaf, the most specific path, and then walk to 1048 // the root, popping items, trying to find a result. 1049 // 1050 // Each time a name is "popped" the projection from the next path is 1051 // pushed onto `projection`. This means that if we actually find a match 1052 // then `projection` is a collection of namespaces that results in the 1053 // final replacement name. 1054 let (interface_required, item) = match item { 1055 LookupItem::None => (false, None), 1056 LookupItem::Name(s) => (false, Some(s)), 1057 LookupItem::InterfaceNoPop => (true, None), 1058 }; 1059 let mut name = Name { prefix, item }; 1060 let mut projection = Vec::new(); 1061 let mut ret = Vec::new(); 1062 loop { 1063 let lookup = name.lookup_key(resolve); 1064 ret.push((lookup, projection.clone())); 1065 if !name.pop(resolve, &mut projection) { 1066 break; 1067 } 1068 if interface_required { 1069 match name.prefix { 1070 Prefix::VersionedInterface(_) | Prefix::UnversionedInterface(_) => {} 1071 _ => break, 1072 } 1073 } 1074 } 1075 1076 return ret; 1077 1078 impl<'a> Name<'a> { 1079 fn lookup_key(&self, resolve: &Resolve) -> String { 1080 let mut s = self.prefix.lookup_key(resolve); 1081 if let Some(item) = self.item { 1082 s.push_str("/"); 1083 s.push_str(item); 1084 } 1085 s 1086 } 1087 1088 fn pop(&mut self, resolve: &'a Resolve, projection: &mut Vec<String>) -> bool { 1089 match (self.item, self.prefix) { 1090 // If this is a versioned resource name, try the unversioned 1091 // resource name next. 1092 (Some(_), Prefix::VersionedInterface(id)) => { 1093 self.prefix = Prefix::UnversionedInterface(id); 1094 true 1095 } 1096 // If this is an unversioned resource name then time to 1097 // ignore the resource itself and move on to the next most 1098 // specific item, versioned interface names. 1099 (Some(item), Prefix::UnversionedInterface(id)) => { 1100 self.prefix = Prefix::VersionedInterface(id); 1101 self.item = None; 1102 projection.push(item.to_upper_camel_case()); 1103 true 1104 } 1105 (Some(_), _) => unreachable!(), 1106 (None, _) => self.prefix.pop(resolve, projection), 1107 } 1108 } 1109 } 1110 1111 impl Prefix { 1112 fn lookup_key(&self, resolve: &Resolve) -> String { 1113 match *self { 1114 Prefix::Namespace(id) => resolve.packages[id].name.namespace.clone(), 1115 Prefix::UnversionedPackage(id) => { 1116 let mut name = resolve.packages[id].name.clone(); 1117 name.version = None; 1118 name.to_string() 1119 } 1120 Prefix::VersionedPackage(id) => resolve.packages[id].name.to_string(), 1121 Prefix::UnversionedInterface(id) => { 1122 let id = resolve.id_of(id).unwrap(); 1123 match id.find('@') { 1124 Some(i) => id[..i].to_string(), 1125 None => id, 1126 } 1127 } 1128 Prefix::VersionedInterface(id) => resolve.id_of(id).unwrap(), 1129 } 1130 } 1131 1132 fn pop(&mut self, resolve: &Resolve, projection: &mut Vec<String>) -> bool { 1133 *self = match *self { 1134 // try the unversioned interface next 1135 Prefix::VersionedInterface(id) => Prefix::UnversionedInterface(id), 1136 // try this interface's versioned package next 1137 Prefix::UnversionedInterface(id) => { 1138 let iface = &resolve.interfaces[id]; 1139 let name = iface.name.as_ref().unwrap(); 1140 projection.push(to_rust_ident(name)); 1141 Prefix::VersionedPackage(iface.package.unwrap()) 1142 } 1143 // try the unversioned package next 1144 Prefix::VersionedPackage(id) => Prefix::UnversionedPackage(id), 1145 // try this package's namespace next 1146 Prefix::UnversionedPackage(id) => { 1147 let name = &resolve.packages[id].name; 1148 projection.push(to_rust_ident(&name.name)); 1149 Prefix::Namespace(id) 1150 } 1151 // nothing left to try any more 1152 Prefix::Namespace(_) => return false, 1153 }; 1154 true 1155 } 1156 } 1157 } 1158 1159 impl Wasmtime { 1160 fn has_world_imports_trait(&self, resolve: &Resolve, world: WorldId) -> bool { 1161 !self.import_functions.is_empty() || get_world_resources(resolve, world).count() > 0 1162 } 1163 1164 fn world_imports_trait(&mut self, resolve: &Resolve, world: WorldId) { 1165 if !self.has_world_imports_trait(resolve, world) { 1166 return; 1167 } 1168 1169 let wt = self.wasmtime_path(); 1170 let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name); 1171 if self.opts.async_.maybe_async() { 1172 uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]") 1173 } 1174 uwrite!(self.src, "pub trait {world_camel}Imports"); 1175 let mut supertraits = vec![]; 1176 if self.opts.async_.maybe_async() { 1177 supertraits.push("Send".to_string()); 1178 } 1179 for resource in get_world_resources(resolve, world) { 1180 supertraits.push(format!("Host{}", resource.to_upper_camel_case())); 1181 } 1182 if !supertraits.is_empty() { 1183 uwrite!(self.src, ": {}", supertraits.join(" + ")); 1184 } 1185 uwriteln!(self.src, " {{"); 1186 for f in self.import_functions.iter() { 1187 if let Some(sig) = &f.sig { 1188 self.src.push_str(sig); 1189 self.src.push_str(";\n"); 1190 } 1191 } 1192 uwriteln!(self.src, "}}"); 1193 1194 uwriteln!( 1195 self.src, 1196 " 1197 pub trait {world_camel}ImportsGetHost<T>: 1198 Fn(T) -> <Self as {world_camel}ImportsGetHost<T>>::Host 1199 + Send 1200 + Sync 1201 + Copy 1202 + 'static 1203 {{ 1204 type Host: {world_camel}Imports; 1205 }} 1206 1207 impl<F, T, O> {world_camel}ImportsGetHost<T> for F 1208 where 1209 F: Fn(T) -> O + Send + Sync + Copy + 'static, 1210 O: {world_camel}Imports 1211 {{ 1212 type Host = O; 1213 }} 1214 " 1215 ); 1216 1217 // Generate impl WorldImports for &mut WorldImports 1218 let (async_trait, maybe_send) = if self.opts.async_.maybe_async() { 1219 ( 1220 format!("#[{wt}::component::__internal::async_trait]\n"), 1221 "+ Send", 1222 ) 1223 } else { 1224 (String::new(), "") 1225 }; 1226 if !self.opts.skip_mut_forwarding_impls { 1227 uwriteln!( 1228 self.src, 1229 "{async_trait}impl<_T: {world_camel}Imports + ?Sized {maybe_send}> {world_camel}Imports for &mut _T {{" 1230 ); 1231 // Forward each method call to &mut T 1232 for f in self.import_functions.iter() { 1233 if let Some(sig) = &f.sig { 1234 self.src.push_str(sig); 1235 uwrite!( 1236 self.src, 1237 "{{ {world_camel}Imports::{}(*self,", 1238 rust_function_name(&f.func) 1239 ); 1240 for (name, _) in f.func.params.iter() { 1241 uwrite!(self.src, "{},", to_rust_ident(name)); 1242 } 1243 uwrite!(self.src, ")"); 1244 if self.opts.async_.is_import_async(&f.func.name) { 1245 uwrite!(self.src, ".await"); 1246 } 1247 uwriteln!(self.src, "}}"); 1248 } 1249 } 1250 uwriteln!(self.src, "}}"); 1251 } 1252 } 1253 1254 fn import_interface_paths(&self) -> Vec<String> { 1255 self.import_interfaces 1256 .iter() 1257 .map(|(_, name)| match name { 1258 InterfaceName::Path(path) => path.join("::"), 1259 InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(), 1260 }) 1261 .collect() 1262 } 1263 1264 fn world_host_traits(&self, resolve: &Resolve, world: WorldId) -> Vec<String> { 1265 let mut traits = self 1266 .import_interface_paths() 1267 .iter() 1268 .map(|path| format!("{path}::Host")) 1269 .collect::<Vec<_>>(); 1270 if self.has_world_imports_trait(resolve, world) { 1271 let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name); 1272 traits.push(format!("{world_camel}Imports")); 1273 } 1274 if self.opts.async_.maybe_async() { 1275 traits.push("Send".to_string()); 1276 } 1277 traits 1278 } 1279 1280 fn world_add_to_linker(&mut self, resolve: &Resolve, world: WorldId) { 1281 let has_world_imports_trait = self.has_world_imports_trait(resolve, world); 1282 if self.import_interfaces.is_empty() && !has_world_imports_trait { 1283 return; 1284 } 1285 1286 let camel = to_rust_upper_camel_case(&resolve.worlds[world].name); 1287 let data_bounds = if self.opts.is_store_data_send() { 1288 "T: Send," 1289 } else { 1290 "" 1291 }; 1292 let wt = self.wasmtime_path(); 1293 if has_world_imports_trait { 1294 uwrite!( 1295 self.src, 1296 " 1297 pub fn add_to_linker_imports_get_host<T>( 1298 linker: &mut {wt}::component::Linker<T>, 1299 host_getter: impl for<'a> {camel}ImportsGetHost<&'a mut T>, 1300 ) -> {wt}::Result<()> 1301 where {data_bounds} 1302 {{ 1303 let mut linker = linker.root(); 1304 " 1305 ); 1306 for name in get_world_resources(resolve, world) { 1307 let camel = name.to_upper_camel_case(); 1308 uwriteln!( 1309 self.src, 1310 " 1311 linker.resource( 1312 \"{name}\", 1313 {wt}::component::ResourceType::host::<{camel}>(), 1314 move |mut store, rep| -> {wt}::Result<()> {{ 1315 Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)) 1316 }}, 1317 )?;" 1318 ); 1319 } 1320 for f in self.import_functions.iter() { 1321 self.src.push_str(&f.add_to_linker); 1322 self.src.push_str("\n"); 1323 } 1324 uwriteln!(self.src, "Ok(())\n}}"); 1325 } 1326 1327 let host_bounds = format!("U: {}", self.world_host_traits(resolve, world).join(" + ")); 1328 1329 if !self.opts.skip_mut_forwarding_impls { 1330 uwriteln!( 1331 self.src, 1332 " 1333 pub fn add_to_linker<T, U>( 1334 linker: &mut {wt}::component::Linker<T>, 1335 get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, 1336 ) -> {wt}::Result<()> 1337 where 1338 {data_bounds} 1339 {host_bounds} 1340 {{ 1341 " 1342 ); 1343 if has_world_imports_trait { 1344 uwriteln!( 1345 self.src, 1346 "Self::add_to_linker_imports_get_host(linker, get)?;" 1347 ); 1348 } 1349 for path in self.import_interface_paths() { 1350 uwriteln!(self.src, "{path}::add_to_linker(linker, get)?;"); 1351 } 1352 uwriteln!(self.src, "Ok(())\n}}"); 1353 } 1354 } 1355 } 1356 1357 struct InterfaceGenerator<'a> { 1358 src: Source, 1359 gen: &'a mut Wasmtime, 1360 resolve: &'a Resolve, 1361 current_interface: Option<(InterfaceId, &'a WorldKey, bool)>, 1362 } 1363 1364 impl<'a> InterfaceGenerator<'a> { 1365 fn new(gen: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> { 1366 InterfaceGenerator { 1367 src: Source::default(), 1368 gen, 1369 resolve, 1370 current_interface: None, 1371 } 1372 } 1373 1374 fn types_imported(&self) -> bool { 1375 match self.current_interface { 1376 Some((_, _, is_export)) => !is_export, 1377 None => true, 1378 } 1379 } 1380 1381 fn types(&mut self, id: InterfaceId) { 1382 for (name, id) in self.resolve.interfaces[id].types.iter() { 1383 self.define_type(name, *id); 1384 } 1385 } 1386 1387 fn define_type(&mut self, name: &str, id: TypeId) { 1388 let ty = &self.resolve.types[id]; 1389 match &ty.kind { 1390 TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs), 1391 TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs), 1392 TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs), 1393 TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs), 1394 TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs), 1395 TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs), 1396 TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs), 1397 TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs), 1398 TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs), 1399 TypeDefKind::Future(_) => todo!("generate for future"), 1400 TypeDefKind::Stream(_) => todo!("generate for stream"), 1401 TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs), 1402 TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs), 1403 TypeDefKind::Unknown => unreachable!(), 1404 } 1405 } 1406 1407 fn type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs) { 1408 self.rustdoc(docs); 1409 let name = name.to_upper_camel_case(); 1410 uwriteln!(self.src, "pub type {name} = "); 1411 self.print_handle(handle); 1412 self.push_str(";\n"); 1413 self.assert_type(id, &name); 1414 } 1415 1416 fn type_resource(&mut self, id: TypeId, name: &str, resource: &TypeDef, docs: &Docs) { 1417 let camel = name.to_upper_camel_case(); 1418 let wt = self.gen.wasmtime_path(); 1419 1420 if self.types_imported() { 1421 self.rustdoc(docs); 1422 1423 let replacement = match self.current_interface { 1424 Some((_, key, _)) => self.gen.lookup_replacement(self.resolve, key, Some(name)), 1425 None => { 1426 self.gen.used_with_opts.insert(name.into()); 1427 self.gen.opts.with.get(name).cloned() 1428 } 1429 }; 1430 match replacement { 1431 Some(path) => { 1432 uwriteln!( 1433 self.src, 1434 "pub use {}{path} as {camel};", 1435 self.path_to_root() 1436 ); 1437 } 1438 None => { 1439 uwriteln!(self.src, "pub enum {camel} {{}}"); 1440 } 1441 } 1442 1443 // Generate resource trait 1444 if self.gen.opts.async_.maybe_async() { 1445 uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]") 1446 } 1447 uwriteln!(self.src, "pub trait Host{camel} {{"); 1448 1449 let mut functions = match resource.owner { 1450 TypeOwner::World(id) => self.resolve.worlds[id] 1451 .imports 1452 .values() 1453 .filter_map(|item| match item { 1454 WorldItem::Function(f) => Some(f), 1455 _ => None, 1456 }) 1457 .collect(), 1458 TypeOwner::Interface(id) => self.resolve.interfaces[id] 1459 .functions 1460 .values() 1461 .collect::<Vec<_>>(), 1462 TypeOwner::None => { 1463 panic!("A resource must be owned by a world or interface"); 1464 } 1465 }; 1466 1467 functions.retain(|func| match func.kind { 1468 FunctionKind::Freestanding => false, 1469 FunctionKind::Method(resource) 1470 | FunctionKind::Static(resource) 1471 | FunctionKind::Constructor(resource) => id == resource, 1472 }); 1473 1474 for func in &functions { 1475 self.generate_function_trait_sig(func); 1476 self.push_str(";\n"); 1477 } 1478 1479 uwrite!( 1480 self.src, 1481 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()>;" 1482 ); 1483 1484 uwriteln!(self.src, "}}"); 1485 1486 // Generate impl HostResource for &mut HostResource 1487 if !self.gen.opts.skip_mut_forwarding_impls { 1488 let (async_trait, maybe_send) = if self.gen.opts.async_.maybe_async() { 1489 ( 1490 format!("#[{wt}::component::__internal::async_trait]\n"), 1491 "+ Send", 1492 ) 1493 } else { 1494 (String::new(), "") 1495 }; 1496 uwriteln!( 1497 self.src, 1498 "{async_trait}impl <_T: Host{camel} + ?Sized {maybe_send}> Host{camel} for &mut _T {{" 1499 ); 1500 for func in &functions { 1501 self.generate_function_trait_sig(func); 1502 uwrite!( 1503 self.src, 1504 "{{ Host{camel}::{}(*self,", 1505 rust_function_name(func) 1506 ); 1507 for (name, _) in func.params.iter() { 1508 uwrite!(self.src, "{},", to_rust_ident(name)); 1509 } 1510 uwrite!(self.src, ")"); 1511 if self.gen.opts.async_.is_import_async(&func.name) { 1512 uwrite!(self.src, ".await"); 1513 } 1514 uwriteln!(self.src, "}}"); 1515 } 1516 uwriteln!(self.src, " 1517 fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{ 1518 Host{camel}::drop(*self, rep) 1519 }}", 1520 ); 1521 uwriteln!(self.src, "}}"); 1522 } 1523 } else { 1524 self.rustdoc(docs); 1525 uwriteln!( 1526 self.src, 1527 " 1528 pub type {camel} = {wt}::component::ResourceAny; 1529 1530 pub struct Guest{camel}<'a> {{ 1531 funcs: &'a Guest, 1532 }} 1533 " 1534 ); 1535 } 1536 } 1537 1538 fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) { 1539 let info = self.info(id); 1540 let wt = self.gen.wasmtime_path(); 1541 1542 // We use a BTree set to make sure we don't have any duplicates and we have a stable order 1543 let additional_derives: BTreeSet<String> = self 1544 .gen 1545 .opts 1546 .additional_derive_attributes 1547 .iter() 1548 .cloned() 1549 .collect(); 1550 1551 for (name, mode) in self.modes_of(id) { 1552 let lt = self.lifetime_for(&info, mode); 1553 self.rustdoc(docs); 1554 1555 let mut derives = additional_derives.clone(); 1556 1557 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 1558 if lt.is_none() { 1559 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 1560 } 1561 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 1562 self.push_str("#[component(record)]\n"); 1563 if let Some(path) = &self.gen.opts.wasmtime_crate { 1564 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 1565 } 1566 1567 if info.is_copy() { 1568 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string())); 1569 } else if info.is_clone() { 1570 derives.insert("Clone".to_string()); 1571 } 1572 1573 if !derives.is_empty() { 1574 self.push_str("#[derive("); 1575 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 1576 self.push_str(")]\n") 1577 } 1578 1579 self.push_str(&format!("pub struct {}", name)); 1580 self.print_generics(lt); 1581 self.push_str(" {\n"); 1582 for field in record.fields.iter() { 1583 self.rustdoc(&field.docs); 1584 self.push_str(&format!("#[component(name = \"{}\")]\n", field.name)); 1585 self.push_str("pub "); 1586 self.push_str(&to_rust_ident(&field.name)); 1587 self.push_str(": "); 1588 self.print_ty(&field.ty, mode); 1589 self.push_str(",\n"); 1590 } 1591 self.push_str("}\n"); 1592 1593 self.push_str("impl"); 1594 self.print_generics(lt); 1595 self.push_str(" core::fmt::Debug for "); 1596 self.push_str(&name); 1597 self.print_generics(lt); 1598 self.push_str(" {\n"); 1599 self.push_str( 1600 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1601 ); 1602 self.push_str(&format!("f.debug_struct(\"{}\")", name)); 1603 for field in record.fields.iter() { 1604 self.push_str(&format!( 1605 ".field(\"{}\", &self.{})", 1606 field.name, 1607 to_rust_ident(&field.name) 1608 )); 1609 } 1610 self.push_str(".finish()\n"); 1611 self.push_str("}\n"); 1612 self.push_str("}\n"); 1613 1614 if info.error { 1615 self.push_str("impl"); 1616 self.print_generics(lt); 1617 self.push_str(" core::fmt::Display for "); 1618 self.push_str(&name); 1619 self.print_generics(lt); 1620 self.push_str(" {\n"); 1621 self.push_str( 1622 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1623 ); 1624 self.push_str("write!(f, \"{:?}\", self)\n"); 1625 self.push_str("}\n"); 1626 self.push_str("}\n"); 1627 1628 if cfg!(feature = "std") { 1629 self.push_str("impl std::error::Error for "); 1630 self.push_str(&name); 1631 self.push_str("{}\n"); 1632 } 1633 } 1634 self.assert_type(id, &name); 1635 } 1636 } 1637 1638 fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) { 1639 let info = self.info(id); 1640 for (name, mode) in self.modes_of(id) { 1641 let lt = self.lifetime_for(&info, mode); 1642 self.rustdoc(docs); 1643 self.push_str(&format!("pub type {}", name)); 1644 self.print_generics(lt); 1645 self.push_str(" = ("); 1646 for ty in tuple.types.iter() { 1647 self.print_ty(ty, mode); 1648 self.push_str(","); 1649 } 1650 self.push_str(");\n"); 1651 self.assert_type(id, &name); 1652 } 1653 } 1654 1655 fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) { 1656 self.rustdoc(docs); 1657 let wt = self.gen.wasmtime_path(); 1658 let rust_name = to_rust_upper_camel_case(name); 1659 uwriteln!(self.src, "{wt}::component::flags!(\n"); 1660 self.src.push_str(&format!("{rust_name} {{\n")); 1661 for flag in flags.flags.iter() { 1662 // TODO wasmtime-component-macro doesn't support docs for flags rn 1663 uwrite!( 1664 self.src, 1665 "#[component(name=\"{}\")] const {};\n", 1666 flag.name, 1667 flag.name.to_shouty_snake_case() 1668 ); 1669 } 1670 self.src.push_str("}\n"); 1671 self.src.push_str(");\n\n"); 1672 self.assert_type(id, &rust_name); 1673 } 1674 1675 fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) { 1676 self.print_rust_enum( 1677 id, 1678 variant.cases.iter().map(|c| { 1679 ( 1680 c.name.to_upper_camel_case(), 1681 Some(c.name.clone()), 1682 &c.docs, 1683 c.ty.as_ref(), 1684 ) 1685 }), 1686 docs, 1687 "variant", 1688 ); 1689 } 1690 1691 fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) { 1692 let info = self.info(id); 1693 1694 for (name, mode) in self.modes_of(id) { 1695 self.rustdoc(docs); 1696 let lt = self.lifetime_for(&info, mode); 1697 self.push_str(&format!("pub type {}", name)); 1698 self.print_generics(lt); 1699 self.push_str("= Option<"); 1700 self.print_ty(payload, mode); 1701 self.push_str(">;\n"); 1702 self.assert_type(id, &name); 1703 } 1704 } 1705 1706 // Emit a double-check that the wit-parser-understood size of a type agrees 1707 // with the Wasmtime-understood size of a type. 1708 fn assert_type(&mut self, id: TypeId, name: &str) { 1709 self.push_str("const _: () = {\n"); 1710 let wt = self.gen.wasmtime_path(); 1711 uwriteln!( 1712 self.src, 1713 "assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);", 1714 self.gen.sizes.size(&Type::Id(id)), 1715 ); 1716 uwriteln!( 1717 self.src, 1718 "assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);", 1719 self.gen.sizes.align(&Type::Id(id)), 1720 ); 1721 self.push_str("};\n"); 1722 } 1723 1724 fn print_rust_enum<'b>( 1725 &mut self, 1726 id: TypeId, 1727 cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone, 1728 docs: &Docs, 1729 derive_component: &str, 1730 ) where 1731 Self: Sized, 1732 { 1733 let info = self.info(id); 1734 let wt = self.gen.wasmtime_path(); 1735 1736 // We use a BTree set to make sure we don't have any duplicates and we have a stable order 1737 let additional_derives: BTreeSet<String> = self 1738 .gen 1739 .opts 1740 .additional_derive_attributes 1741 .iter() 1742 .cloned() 1743 .collect(); 1744 1745 for (name, mode) in self.modes_of(id) { 1746 let name = to_rust_upper_camel_case(&name); 1747 1748 let mut derives = additional_derives.clone(); 1749 1750 self.rustdoc(docs); 1751 let lt = self.lifetime_for(&info, mode); 1752 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 1753 if lt.is_none() { 1754 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 1755 } 1756 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 1757 self.push_str(&format!("#[component({})]\n", derive_component)); 1758 if let Some(path) = &self.gen.opts.wasmtime_crate { 1759 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 1760 } 1761 if info.is_copy() { 1762 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string())); 1763 } else if info.is_clone() { 1764 derives.insert("Clone".to_string()); 1765 } 1766 1767 if !derives.is_empty() { 1768 self.push_str("#[derive("); 1769 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 1770 self.push_str(")]\n") 1771 } 1772 1773 self.push_str(&format!("pub enum {name}")); 1774 self.print_generics(lt); 1775 self.push_str("{\n"); 1776 for (case_name, component_name, docs, payload) in cases.clone() { 1777 self.rustdoc(docs); 1778 if let Some(n) = component_name { 1779 self.push_str(&format!("#[component(name = \"{}\")] ", n)); 1780 } 1781 self.push_str(&case_name); 1782 if let Some(ty) = payload { 1783 self.push_str("("); 1784 self.print_ty(ty, mode); 1785 self.push_str(")") 1786 } 1787 self.push_str(",\n"); 1788 } 1789 self.push_str("}\n"); 1790 1791 self.print_rust_enum_debug( 1792 id, 1793 mode, 1794 &name, 1795 cases 1796 .clone() 1797 .into_iter() 1798 .map(|(name, _attr, _docs, ty)| (name, ty)), 1799 ); 1800 1801 if info.error { 1802 self.push_str("impl"); 1803 self.print_generics(lt); 1804 self.push_str(" core::fmt::Display for "); 1805 self.push_str(&name); 1806 self.print_generics(lt); 1807 self.push_str(" {\n"); 1808 self.push_str( 1809 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1810 ); 1811 self.push_str("write!(f, \"{:?}\", self)"); 1812 self.push_str("}\n"); 1813 self.push_str("}\n"); 1814 self.push_str("\n"); 1815 1816 if cfg!(feature = "std") { 1817 self.push_str("impl"); 1818 self.print_generics(lt); 1819 self.push_str(" std::error::Error for "); 1820 self.push_str(&name); 1821 self.print_generics(lt); 1822 self.push_str(" {}\n"); 1823 } 1824 } 1825 1826 self.assert_type(id, &name); 1827 } 1828 } 1829 1830 fn print_rust_enum_debug<'b>( 1831 &mut self, 1832 id: TypeId, 1833 mode: TypeMode, 1834 name: &str, 1835 cases: impl IntoIterator<Item = (String, Option<&'b Type>)>, 1836 ) where 1837 Self: Sized, 1838 { 1839 let info = self.info(id); 1840 let lt = self.lifetime_for(&info, mode); 1841 self.push_str("impl"); 1842 self.print_generics(lt); 1843 self.push_str(" core::fmt::Debug for "); 1844 self.push_str(name); 1845 self.print_generics(lt); 1846 self.push_str(" {\n"); 1847 self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n"); 1848 self.push_str("match self {\n"); 1849 for (case_name, payload) in cases { 1850 self.push_str(name); 1851 self.push_str("::"); 1852 self.push_str(&case_name); 1853 if payload.is_some() { 1854 self.push_str("(e)"); 1855 } 1856 self.push_str(" => {\n"); 1857 self.push_str(&format!("f.debug_tuple(\"{}::{}\")", name, case_name)); 1858 if payload.is_some() { 1859 self.push_str(".field(e)"); 1860 } 1861 self.push_str(".finish()\n"); 1862 self.push_str("}\n"); 1863 } 1864 self.push_str("}\n"); 1865 self.push_str("}\n"); 1866 self.push_str("}\n"); 1867 } 1868 1869 fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) { 1870 let info = self.info(id); 1871 1872 for (name, mode) in self.modes_of(id) { 1873 self.rustdoc(docs); 1874 let lt = self.lifetime_for(&info, mode); 1875 self.push_str(&format!("pub type {}", name)); 1876 self.print_generics(lt); 1877 self.push_str("= Result<"); 1878 self.print_optional_ty(result.ok.as_ref(), mode); 1879 self.push_str(","); 1880 self.print_optional_ty(result.err.as_ref(), mode); 1881 self.push_str(">;\n"); 1882 self.assert_type(id, &name); 1883 } 1884 } 1885 1886 fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) { 1887 let info = self.info(id); 1888 let wt = self.gen.wasmtime_path(); 1889 1890 // We use a BTree set to make sure we don't have any duplicates and have a stable order 1891 let mut derives: BTreeSet<String> = self 1892 .gen 1893 .opts 1894 .additional_derive_attributes 1895 .iter() 1896 .cloned() 1897 .collect(); 1898 1899 derives.extend( 1900 ["Clone", "Copy", "PartialEq", "Eq"] 1901 .into_iter() 1902 .map(|s| s.to_string()), 1903 ); 1904 1905 let name = to_rust_upper_camel_case(name); 1906 self.rustdoc(docs); 1907 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 1908 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 1909 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 1910 self.push_str("#[component(enum)]\n"); 1911 if let Some(path) = &self.gen.opts.wasmtime_crate { 1912 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 1913 } 1914 1915 self.push_str("#[derive("); 1916 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 1917 self.push_str(")]\n"); 1918 1919 self.push_str(&format!("pub enum {} {{\n", name)); 1920 for case in enum_.cases.iter() { 1921 self.rustdoc(&case.docs); 1922 self.push_str(&format!("#[component(name = \"{}\")]", case.name)); 1923 self.push_str(&case.name.to_upper_camel_case()); 1924 self.push_str(",\n"); 1925 } 1926 self.push_str("}\n"); 1927 1928 // Auto-synthesize an implementation of the standard `Error` trait for 1929 // error-looking types based on their name. 1930 if info.error { 1931 self.push_str("impl "); 1932 self.push_str(&name); 1933 self.push_str("{\n"); 1934 1935 self.push_str("pub fn name(&self) -> &'static str {\n"); 1936 self.push_str("match self {\n"); 1937 for case in enum_.cases.iter() { 1938 self.push_str(&name); 1939 self.push_str("::"); 1940 self.push_str(&case.name.to_upper_camel_case()); 1941 self.push_str(" => \""); 1942 self.push_str(case.name.as_str()); 1943 self.push_str("\",\n"); 1944 } 1945 self.push_str("}\n"); 1946 self.push_str("}\n"); 1947 1948 self.push_str("pub fn message(&self) -> &'static str {\n"); 1949 self.push_str("match self {\n"); 1950 for case in enum_.cases.iter() { 1951 self.push_str(&name); 1952 self.push_str("::"); 1953 self.push_str(&case.name.to_upper_camel_case()); 1954 self.push_str(" => \""); 1955 if let Some(contents) = &case.docs.contents { 1956 self.push_str(contents.trim()); 1957 } 1958 self.push_str("\",\n"); 1959 } 1960 self.push_str("}\n"); 1961 self.push_str("}\n"); 1962 1963 self.push_str("}\n"); 1964 1965 self.push_str("impl core::fmt::Debug for "); 1966 self.push_str(&name); 1967 self.push_str( 1968 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1969 ); 1970 self.push_str("f.debug_struct(\""); 1971 self.push_str(&name); 1972 self.push_str("\")\n"); 1973 self.push_str(".field(\"code\", &(*self as i32))\n"); 1974 self.push_str(".field(\"name\", &self.name())\n"); 1975 self.push_str(".field(\"message\", &self.message())\n"); 1976 self.push_str(".finish()\n"); 1977 self.push_str("}\n"); 1978 self.push_str("}\n"); 1979 1980 self.push_str("impl core::fmt::Display for "); 1981 self.push_str(&name); 1982 self.push_str( 1983 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1984 ); 1985 self.push_str("write!(f, \"{} (error {})\", self.name(), *self as i32)"); 1986 self.push_str("}\n"); 1987 self.push_str("}\n"); 1988 self.push_str("\n"); 1989 if cfg!(feature = "std") { 1990 self.push_str("impl std::error::Error for "); 1991 self.push_str(&name); 1992 self.push_str("{}\n"); 1993 } 1994 } else { 1995 self.print_rust_enum_debug( 1996 id, 1997 TypeMode::Owned, 1998 &name, 1999 enum_ 2000 .cases 2001 .iter() 2002 .map(|c| (c.name.to_upper_camel_case(), None)), 2003 ) 2004 } 2005 self.assert_type(id, &name); 2006 } 2007 2008 fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { 2009 let info = self.info(id); 2010 for (name, mode) in self.modes_of(id) { 2011 self.rustdoc(docs); 2012 self.push_str(&format!("pub type {}", name)); 2013 let lt = self.lifetime_for(&info, mode); 2014 self.print_generics(lt); 2015 self.push_str(" = "); 2016 self.print_ty(ty, mode); 2017 self.push_str(";\n"); 2018 let def_id = resolve_type_definition_id(self.resolve, id); 2019 if !matches!(self.resolve().types[def_id].kind, TypeDefKind::Resource) { 2020 self.assert_type(id, &name); 2021 } 2022 } 2023 } 2024 2025 fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { 2026 let info = self.info(id); 2027 for (name, mode) in self.modes_of(id) { 2028 let lt = self.lifetime_for(&info, mode); 2029 self.rustdoc(docs); 2030 self.push_str(&format!("pub type {}", name)); 2031 self.print_generics(lt); 2032 self.push_str(" = "); 2033 self.print_list(ty, mode); 2034 self.push_str(";\n"); 2035 self.assert_type(id, &name); 2036 } 2037 } 2038 2039 fn print_result_ty(&mut self, results: &Results, mode: TypeMode) { 2040 match results { 2041 Results::Named(rs) => match rs.len() { 2042 0 => self.push_str("()"), 2043 1 => self.print_ty(&rs[0].1, mode), 2044 _ => { 2045 self.push_str("("); 2046 for (i, (_, ty)) in rs.iter().enumerate() { 2047 if i > 0 { 2048 self.push_str(", ") 2049 } 2050 self.print_ty(ty, mode) 2051 } 2052 self.push_str(")"); 2053 } 2054 }, 2055 Results::Anon(ty) => self.print_ty(ty, mode), 2056 } 2057 } 2058 2059 fn special_case_trappable_error( 2060 &self, 2061 results: &Results, 2062 ) -> Option<(&'a Result_, TypeId, String)> { 2063 // We fillin a special trappable error type in the case when a function has just one 2064 // result, which is itself a `result<a, e>`, and the `e` is *not* a primitive 2065 // (i.e. defined in std) type, and matches the typename given by the user. 2066 let mut i = results.iter_types(); 2067 let id = match i.next()? { 2068 Type::Id(id) => id, 2069 _ => return None, 2070 }; 2071 if i.next().is_some() { 2072 return None; 2073 } 2074 let result = match &self.resolve.types[*id].kind { 2075 TypeDefKind::Result(r) => r, 2076 _ => return None, 2077 }; 2078 let error_typeid = match result.err? { 2079 Type::Id(id) => resolve_type_definition_id(&self.resolve, id), 2080 _ => return None, 2081 }; 2082 2083 let name = self.gen.trappable_errors.get(&error_typeid)?; 2084 2085 let mut path = self.path_to_root(); 2086 uwrite!(path, "{name}"); 2087 Some((result, error_typeid, path)) 2088 } 2089 2090 fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) { 2091 let iface = &self.resolve.interfaces[id]; 2092 let owner = TypeOwner::Interface(id); 2093 let wt = self.gen.wasmtime_path(); 2094 2095 let is_maybe_async = self.gen.opts.async_.maybe_async(); 2096 if is_maybe_async { 2097 uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]") 2098 } 2099 // Generate the `pub trait` which represents the host functionality for 2100 // this import which additionally inherits from all resource traits 2101 // for this interface defined by `type_resource`. 2102 uwrite!(self.src, "pub trait Host"); 2103 let mut host_supertraits = vec![]; 2104 if is_maybe_async { 2105 host_supertraits.push("Send".to_string()); 2106 } 2107 for resource in get_resources(self.resolve, id) { 2108 host_supertraits.push(format!("Host{}", resource.to_upper_camel_case())); 2109 } 2110 if !host_supertraits.is_empty() { 2111 uwrite!(self.src, ": {}", host_supertraits.join(" + ")); 2112 } 2113 uwriteln!(self.src, " {{"); 2114 for (_, func) in iface.functions.iter() { 2115 match func.kind { 2116 FunctionKind::Freestanding => {} 2117 _ => continue, 2118 } 2119 self.generate_function_trait_sig(func); 2120 self.push_str(";\n"); 2121 } 2122 2123 // Generate `convert_*` functions to convert custom trappable errors 2124 // into the representation required by Wasmtime's component API. 2125 let mut required_conversion_traits = IndexSet::new(); 2126 let mut errors_converted = IndexMap::new(); 2127 let my_error_types = iface 2128 .types 2129 .iter() 2130 .filter(|(_, id)| self.gen.trappable_errors.contains_key(*id)) 2131 .map(|(_, id)| *id); 2132 let used_error_types = iface 2133 .functions 2134 .iter() 2135 .filter_map(|(_, func)| self.special_case_trappable_error(&func.results)) 2136 .map(|(_, id, _)| id); 2137 let root = self.path_to_root(); 2138 for err_id in my_error_types.chain(used_error_types).collect::<Vec<_>>() { 2139 let custom_name = &self.gen.trappable_errors[&err_id]; 2140 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err_id)]; 2141 let err_name = err.name.as_ref().unwrap(); 2142 let err_snake = err_name.to_snake_case(); 2143 let err_camel = err_name.to_upper_camel_case(); 2144 let owner = match err.owner { 2145 TypeOwner::Interface(i) => i, 2146 _ => unimplemented!(), 2147 }; 2148 match self.path_to_interface(owner) { 2149 Some(path) => { 2150 required_conversion_traits.insert(format!("{path}::Host")); 2151 } 2152 None => { 2153 if errors_converted.insert(err_name, err_id).is_none() { 2154 uwriteln!( 2155 self.src, 2156 "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{err_camel}>;" 2157 ); 2158 } 2159 } 2160 } 2161 } 2162 uwriteln!(self.src, "}}"); 2163 2164 let (data_bounds, mut host_bounds) = if self.gen.opts.is_store_data_send() { 2165 ("T: Send,", "Host + Send".to_string()) 2166 } else { 2167 ("", "Host".to_string()) 2168 }; 2169 for ty in required_conversion_traits { 2170 uwrite!(host_bounds, " + {ty}"); 2171 } 2172 2173 uwriteln!( 2174 self.src, 2175 " 2176 pub trait GetHost<T>: 2177 Fn(T) -> <Self as GetHost<T>>::Host 2178 + Send 2179 + Sync 2180 + Copy 2181 + 'static 2182 {{ 2183 type Host: {host_bounds}; 2184 }} 2185 2186 impl<F, T, O> GetHost<T> for F 2187 where 2188 F: Fn(T) -> O + Send + Sync + Copy + 'static, 2189 O: {host_bounds}, 2190 {{ 2191 type Host = O; 2192 }} 2193 2194 pub fn add_to_linker_get_host<T>( 2195 linker: &mut {wt}::component::Linker<T>, 2196 host_getter: impl for<'a> GetHost<&'a mut T>, 2197 ) -> {wt}::Result<()> 2198 where {data_bounds} 2199 {{ 2200 " 2201 ); 2202 uwriteln!(self.src, "let mut inst = linker.instance(\"{name}\")?;"); 2203 2204 for name in get_resources(self.resolve, id) { 2205 let camel = name.to_upper_camel_case(); 2206 uwriteln!( 2207 self.src, 2208 "inst.resource( 2209 \"{name}\", 2210 {wt}::component::ResourceType::host::<{camel}>(), 2211 move |mut store, rep| -> {wt}::Result<()> {{ 2212 Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)) 2213 }}, 2214 )?;" 2215 ) 2216 } 2217 2218 for (_, func) in iface.functions.iter() { 2219 self.generate_add_function_to_linker(owner, func, "inst"); 2220 } 2221 uwriteln!(self.src, "Ok(())"); 2222 uwriteln!(self.src, "}}"); 2223 2224 if !self.gen.opts.skip_mut_forwarding_impls { 2225 // Generate add_to_linker (with closure) 2226 uwriteln!( 2227 self.src, 2228 " 2229 pub fn add_to_linker<T, U>( 2230 linker: &mut {wt}::component::Linker<T>, 2231 get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, 2232 ) -> {wt}::Result<()> 2233 where 2234 U: {host_bounds}, {data_bounds} 2235 {{ 2236 add_to_linker_get_host(linker, get) 2237 }} 2238 " 2239 ); 2240 2241 // Generate impl Host for &mut Host 2242 let (async_trait, maybe_send) = if is_maybe_async { 2243 ( 2244 format!("#[{wt}::component::__internal::async_trait]"), 2245 "+ Send", 2246 ) 2247 } else { 2248 (String::new(), "") 2249 }; 2250 2251 uwriteln!( 2252 self.src, 2253 "{async_trait}impl<_T: Host + ?Sized {maybe_send}> Host for &mut _T {{" 2254 ); 2255 // Forward each method call to &mut T 2256 for (_, func) in iface.functions.iter() { 2257 match func.kind { 2258 FunctionKind::Freestanding => {} 2259 _ => continue, 2260 } 2261 self.generate_function_trait_sig(func); 2262 uwrite!(self.src, "{{ Host::{}(*self,", rust_function_name(func)); 2263 for (name, _) in func.params.iter() { 2264 uwrite!(self.src, "{},", to_rust_ident(name)); 2265 } 2266 uwrite!(self.src, ")"); 2267 if self.gen.opts.async_.is_import_async(&func.name) { 2268 uwrite!(self.src, ".await"); 2269 } 2270 uwriteln!(self.src, "}}"); 2271 } 2272 for (err_name, err_id) in errors_converted { 2273 uwriteln!( 2274 self.src, 2275 "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{err_camel}> {{ 2276 Host::convert_{err_snake}(*self, err) 2277 }}", 2278 custom_name = self.gen.trappable_errors[&err_id], 2279 err_snake = err_name.to_snake_case(), 2280 err_camel = err_name.to_upper_camel_case(), 2281 ); 2282 } 2283 uwriteln!(self.src, "}}"); 2284 } 2285 } 2286 2287 fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) { 2288 uwrite!( 2289 self.src, 2290 "{linker}.{}(\"{}\", ", 2291 if self.gen.opts.async_.is_import_async(&func.name) { 2292 "func_wrap_async" 2293 } else { 2294 "func_wrap" 2295 }, 2296 func.name 2297 ); 2298 self.generate_guest_import_closure(owner, func); 2299 uwriteln!(self.src, ")?;") 2300 } 2301 2302 fn generate_guest_import_closure(&mut self, owner: TypeOwner, func: &Function) { 2303 // Generate the closure that's passed to a `Linker`, the final piece of 2304 // codegen here. 2305 2306 let wt = self.gen.wasmtime_path(); 2307 uwrite!( 2308 self.src, 2309 "move |mut caller: {wt}::StoreContextMut<'_, T>, (" 2310 ); 2311 for (i, _param) in func.params.iter().enumerate() { 2312 uwrite!(self.src, "arg{},", i); 2313 } 2314 self.src.push_str(") : ("); 2315 2316 for (_, ty) in func.params.iter() { 2317 // Lift is required to be impled for this type, so we can't use 2318 // a borrowed type: 2319 self.print_ty(ty, TypeMode::Owned); 2320 self.src.push_str(", "); 2321 } 2322 self.src.push_str(") |"); 2323 if self.gen.opts.async_.is_import_async(&func.name) { 2324 uwriteln!( 2325 self.src, 2326 " {wt}::component::__internal::Box::new(async move {{ " 2327 ); 2328 } else { 2329 self.src.push_str(" { \n"); 2330 } 2331 2332 if self.gen.opts.tracing { 2333 uwrite!( 2334 self.src, 2335 " 2336 let span = tracing::span!( 2337 tracing::Level::TRACE, 2338 \"wit-bindgen import\", 2339 module = \"{}\", 2340 function = \"{}\", 2341 ); 2342 let _enter = span.enter(); 2343 ", 2344 match owner { 2345 TypeOwner::Interface(id) => self.resolve.interfaces[id] 2346 .name 2347 .as_deref() 2348 .unwrap_or("<no module>"), 2349 TypeOwner::World(id) => &self.resolve.worlds[id].name, 2350 TypeOwner::None => "<no owner>", 2351 }, 2352 func.name, 2353 ); 2354 let mut event_fields = func 2355 .params 2356 .iter() 2357 .enumerate() 2358 .map(|(i, (name, _ty))| { 2359 let name = to_rust_ident(&name); 2360 format!("{name} = tracing::field::debug(&arg{i})") 2361 }) 2362 .collect::<Vec<String>>(); 2363 event_fields.push(format!("\"call\"")); 2364 uwrite!( 2365 self.src, 2366 "tracing::event!(tracing::Level::TRACE, {});\n", 2367 event_fields.join(", ") 2368 ); 2369 } 2370 2371 self.src 2372 .push_str("let host = &mut host_getter(caller.data_mut());\n"); 2373 let func_name = rust_function_name(func); 2374 let host_trait = match func.kind { 2375 FunctionKind::Freestanding => match owner { 2376 TypeOwner::World(id) => format!( 2377 "{}Imports", 2378 self.resolve.worlds[id].name.to_upper_camel_case() 2379 ), 2380 _ => "Host".to_string(), 2381 }, 2382 FunctionKind::Method(id) | FunctionKind::Static(id) | FunctionKind::Constructor(id) => { 2383 let resource = self.resolve.types[id] 2384 .name 2385 .as_ref() 2386 .unwrap() 2387 .to_upper_camel_case(); 2388 format!("Host{resource}") 2389 } 2390 }; 2391 uwrite!(self.src, "let r = {host_trait}::{func_name}(host, "); 2392 2393 for (i, _) in func.params.iter().enumerate() { 2394 uwrite!(self.src, "arg{},", i); 2395 } 2396 if self.gen.opts.async_.is_import_async(&func.name) { 2397 uwrite!(self.src, ").await;\n"); 2398 } else { 2399 uwrite!(self.src, ");\n"); 2400 } 2401 2402 if self.gen.opts.tracing { 2403 uwrite!( 2404 self.src, 2405 "tracing::event!(tracing::Level::TRACE, result = tracing::field::debug(&r), \"return\");" 2406 ); 2407 } 2408 2409 if !self.gen.opts.trappable_imports.can_trap(&func) { 2410 if func.results.iter_types().len() == 1 { 2411 uwrite!(self.src, "Ok((r,))\n"); 2412 } else { 2413 uwrite!(self.src, "Ok(r)\n"); 2414 } 2415 } else if let Some((_, err, _)) = self.special_case_trappable_error(&func.results) { 2416 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)]; 2417 let err_name = err.name.as_ref().unwrap(); 2418 let owner = match err.owner { 2419 TypeOwner::Interface(i) => i, 2420 _ => unimplemented!(), 2421 }; 2422 let convert_trait = match self.path_to_interface(owner) { 2423 Some(path) => format!("{path}::Host"), 2424 None => format!("Host"), 2425 }; 2426 let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case()); 2427 uwrite!( 2428 self.src, 2429 "Ok((match r {{ 2430 Ok(a) => Ok(a), 2431 Err(e) => Err({convert}(host, e)?), 2432 }},))" 2433 ); 2434 } else if func.results.iter_types().len() == 1 { 2435 uwrite!(self.src, "Ok((r?,))\n"); 2436 } else { 2437 uwrite!(self.src, "r\n"); 2438 } 2439 2440 if self.gen.opts.async_.is_import_async(&func.name) { 2441 // Need to close Box::new and async block 2442 self.src.push_str("})"); 2443 } else { 2444 self.src.push_str("}"); 2445 } 2446 } 2447 2448 fn generate_function_trait_sig(&mut self, func: &Function) { 2449 let wt = self.gen.wasmtime_path(); 2450 self.rustdoc(&func.docs); 2451 2452 if self.gen.opts.async_.is_import_async(&func.name) { 2453 self.push_str("async "); 2454 } 2455 self.push_str("fn "); 2456 self.push_str(&rust_function_name(func)); 2457 self.push_str("(&mut self, "); 2458 for (name, param) in func.params.iter() { 2459 let name = to_rust_ident(name); 2460 self.push_str(&name); 2461 self.push_str(": "); 2462 self.print_ty(param, TypeMode::Owned); 2463 self.push_str(","); 2464 } 2465 self.push_str(")"); 2466 self.push_str(" -> "); 2467 2468 if !self.gen.opts.trappable_imports.can_trap(func) { 2469 self.print_result_ty(&func.results, TypeMode::Owned); 2470 } else if let Some((r, _id, error_typename)) = 2471 self.special_case_trappable_error(&func.results) 2472 { 2473 // Functions which have a single result `result<ok,err>` get special 2474 // cased to use the host_wasmtime_rust::Error<err>, making it possible 2475 // for them to trap or use `?` to propagate their errors 2476 self.push_str("Result<"); 2477 if let Some(ok) = r.ok { 2478 self.print_ty(&ok, TypeMode::Owned); 2479 } else { 2480 self.push_str("()"); 2481 } 2482 self.push_str(","); 2483 self.push_str(&error_typename); 2484 self.push_str(">"); 2485 } else { 2486 // All other functions get their return values wrapped in an wasmtime::Result. 2487 // Returning the anyhow::Error case can be used to trap. 2488 uwrite!(self.src, "{wt}::Result<"); 2489 self.print_result_ty(&func.results, TypeMode::Owned); 2490 self.push_str(">"); 2491 } 2492 } 2493 2494 fn extract_typed_function(&mut self, func: &Function) -> (String, String) { 2495 let prev = mem::take(&mut self.src); 2496 let snake = func_field_name(self.resolve, func); 2497 uwrite!(self.src, "*_instance.get_typed_func::<("); 2498 for (_, ty) in func.params.iter() { 2499 self.print_ty(ty, TypeMode::AllBorrowed("'_")); 2500 self.push_str(", "); 2501 } 2502 self.src.push_str("), ("); 2503 for ty in func.results.iter_types() { 2504 self.print_ty(ty, TypeMode::Owned); 2505 self.push_str(", "); 2506 } 2507 uwriteln!(self.src, ")>(&mut store, &self.{snake})?.func()"); 2508 2509 let ret = (snake, mem::take(&mut self.src).to_string()); 2510 self.src = prev; 2511 ret 2512 } 2513 2514 fn define_rust_guest_export( 2515 &mut self, 2516 resolve: &Resolve, 2517 ns: Option<&WorldKey>, 2518 func: &Function, 2519 ) { 2520 // Exports must be async if anything could be async, it's just imports 2521 // that get to be optionally async/sync. 2522 let is_async = self.gen.opts.async_.maybe_async(); 2523 2524 let (async_, async__, await_) = if is_async { 2525 ("async", "_async", ".await") 2526 } else { 2527 ("", "", "") 2528 }; 2529 2530 self.rustdoc(&func.docs); 2531 let wt = self.gen.wasmtime_path(); 2532 2533 uwrite!( 2534 self.src, 2535 "pub {async_} fn call_{}<S: {wt}::AsContextMut>(&self, mut store: S, ", 2536 func.item_name().to_snake_case(), 2537 ); 2538 2539 for (i, param) in func.params.iter().enumerate() { 2540 uwrite!(self.src, "arg{}: ", i); 2541 self.print_ty(¶m.1, TypeMode::AllBorrowed("'_")); 2542 self.push_str(","); 2543 } 2544 2545 uwrite!(self.src, ") -> {wt}::Result<"); 2546 self.print_result_ty(&func.results, TypeMode::Owned); 2547 2548 if is_async { 2549 uwriteln!(self.src, "> where <S as {wt}::AsContext>::Data: Send {{"); 2550 } else { 2551 self.src.push_str("> {\n"); 2552 } 2553 2554 if self.gen.opts.tracing { 2555 let ns = match ns { 2556 Some(key) => resolve.name_world_key(key), 2557 None => "default".to_string(), 2558 }; 2559 self.src.push_str(&format!( 2560 " 2561 let span = tracing::span!( 2562 tracing::Level::TRACE, 2563 \"wit-bindgen export\", 2564 module = \"{ns}\", 2565 function = \"{}\", 2566 ); 2567 let _enter = span.enter(); 2568 ", 2569 func.name, 2570 )); 2571 } 2572 2573 self.src.push_str("let callee = unsafe {\n"); 2574 uwrite!(self.src, "{wt}::component::TypedFunc::<("); 2575 for (_, ty) in func.params.iter() { 2576 self.print_ty(ty, TypeMode::AllBorrowed("'_")); 2577 self.push_str(", "); 2578 } 2579 self.src.push_str("), ("); 2580 for ty in func.results.iter_types() { 2581 self.print_ty(ty, TypeMode::Owned); 2582 self.push_str(", "); 2583 } 2584 let projection_to_func = match &func.kind { 2585 FunctionKind::Freestanding => "", 2586 _ => ".funcs", 2587 }; 2588 uwriteln!( 2589 self.src, 2590 ")>::new_unchecked(self{projection_to_func}.{})", 2591 func_field_name(self.resolve, func), 2592 ); 2593 self.src.push_str("};\n"); 2594 self.src.push_str("let ("); 2595 for (i, _) in func.results.iter_types().enumerate() { 2596 uwrite!(self.src, "ret{},", i); 2597 } 2598 uwrite!( 2599 self.src, 2600 ") = callee.call{async__}(store.as_context_mut(), (" 2601 ); 2602 for (i, _) in func.params.iter().enumerate() { 2603 uwrite!(self.src, "arg{}, ", i); 2604 } 2605 uwriteln!(self.src, ")){await_}?;"); 2606 2607 uwriteln!( 2608 self.src, 2609 "callee.post_return{async__}(store.as_context_mut()){await_}?;" 2610 ); 2611 2612 self.src.push_str("Ok("); 2613 if func.results.iter_types().len() == 1 { 2614 self.src.push_str("ret0"); 2615 } else { 2616 self.src.push_str("("); 2617 for (i, _) in func.results.iter_types().enumerate() { 2618 uwrite!(self.src, "ret{},", i); 2619 } 2620 self.src.push_str(")"); 2621 } 2622 self.src.push_str(")\n"); 2623 2624 // End function body 2625 self.src.push_str("}\n"); 2626 } 2627 2628 fn rustdoc(&mut self, docs: &Docs) { 2629 let docs = match &docs.contents { 2630 Some(docs) => docs, 2631 None => return, 2632 }; 2633 for line in docs.trim().lines() { 2634 self.push_str("/// "); 2635 self.push_str(line); 2636 self.push_str("\n"); 2637 } 2638 } 2639 2640 fn path_to_root(&self) -> String { 2641 let mut path_to_root = String::new(); 2642 if let Some((_, key, is_export)) = self.current_interface { 2643 match key { 2644 WorldKey::Name(_) => { 2645 path_to_root.push_str("super::"); 2646 } 2647 WorldKey::Interface(_) => { 2648 path_to_root.push_str("super::super::super::"); 2649 } 2650 } 2651 if is_export { 2652 path_to_root.push_str("super::"); 2653 } 2654 } 2655 path_to_root 2656 } 2657 } 2658 2659 impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> { 2660 fn resolve(&self) -> &'a Resolve { 2661 self.resolve 2662 } 2663 2664 fn ownership(&self) -> Ownership { 2665 self.gen.opts.ownership 2666 } 2667 2668 fn path_to_interface(&self, interface: InterfaceId) -> Option<String> { 2669 if let Some((cur, _, _)) = self.current_interface { 2670 if cur == interface { 2671 return None; 2672 } 2673 } 2674 let mut path_to_root = self.path_to_root(); 2675 match &self.gen.interface_names[&interface] { 2676 InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root), 2677 InterfaceName::Path(path) => { 2678 for (i, name) in path.iter().enumerate() { 2679 if i > 0 { 2680 path_to_root.push_str("::"); 2681 } 2682 path_to_root.push_str(name); 2683 } 2684 } 2685 } 2686 Some(path_to_root) 2687 } 2688 2689 fn push_str(&mut self, s: &str) { 2690 self.src.push_str(s); 2691 } 2692 2693 fn info(&self, ty: TypeId) -> TypeInfo { 2694 self.gen.types.get(ty) 2695 } 2696 2697 fn is_imported_interface(&self, interface: InterfaceId) -> bool { 2698 self.gen.interface_last_seen_as_import[&interface] 2699 } 2700 2701 fn wasmtime_path(&self) -> String { 2702 self.gen.wasmtime_path() 2703 } 2704 } 2705 2706 /// When an interface `use`s a type from another interface, it creates a new TypeId 2707 /// referring to the definition TypeId. Chase this chain of references down to 2708 /// a TypeId for type's definition. 2709 fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId { 2710 loop { 2711 match resolve.types[id].kind { 2712 TypeDefKind::Type(Type::Id(def_id)) => id = def_id, 2713 _ => return id, 2714 } 2715 } 2716 } 2717 2718 fn rust_function_name(func: &Function) -> String { 2719 match func.kind { 2720 FunctionKind::Method(_) | FunctionKind::Static(_) => to_rust_ident(func.item_name()), 2721 FunctionKind::Constructor(_) => "new".to_string(), 2722 FunctionKind::Freestanding => to_rust_ident(&func.name), 2723 } 2724 } 2725 2726 fn func_field_name(resolve: &Resolve, func: &Function) -> String { 2727 let mut name = String::new(); 2728 match func.kind { 2729 FunctionKind::Method(id) => { 2730 name.push_str("method-"); 2731 name.push_str(resolve.types[id].name.as_ref().unwrap()); 2732 name.push_str("-"); 2733 } 2734 FunctionKind::Static(id) => { 2735 name.push_str("static-"); 2736 name.push_str(resolve.types[id].name.as_ref().unwrap()); 2737 name.push_str("-"); 2738 } 2739 FunctionKind::Constructor(id) => { 2740 name.push_str("constructor-"); 2741 name.push_str(resolve.types[id].name.as_ref().unwrap()); 2742 name.push_str("-"); 2743 } 2744 FunctionKind::Freestanding => {} 2745 } 2746 name.push_str(func.item_name()); 2747 name.to_snake_case() 2748 } 2749 2750 fn get_resources<'a>(resolve: &'a Resolve, id: InterfaceId) -> impl Iterator<Item = &'a str> + 'a { 2751 resolve.interfaces[id] 2752 .types 2753 .iter() 2754 .filter_map(move |(name, ty)| match resolve.types[*ty].kind { 2755 TypeDefKind::Resource => Some(name.as_str()), 2756 _ => None, 2757 }) 2758 } 2759 2760 fn get_world_resources<'a>( 2761 resolve: &'a Resolve, 2762 id: WorldId, 2763 ) -> impl Iterator<Item = &'a str> + 'a { 2764 resolve.worlds[id] 2765 .imports 2766 .iter() 2767 .filter_map(move |(name, item)| match item { 2768 WorldItem::Type(id) => match resolve.types[*id].kind { 2769 TypeDefKind::Resource => Some(match name { 2770 WorldKey::Name(s) => s.as_str(), 2771 WorldKey::Interface(_) => unreachable!(), 2772 }), 2773 _ => None, 2774 }, 2775 _ => None, 2776 }) 2777 } 2778