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