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 two values identify the interface; the third is the contents of the 63 /// module that this interface generated. The fourth value is the name of the 64 /// interface as also present in `self.interface_names`. 65 import_interfaces: Vec<(WorldKey, InterfaceId, 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 world_link_options: LinkOptionsBuilder, 79 interface_link_options: HashMap<InterfaceId, LinkOptionsBuilder>, 80 } 81 82 struct ImportFunction { 83 func: Function, 84 add_to_linker: String, 85 sig: Option<String>, 86 } 87 88 #[derive(Default)] 89 struct Exports { 90 fields: BTreeMap<String, ExportField>, 91 modules: Vec<(InterfaceId, String, InterfaceName)>, 92 funcs: Vec<String>, 93 } 94 95 struct ExportField { 96 ty: String, 97 ty_index: String, 98 load: String, 99 get_index_from_component: String, 100 get_index_from_instance: String, 101 } 102 103 #[derive(Default, Debug, Clone, Copy)] 104 pub enum Ownership { 105 /// Generated types will be composed entirely of owning fields, regardless 106 /// of whether they are used as parameters to guest exports or not. 107 #[default] 108 Owning, 109 110 /// Generated types used as parameters to guest exports will be "deeply 111 /// borrowing", i.e. contain references rather than owned values when 112 /// applicable. 113 Borrowing { 114 /// Whether or not to generate "duplicate" type definitions for a single 115 /// WIT type if necessary, for example if it's used as both an import 116 /// and an export, or if it's used both as a parameter to an export and 117 /// a return value from an export. 118 duplicate_if_necessary: bool, 119 }, 120 } 121 122 #[derive(Default, Debug, Clone)] 123 pub struct Opts { 124 /// Whether or not `rustfmt` is executed to format generated code. 125 pub rustfmt: bool, 126 127 /// Whether or not to emit `tracing` macro calls on function entry/exit. 128 pub tracing: bool, 129 130 /// Whether or not `tracing` macro calls should included argument and 131 /// return values which contain dynamically-sized `list` values. 132 pub verbose_tracing: bool, 133 134 /// Whether or not to use async rust functions and traits. 135 pub async_: AsyncConfig, 136 137 /// Whether or not to use `func_wrap_concurrent` when generating code for 138 /// async imports. 139 /// 140 /// Unlike `func_wrap_async`, `func_wrap_concurrent` allows host functions 141 /// to suspend without monopolizing the `Store`, meaning other guest tasks 142 /// can make progress concurrently. 143 pub concurrent_imports: bool, 144 145 /// Whether or not to use `call_concurrent` when generating code for 146 /// async exports. 147 /// 148 /// Unlike `call_async`, `call_concurrent` allows the caller to make 149 /// multiple concurrent calls on the same component instance. 150 pub concurrent_exports: bool, 151 152 /// A list of "trappable errors" which are used to replace the `E` in 153 /// `result<T, E>` found in WIT. 154 pub trappable_error_type: Vec<TrappableError>, 155 156 /// Whether to generate owning or borrowing type definitions. 157 pub ownership: Ownership, 158 159 /// Whether or not to generate code for only the interfaces of this wit file or not. 160 pub only_interfaces: bool, 161 162 /// Configuration of which imports are allowed to generate a trap. 163 pub trappable_imports: TrappableImports, 164 165 /// Remapping of interface names to rust module names. 166 /// TODO: is there a better type to use for the value of this map? 167 pub with: HashMap<String, String>, 168 169 /// Additional derive attributes to add to generated types. If using in a CLI, this flag can be 170 /// specified multiple times to add multiple attributes. 171 /// 172 /// These derive attributes will be added to any generated structs or enums 173 pub additional_derive_attributes: Vec<String>, 174 175 /// Evaluate to a string literal containing the generated code rather than the generated tokens 176 /// themselves. Mostly useful for Wasmtime internal debugging and development. 177 pub stringify: bool, 178 179 /// Temporary option to skip `impl<T: Trait> Trait for &mut T` for the 180 /// `wasmtime-wasi` crate while that's given a chance to update its b 181 /// indings. 182 pub skip_mut_forwarding_impls: bool, 183 184 /// Indicates that the `T` in `Store<T>` should be send even if async is not 185 /// enabled. 186 /// 187 /// This is helpful when sync bindings depend on generated functions from 188 /// async bindings as is the case with WASI in-tree. 189 pub require_store_data_send: bool, 190 191 /// Path to the `wasmtime` crate if it's not the default path. 192 pub wasmtime_crate: Option<String>, 193 194 /// If true, write the generated bindings to a file for better error 195 /// messages from `rustc`. 196 /// 197 /// This can also be toggled via the `WASMTIME_DEBUG_BINDGEN` environment 198 /// variable, but that will affect _all_ `bindgen!` macro invocations (and 199 /// can sometimes lead to one invocation ovewriting another in unpredictable 200 /// ways), whereas this option lets you specify it on a case-by-case basis. 201 pub debug: bool, 202 } 203 204 #[derive(Debug, Clone)] 205 pub struct TrappableError { 206 /// Full path to the error, such as `wasi:io/streams/error`. 207 pub wit_path: String, 208 209 /// The name, in Rust, of the error type to generate. 210 pub rust_type_name: String, 211 } 212 213 /// Which imports should be generated as async functions. 214 /// 215 /// The imports should be declared in the following format: 216 /// - Regular functions: `"{function-name}"` 217 /// - Resource methods: `"[method]{resource-name}.{method-name}"` 218 /// - Resource destructors: `"[drop]{resource-name}"` 219 /// 220 /// Examples: 221 /// - Regular function: `"get-environment"` 222 /// - Resource method: `"[method]input-stream.read"` 223 /// - Resource destructor: `"[drop]input-stream"` 224 #[derive(Default, Debug, Clone)] 225 pub enum AsyncConfig { 226 /// No functions are `async`. 227 #[default] 228 None, 229 /// All generated functions should be `async`. 230 All, 231 /// These imported functions should not be async, but everything else is. 232 AllExceptImports(HashSet<String>), 233 /// These functions are the only imports that are async, all other imports 234 /// are sync. 235 /// 236 /// Note that all exports are still async in this situation. 237 OnlyImports(HashSet<String>), 238 } 239 240 pub enum CallStyle { 241 Sync, 242 Async, 243 Concurrent, 244 } 245 246 #[derive(Default, Debug, Clone)] 247 pub enum TrappableImports { 248 /// No imports are allowed to trap. 249 #[default] 250 None, 251 /// All imports may trap. 252 All, 253 /// Only the specified set of functions may trap. 254 Only(HashSet<String>), 255 } 256 257 impl TrappableImports { 258 fn can_trap(&self, f: &Function) -> bool { 259 match self { 260 TrappableImports::None => false, 261 TrappableImports::All => true, 262 TrappableImports::Only(set) => set.contains(&f.name), 263 } 264 } 265 } 266 267 impl Opts { 268 pub fn generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> { 269 // TODO: Should we refine this test to inspect only types reachable from 270 // the specified world? 271 if !cfg!(feature = "component-model-async") 272 && resolve 273 .types 274 .iter() 275 .any(|(_, ty)| matches!(ty.kind, TypeDefKind::Future(_) | TypeDefKind::Stream(_))) 276 { 277 anyhow::bail!( 278 "must enable `component-model-async` feature when using WIT files \ 279 containing future, stream, or error types" 280 ); 281 } 282 283 let mut r = Wasmtime::default(); 284 r.sizes.fill(resolve); 285 r.opts = self.clone(); 286 r.populate_world_and_interface_options(resolve, world); 287 r.generate(resolve, world) 288 } 289 290 fn is_store_data_send(&self) -> bool { 291 matches!(self.call_style(), CallStyle::Async | CallStyle::Concurrent) 292 || self.require_store_data_send 293 } 294 295 pub fn import_call_style(&self, qualifier: Option<&str>, f: &str) -> CallStyle { 296 let matched = |names: &HashSet<String>| { 297 names.contains(f) 298 || qualifier 299 .map(|v| names.contains(&format!("{v}#{f}"))) 300 .unwrap_or(false) 301 }; 302 303 match &self.async_ { 304 AsyncConfig::AllExceptImports(names) if matched(names) => CallStyle::Sync, 305 AsyncConfig::OnlyImports(names) if !matched(names) => CallStyle::Sync, 306 _ => self.call_style(), 307 } 308 } 309 310 pub fn drop_call_style(&self, qualifier: Option<&str>, r: &str) -> CallStyle { 311 self.import_call_style(qualifier, &format!("[drop]{r}")) 312 } 313 314 pub fn call_style(&self) -> CallStyle { 315 match &self.async_ { 316 AsyncConfig::None => CallStyle::Sync, 317 318 AsyncConfig::All | AsyncConfig::AllExceptImports(_) | AsyncConfig::OnlyImports(_) => { 319 if self.concurrent_imports { 320 CallStyle::Concurrent 321 } else { 322 CallStyle::Async 323 } 324 } 325 } 326 } 327 } 328 329 impl Wasmtime { 330 fn populate_world_and_interface_options(&mut self, resolve: &Resolve, world: WorldId) { 331 self.world_link_options.add_world(resolve, &world); 332 333 for (_, import) in resolve.worlds[world].imports.iter() { 334 match import { 335 WorldItem::Interface { id, .. } => { 336 let mut o = LinkOptionsBuilder::default(); 337 o.add_interface(resolve, id); 338 self.interface_link_options.insert(*id, o); 339 } 340 WorldItem::Function(_) | WorldItem::Type(_) => {} 341 } 342 } 343 } 344 fn name_interface( 345 &mut self, 346 resolve: &Resolve, 347 id: InterfaceId, 348 name: &WorldKey, 349 is_export: bool, 350 ) -> bool { 351 let mut path = Vec::new(); 352 if is_export { 353 path.push("exports".to_string()); 354 } 355 match name { 356 WorldKey::Name(name) => { 357 path.push(name.to_snake_case()); 358 } 359 WorldKey::Interface(_) => { 360 let iface = &resolve.interfaces[id]; 361 let pkgname = &resolve.packages[iface.package.unwrap()].name; 362 path.push(pkgname.namespace.to_snake_case()); 363 path.push(self.name_package_module(resolve, iface.package.unwrap())); 364 path.push(to_rust_ident(iface.name.as_ref().unwrap())); 365 } 366 } 367 let entry = if let Some(name_at_root) = self.lookup_replacement(resolve, name, None) { 368 InterfaceName::Remapped { 369 name_at_root, 370 local_path: path, 371 } 372 } else { 373 InterfaceName::Path(path) 374 }; 375 376 let remapped = matches!(entry, InterfaceName::Remapped { .. }); 377 self.interface_names.insert(id, entry); 378 remapped 379 } 380 381 /// If the package `id` is the only package with its namespace/name combo 382 /// then pass through the name unmodified. If, however, there are multiple 383 /// versions of this package then the package module is going to get version 384 /// information. 385 fn name_package_module(&self, resolve: &Resolve, id: PackageId) -> String { 386 let pkg = &resolve.packages[id]; 387 let versions_with_same_name = resolve 388 .packages 389 .iter() 390 .filter_map(|(_, p)| { 391 if p.name.namespace == pkg.name.namespace && p.name.name == pkg.name.name { 392 Some(&p.name.version) 393 } else { 394 None 395 } 396 }) 397 .collect::<Vec<_>>(); 398 let base = pkg.name.name.to_snake_case(); 399 if versions_with_same_name.len() == 1 { 400 return base; 401 } 402 403 let version = match &pkg.name.version { 404 Some(version) => version, 405 // If this package didn't have a version then don't mangle its name 406 // and other packages with the same name but with versions present 407 // will have their names mangled. 408 None => return base, 409 }; 410 411 // Here there's multiple packages with the same name that differ only in 412 // version, so the version needs to be mangled into the Rust module name 413 // that we're generating. This in theory could look at all of 414 // `versions_with_same_name` and produce a minimal diff, e.g. for 0.1.0 415 // and 0.2.0 this could generate "foo1" and "foo2", but for now 416 // a simpler path is chosen to generate "foo0_1_0" and "foo0_2_0". 417 let version = version 418 .to_string() 419 .replace('.', "_") 420 .replace('-', "_") 421 .replace('+', "_") 422 .to_snake_case(); 423 format!("{base}{version}") 424 } 425 426 fn generate(&mut self, resolve: &Resolve, id: WorldId) -> anyhow::Result<String> { 427 self.types.analyze(resolve, id); 428 429 self.world_link_options.write_struct(&mut self.src); 430 431 // Resolve the `trappable_error_type` configuration values to `TypeId` 432 // values. This is done by iterating over each `trappable_error_type` 433 // and then locating the interface that it corresponds to as well as the 434 // type within that interface. 435 // 436 // Note that `LookupItem::InterfaceNoPop` is used here as the full 437 // hierarchical behavior of `lookup_keys` isn't used as the interface 438 // must be named here. 439 'outer: for (i, te) in self.opts.trappable_error_type.iter().enumerate() { 440 let error_name = format!("_TrappableError{i}"); 441 for (id, iface) in resolve.interfaces.iter() { 442 for (key, projection) in lookup_keys( 443 resolve, 444 &WorldKey::Interface(id), 445 LookupItem::InterfaceNoPop, 446 ) { 447 assert!(projection.is_empty()); 448 449 // If `wit_path` looks like `{key}/{type_name}` where 450 // `type_name` is a type within `iface` then we've found a 451 // match. Otherwise continue to the next lookup key if there 452 // is one, and failing that continue to the next interface. 453 let suffix = match te.wit_path.strip_prefix(&key) { 454 Some(s) => s, 455 None => continue, 456 }; 457 let suffix = match suffix.strip_prefix('/') { 458 Some(s) => s, 459 None => continue, 460 }; 461 if let Some(id) = iface.types.get(suffix) { 462 uwriteln!(self.src, "type {error_name} = {};", te.rust_type_name); 463 let prev = self.trappable_errors.insert(*id, error_name); 464 assert!(prev.is_none()); 465 continue 'outer; 466 } 467 } 468 } 469 470 bail!( 471 "failed to locate a WIT error type corresponding to the \ 472 `trappable_error_type` name `{}` provided", 473 te.wit_path 474 ) 475 } 476 477 // Convert all entries in `with` as relative to the root of where the 478 // macro itself is invoked. This emits a `pub use` to bring the name 479 // into scope under an "anonymous name" which then replaces the `with` 480 // map entry. 481 let mut with = self.opts.with.iter_mut().collect::<Vec<_>>(); 482 with.sort(); 483 for (i, (_k, v)) in with.into_iter().enumerate() { 484 let name = format!("__with_name{i}"); 485 uwriteln!(self.src, "#[doc(hidden)]\npub use {v} as {name};"); 486 *v = name; 487 } 488 489 let world = &resolve.worlds[id]; 490 for (name, import) in world.imports.iter() { 491 if !self.opts.only_interfaces || matches!(import, WorldItem::Interface { .. }) { 492 self.import(resolve, id, name, import); 493 } 494 } 495 496 for (name, export) in world.exports.iter() { 497 if !self.opts.only_interfaces || matches!(export, WorldItem::Interface { .. }) { 498 self.export(resolve, name, export); 499 } 500 } 501 self.finish(resolve, id) 502 } 503 504 fn import(&mut self, resolve: &Resolve, world: WorldId, name: &WorldKey, item: &WorldItem) { 505 let mut generator = InterfaceGenerator::new(self, resolve); 506 match item { 507 WorldItem::Function(func) => { 508 // Only generate a trait signature for free functions since 509 // resource-related functions get their trait signatures 510 // during `type_resource`. 511 let sig = if let FunctionKind::Freestanding = func.kind { 512 generator.generate_function_trait_sig(func, "Data"); 513 Some(mem::take(&mut generator.src).into()) 514 } else { 515 None 516 }; 517 generator.generate_add_function_to_linker(TypeOwner::World(world), func, "linker"); 518 let add_to_linker = generator.src.into(); 519 self.import_functions.push(ImportFunction { 520 func: func.clone(), 521 sig, 522 add_to_linker, 523 }); 524 } 525 WorldItem::Interface { id, .. } => { 526 generator 527 .generator 528 .interface_last_seen_as_import 529 .insert(*id, true); 530 generator.current_interface = Some((*id, name, false)); 531 let snake = to_rust_ident(&match name { 532 WorldKey::Name(s) => s.to_snake_case(), 533 WorldKey::Interface(id) => resolve.interfaces[*id] 534 .name 535 .as_ref() 536 .unwrap() 537 .to_snake_case(), 538 }); 539 let module = if generator 540 .generator 541 .name_interface(resolve, *id, name, false) 542 { 543 // If this interface is remapped then that means that it was 544 // provided via the `with` key in the bindgen configuration. 545 // That means that bindings generation is skipped here. To 546 // accommodate future bindgens depending on this bindgen 547 // though we still generate a module which reexports the 548 // original module. This helps maintain the same output 549 // structure regardless of whether `with` is used. 550 let name_at_root = match &generator.generator.interface_names[id] { 551 InterfaceName::Remapped { name_at_root, .. } => name_at_root, 552 InterfaceName::Path(_) => unreachable!(), 553 }; 554 let path_to_root = generator.path_to_root(); 555 format!( 556 " 557 pub mod {snake} {{ 558 #[allow(unused_imports)] 559 pub use {path_to_root}{name_at_root}::*; 560 }} 561 " 562 ) 563 } else { 564 // If this interface is not remapped then it's time to 565 // actually generate bindings here. 566 generator.generator.interface_link_options[id].write_struct(&mut generator.src); 567 generator.types(*id); 568 let key_name = resolve.name_world_key(name); 569 generator.generate_add_to_linker(*id, &key_name); 570 571 let module = &generator.src[..]; 572 let wt = generator.generator.wasmtime_path(); 573 574 format!( 575 " 576 #[allow(clippy::all)] 577 pub mod {snake} {{ 578 #[allow(unused_imports)] 579 use {wt}::component::__internal::{{anyhow, Box}}; 580 581 {module} 582 }} 583 " 584 ) 585 }; 586 self.import_interfaces.push(( 587 name.clone(), 588 *id, 589 module, 590 self.interface_names[id].clone(), 591 )); 592 593 let interface_path = self.import_interface_path(id); 594 self.interface_link_options[id] 595 .write_impl_from_world(&mut self.src, &interface_path); 596 } 597 WorldItem::Type(ty) => { 598 let name = match name { 599 WorldKey::Name(name) => name, 600 WorldKey::Interface(_) => unreachable!(), 601 }; 602 generator.define_type(name, *ty); 603 let body = mem::take(&mut generator.src); 604 self.src.push_str(&body); 605 } 606 }; 607 } 608 609 fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) { 610 let wt = self.wasmtime_path(); 611 let mut generator = InterfaceGenerator::new(self, resolve); 612 let field; 613 let ty; 614 let ty_index; 615 let load; 616 let get_index_from_component; 617 let get_index_from_instance; 618 match item { 619 WorldItem::Function(func) => { 620 generator.define_rust_guest_export(resolve, None, func); 621 let body = mem::take(&mut generator.src).into(); 622 load = generator.extract_typed_function(func).1; 623 assert!(generator.src.is_empty()); 624 self.exports.funcs.push(body); 625 ty_index = format!("{wt}::component::ComponentExportIndex"); 626 field = func_field_name(resolve, func); 627 ty = format!("{wt}::component::Func"); 628 get_index_from_component = format!( 629 "_component.export_index(None, \"{}\") 630 .ok_or_else(|| anyhow::anyhow!(\"no function export `{0}` found\"))?.1", 631 func.name 632 ); 633 get_index_from_instance = format!( 634 "_instance.get_export(&mut store, None, \"{}\") 635 .ok_or_else(|| anyhow::anyhow!(\"no function export `{0}` found\"))?", 636 func.name 637 ); 638 } 639 WorldItem::Type(_) => unreachable!(), 640 WorldItem::Interface { id, .. } => { 641 generator 642 .generator 643 .interface_last_seen_as_import 644 .insert(*id, false); 645 generator.generator.name_interface(resolve, *id, name, true); 646 generator.current_interface = Some((*id, name, true)); 647 generator.types(*id); 648 let struct_name = "Guest"; 649 let iface = &resolve.interfaces[*id]; 650 let iface_name = match name { 651 WorldKey::Name(name) => name, 652 WorldKey::Interface(_) => iface.name.as_ref().unwrap(), 653 }; 654 uwriteln!(generator.src, "pub struct {struct_name} {{"); 655 for (_, func) in iface.functions.iter() { 656 uwriteln!( 657 generator.src, 658 "{}: {wt}::component::Func,", 659 func_field_name(resolve, func) 660 ); 661 } 662 uwriteln!(generator.src, "}}"); 663 664 uwriteln!(generator.src, "#[derive(Clone)]"); 665 uwriteln!(generator.src, "pub struct {struct_name}Indices {{"); 666 for (_, func) in iface.functions.iter() { 667 uwriteln!( 668 generator.src, 669 "{}: {wt}::component::ComponentExportIndex,", 670 func_field_name(resolve, func) 671 ); 672 } 673 uwriteln!(generator.src, "}}"); 674 675 uwriteln!(generator.src, "impl {struct_name}Indices {{"); 676 let instance_name = resolve.name_world_key(name); 677 uwrite!( 678 generator.src, 679 " 680 /// Constructor for [`{struct_name}Indices`] which takes a 681 /// [`Component`]({wt}::component::Component) as input and can be executed 682 /// before instantiation. 683 /// 684 /// This constructor can be used to front-load string lookups to find exports 685 /// within a component. 686 pub fn new( 687 component: &{wt}::component::Component, 688 ) -> {wt}::Result<{struct_name}Indices> {{ 689 let (_, instance) = component.export_index(None, \"{instance_name}\") 690 .ok_or_else(|| anyhow::anyhow!(\"no exported instance named `{instance_name}`\"))?; 691 Self::_new(|name| {{ 692 component.export_index(Some(&instance), name) 693 .map(|p| p.1) 694 }}) 695 }} 696 697 /// This constructor is similar to [`{struct_name}Indices::new`] except that it 698 /// performs string lookups after instantiation time. 699 pub fn new_instance( 700 mut store: impl {wt}::AsContextMut, 701 instance: &{wt}::component::Instance, 702 ) -> {wt}::Result<{struct_name}Indices> {{ 703 let instance_export = instance.get_export(&mut store, None, \"{instance_name}\") 704 .ok_or_else(|| anyhow::anyhow!(\"no exported instance named `{instance_name}`\"))?; 705 Self::_new(|name| {{ 706 instance.get_export(&mut store, Some(&instance_export), name) 707 }}) 708 }} 709 710 fn _new( 711 mut lookup: impl FnMut (&str) -> Option<{wt}::component::ComponentExportIndex>, 712 ) -> {wt}::Result<{struct_name}Indices> {{ 713 let mut lookup = move |name| {{ 714 lookup(name).ok_or_else(|| {{ 715 anyhow::anyhow!( 716 \"instance export `{instance_name}` does \\ 717 not have export `{{name}}`\" 718 ) 719 }}) 720 }}; 721 let _ = &mut lookup; 722 " 723 ); 724 let mut fields = Vec::new(); 725 for (_, func) in iface.functions.iter() { 726 let name = func_field_name(resolve, func); 727 uwriteln!(generator.src, "let {name} = lookup(\"{}\")?;", func.name); 728 fields.push(name); 729 } 730 uwriteln!(generator.src, "Ok({struct_name}Indices {{"); 731 for name in fields { 732 uwriteln!(generator.src, "{name},"); 733 } 734 uwriteln!(generator.src, "}})"); 735 uwriteln!(generator.src, "}}"); // end `fn _new` 736 737 uwrite!( 738 generator.src, 739 " 740 pub fn load( 741 &self, 742 mut store: impl {wt}::AsContextMut, 743 instance: &{wt}::component::Instance, 744 ) -> {wt}::Result<{struct_name}> {{ 745 let mut store = store.as_context_mut(); 746 let _ = &mut store; 747 let _instance = instance; 748 " 749 ); 750 let mut fields = Vec::new(); 751 for (_, func) in iface.functions.iter() { 752 let (name, getter) = generator.extract_typed_function(func); 753 uwriteln!(generator.src, "let {name} = {getter};"); 754 fields.push(name); 755 } 756 uwriteln!(generator.src, "Ok({struct_name} {{"); 757 for name in fields { 758 uwriteln!(generator.src, "{name},"); 759 } 760 uwriteln!(generator.src, "}})"); 761 uwriteln!(generator.src, "}}"); // end `fn new` 762 uwriteln!(generator.src, "}}"); // end `impl {struct_name}Indices` 763 764 uwriteln!(generator.src, "impl {struct_name} {{"); 765 let mut resource_methods = IndexMap::new(); 766 767 for (_, func) in iface.functions.iter() { 768 match func.kind.resource() { 769 None => { 770 generator.define_rust_guest_export(resolve, Some(name), func); 771 } 772 Some(id) => { 773 resource_methods.entry(id).or_insert(Vec::new()).push(func); 774 } 775 } 776 } 777 778 for (id, _) in resource_methods.iter() { 779 let name = resolve.types[*id].name.as_ref().unwrap(); 780 let snake = name.to_snake_case(); 781 let camel = name.to_upper_camel_case(); 782 uwriteln!( 783 generator.src, 784 "pub fn {snake}(&self) -> Guest{camel}<'_> {{ 785 Guest{camel} {{ funcs: self }} 786 }}" 787 ); 788 } 789 790 uwriteln!(generator.src, "}}"); 791 792 for (id, methods) in resource_methods { 793 let resource_name = resolve.types[id].name.as_ref().unwrap(); 794 let camel = resource_name.to_upper_camel_case(); 795 uwriteln!(generator.src, "impl Guest{camel}<'_> {{"); 796 for method in methods { 797 generator.define_rust_guest_export(resolve, Some(name), method); 798 } 799 uwriteln!(generator.src, "}}"); 800 } 801 802 let module = &generator.src[..]; 803 let snake = to_rust_ident(iface_name); 804 805 let module = format!( 806 " 807 #[allow(clippy::all)] 808 pub mod {snake} {{ 809 #[allow(unused_imports)] 810 use {wt}::component::__internal::{{anyhow, Box}}; 811 812 {module} 813 }} 814 " 815 ); 816 let pkgname = match name { 817 WorldKey::Name(_) => None, 818 WorldKey::Interface(_) => { 819 Some(resolve.packages[iface.package.unwrap()].name.clone()) 820 } 821 }; 822 self.exports 823 .modules 824 .push((*id, module, self.interface_names[id].clone())); 825 826 let (path, method_name) = match pkgname { 827 Some(pkgname) => ( 828 format!( 829 "exports::{}::{}::{snake}::{struct_name}", 830 pkgname.namespace.to_snake_case(), 831 self.name_package_module(resolve, iface.package.unwrap()), 832 ), 833 format!( 834 "{}_{}_{snake}", 835 pkgname.namespace.to_snake_case(), 836 self.name_package_module(resolve, iface.package.unwrap()) 837 ), 838 ), 839 None => (format!("exports::{snake}::{struct_name}"), snake.clone()), 840 }; 841 field = format!("interface{}", self.exports.fields.len()); 842 load = format!("self.{field}.load(&mut store, &_instance)?"); 843 self.exports.funcs.push(format!( 844 " 845 pub fn {method_name}(&self) -> &{path} {{ 846 &self.{field} 847 }} 848 ", 849 )); 850 ty_index = format!("{path}Indices"); 851 ty = path; 852 get_index_from_component = format!("{ty_index}::new(_component)?"); 853 get_index_from_instance = 854 format!("{ty_index}::new_instance(&mut store, _instance)?"); 855 } 856 } 857 let prev = self.exports.fields.insert( 858 field, 859 ExportField { 860 ty, 861 ty_index, 862 load, 863 get_index_from_component, 864 get_index_from_instance, 865 }, 866 ); 867 assert!(prev.is_none()); 868 } 869 870 fn build_world_struct(&mut self, resolve: &Resolve, world: WorldId) { 871 let wt = self.wasmtime_path(); 872 let world_name = &resolve.worlds[world].name; 873 let camel = to_rust_upper_camel_case(&world_name); 874 let (async_, async__, where_clause, await_) = match self.opts.call_style() { 875 CallStyle::Async => ("async", "_async", "where _T: Send", ".await"), 876 CallStyle::Concurrent => ("async", "_async", "where _T: Send + 'static", ".await"), 877 CallStyle::Sync => ("", "", "", ""), 878 }; 879 uwriteln!( 880 self.src, 881 " 882 /// Auto-generated bindings for a pre-instantiated version of a 883 /// component which implements the world `{world_name}`. 884 /// 885 /// This structure is created through [`{camel}Pre::new`] which 886 /// takes a [`InstancePre`]({wt}::component::InstancePre) that 887 /// has been created through a [`Linker`]({wt}::component::Linker). 888 /// 889 /// For more information see [`{camel}`] as well. 890 pub struct {camel}Pre<T> {{ 891 instance_pre: {wt}::component::InstancePre<T>, 892 indices: {camel}Indices, 893 }} 894 895 impl<T> Clone for {camel}Pre<T> {{ 896 fn clone(&self) -> Self {{ 897 Self {{ 898 instance_pre: self.instance_pre.clone(), 899 indices: self.indices.clone(), 900 }} 901 }} 902 }} 903 904 impl<_T> {camel}Pre<_T> {{ 905 /// Creates a new copy of `{camel}Pre` bindings which can then 906 /// be used to instantiate into a particular store. 907 /// 908 /// This method may fail if the component behind `instance_pre` 909 /// does not have the required exports. 910 pub fn new(instance_pre: {wt}::component::InstancePre<_T>) -> {wt}::Result<Self> {{ 911 let indices = {camel}Indices::new(instance_pre.component())?; 912 Ok(Self {{ instance_pre, indices }}) 913 }} 914 915 pub fn engine(&self) -> &{wt}::Engine {{ 916 self.instance_pre.engine() 917 }} 918 919 pub fn instance_pre(&self) -> &{wt}::component::InstancePre<_T> {{ 920 &self.instance_pre 921 }} 922 923 /// Instantiates a new instance of [`{camel}`] within the 924 /// `store` provided. 925 /// 926 /// This function will use `self` as the pre-instantiated 927 /// instance to perform instantiation. Afterwards the preloaded 928 /// indices in `self` are used to lookup all exports on the 929 /// resulting instance. 930 pub {async_} fn instantiate{async__}( 931 &self, 932 mut store: impl {wt}::AsContextMut<Data = _T>, 933 ) -> {wt}::Result<{camel}> 934 {where_clause} 935 {{ 936 let mut store = store.as_context_mut(); 937 let instance = self.instance_pre.instantiate{async__}(&mut store){await_}?; 938 self.indices.load(&mut store, &instance) 939 }} 940 }} 941 " 942 ); 943 944 uwriteln!( 945 self.src, 946 " 947 /// Auto-generated bindings for index of the exports of 948 /// `{world_name}`. 949 /// 950 /// This is an implementation detail of [`{camel}Pre`] and can 951 /// be constructed if needed as well. 952 /// 953 /// For more information see [`{camel}`] as well. 954 #[derive(Clone)] 955 pub struct {camel}Indices {{" 956 ); 957 for (name, field) in self.exports.fields.iter() { 958 uwriteln!(self.src, "{name}: {},", field.ty_index); 959 } 960 self.src.push_str("}\n"); 961 962 uwriteln!( 963 self.src, 964 " 965 /// Auto-generated bindings for an instance a component which 966 /// implements the world `{world_name}`. 967 /// 968 /// This structure can be created through a number of means 969 /// depending on your requirements and what you have on hand: 970 /// 971 /// * The most convenient way is to use 972 /// [`{camel}::instantiate{async__}`] which only needs a 973 /// [`Store`], [`Component`], and [`Linker`]. 974 /// 975 /// * Alternatively you can create a [`{camel}Pre`] ahead of 976 /// time with a [`Component`] to front-load string lookups 977 /// of exports once instead of per-instantiation. This 978 /// method then uses [`{camel}Pre::instantiate{async__}`] to 979 /// create a [`{camel}`]. 980 /// 981 /// * If you've instantiated the instance yourself already 982 /// then you can use [`{camel}::new`]. 983 /// 984 /// * You can also access the guts of instantiation through 985 /// [`{camel}Indices::new_instance`] followed 986 /// by [`{camel}Indices::load`] to crate an instance of this 987 /// type. 988 /// 989 /// These methods are all equivalent to one another and move 990 /// around the tradeoff of what work is performed when. 991 /// 992 /// [`Store`]: {wt}::Store 993 /// [`Component`]: {wt}::component::Component 994 /// [`Linker`]: {wt}::component::Linker 995 pub struct {camel} {{" 996 ); 997 for (name, field) in self.exports.fields.iter() { 998 uwriteln!(self.src, "{name}: {},", field.ty); 999 } 1000 self.src.push_str("}\n"); 1001 1002 self.world_imports_trait(resolve, world); 1003 1004 uwriteln!(self.src, "const _: () = {{"); 1005 uwriteln!( 1006 self.src, 1007 " 1008 #[allow(unused_imports)] 1009 use {wt}::component::__internal::anyhow; 1010 " 1011 ); 1012 1013 uwriteln!( 1014 self.src, 1015 "impl {camel}Indices {{ 1016 /// Creates a new copy of `{camel}Indices` bindings which can then 1017 /// be used to instantiate into a particular store. 1018 /// 1019 /// This method may fail if the component does not have the 1020 /// required exports. 1021 pub fn new(component: &{wt}::component::Component) -> {wt}::Result<Self> {{ 1022 let _component = component; 1023 ", 1024 ); 1025 for (name, field) in self.exports.fields.iter() { 1026 uwriteln!(self.src, "let {name} = {};", field.get_index_from_component); 1027 } 1028 uwriteln!(self.src, "Ok({camel}Indices {{"); 1029 for (name, _) in self.exports.fields.iter() { 1030 uwriteln!(self.src, "{name},"); 1031 } 1032 uwriteln!(self.src, "}})"); 1033 uwriteln!(self.src, "}}"); // close `fn new` 1034 1035 uwriteln!( 1036 self.src, 1037 " 1038 /// Creates a new instance of [`{camel}Indices`] from an 1039 /// instantiated component. 1040 /// 1041 /// This method of creating a [`{camel}`] will perform string 1042 /// lookups for all exports when this method is called. This 1043 /// will only succeed if the provided instance matches the 1044 /// requirements of [`{camel}`]. 1045 pub fn new_instance( 1046 mut store: impl {wt}::AsContextMut, 1047 instance: &{wt}::component::Instance, 1048 ) -> {wt}::Result<Self> {{ 1049 let _instance = instance; 1050 ", 1051 ); 1052 for (name, field) in self.exports.fields.iter() { 1053 uwriteln!(self.src, "let {name} = {};", field.get_index_from_instance); 1054 } 1055 uwriteln!(self.src, "Ok({camel}Indices {{"); 1056 for (name, _) in self.exports.fields.iter() { 1057 uwriteln!(self.src, "{name},"); 1058 } 1059 uwriteln!(self.src, "}})"); 1060 uwriteln!(self.src, "}}"); // close `fn new_instance` 1061 1062 uwriteln!( 1063 self.src, 1064 " 1065 /// Uses the indices stored in `self` to load an instance 1066 /// of [`{camel}`] from the instance provided. 1067 /// 1068 /// Note that at this time this method will additionally 1069 /// perform type-checks of all exports. 1070 pub fn load( 1071 &self, 1072 mut store: impl {wt}::AsContextMut, 1073 instance: &{wt}::component::Instance, 1074 ) -> {wt}::Result<{camel}> {{ 1075 let _instance = instance; 1076 ", 1077 ); 1078 for (name, field) in self.exports.fields.iter() { 1079 uwriteln!(self.src, "let {name} = {};", field.load); 1080 } 1081 uwriteln!(self.src, "Ok({camel} {{"); 1082 for (name, _) in self.exports.fields.iter() { 1083 uwriteln!(self.src, "{name},"); 1084 } 1085 uwriteln!(self.src, "}})"); 1086 uwriteln!(self.src, "}}"); // close `fn load` 1087 uwriteln!(self.src, "}}"); // close `impl {camel}Indices` 1088 1089 uwriteln!( 1090 self.src, 1091 "impl {camel} {{ 1092 /// Convenience wrapper around [`{camel}Pre::new`] and 1093 /// [`{camel}Pre::instantiate{async__}`]. 1094 pub {async_} fn instantiate{async__}<_T>( 1095 mut store: impl {wt}::AsContextMut<Data = _T>, 1096 component: &{wt}::component::Component, 1097 linker: &{wt}::component::Linker<_T>, 1098 ) -> {wt}::Result<{camel}> 1099 {where_clause} 1100 {{ 1101 let pre = linker.instantiate_pre(component)?; 1102 {camel}Pre::new(pre)?.instantiate{async__}(store){await_} 1103 }} 1104 1105 /// Convenience wrapper around [`{camel}Indices::new_instance`] and 1106 /// [`{camel}Indices::load`]. 1107 pub fn new( 1108 mut store: impl {wt}::AsContextMut, 1109 instance: &{wt}::component::Instance, 1110 ) -> {wt}::Result<{camel}> {{ 1111 let indices = {camel}Indices::new_instance(&mut store, instance)?; 1112 indices.load(store, instance) 1113 }} 1114 ", 1115 ); 1116 self.world_add_to_linker(resolve, world); 1117 1118 for func in self.exports.funcs.iter() { 1119 self.src.push_str(func); 1120 } 1121 1122 uwriteln!(self.src, "}}"); // close `impl {camel}` 1123 1124 uwriteln!(self.src, "}};"); // close `const _: () = ... 1125 } 1126 1127 fn finish(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> { 1128 let remapping_keys = self.opts.with.keys().cloned().collect::<HashSet<String>>(); 1129 1130 let mut unused_keys = remapping_keys 1131 .difference(&self.used_with_opts) 1132 .map(|s| s.as_str()) 1133 .collect::<Vec<&str>>(); 1134 1135 unused_keys.sort(); 1136 1137 if !unused_keys.is_empty() { 1138 anyhow::bail!("interfaces were specified in the `with` config option but are not referenced in the target world: {unused_keys:?}"); 1139 } 1140 1141 if let TrappableImports::Only(only) = &self.opts.trappable_imports { 1142 let mut unused_imports = Vec::from_iter( 1143 only.difference(&self.used_trappable_imports_opts) 1144 .map(|s| s.as_str()), 1145 ); 1146 1147 if !unused_imports.is_empty() { 1148 dbg!(&self.used_trappable_imports_opts); 1149 unused_imports.sort(); 1150 anyhow::bail!("names specified in the `trappable_imports` config option but are not referenced in the target world: {unused_imports:?}"); 1151 } 1152 } 1153 1154 if !self.opts.only_interfaces { 1155 self.build_world_struct(resolve, world) 1156 } 1157 1158 let imports = mem::take(&mut self.import_interfaces); 1159 self.emit_modules( 1160 imports 1161 .into_iter() 1162 .map(|(_, id, module, path)| (id, module, path)) 1163 .collect(), 1164 ); 1165 1166 let exports = mem::take(&mut self.exports.modules); 1167 self.emit_modules(exports); 1168 1169 let mut src = mem::take(&mut self.src); 1170 if self.opts.rustfmt { 1171 let mut child = Command::new("rustfmt") 1172 .arg("--edition=2018") 1173 .stdin(Stdio::piped()) 1174 .stdout(Stdio::piped()) 1175 .spawn() 1176 .expect("failed to spawn `rustfmt`"); 1177 child 1178 .stdin 1179 .take() 1180 .unwrap() 1181 .write_all(src.as_bytes()) 1182 .unwrap(); 1183 src.as_mut_string().truncate(0); 1184 child 1185 .stdout 1186 .take() 1187 .unwrap() 1188 .read_to_string(src.as_mut_string()) 1189 .unwrap(); 1190 let status = child.wait().unwrap(); 1191 assert!(status.success()); 1192 } 1193 1194 Ok(src.into()) 1195 } 1196 1197 fn emit_modules(&mut self, modules: Vec<(InterfaceId, String, InterfaceName)>) { 1198 #[derive(Default)] 1199 struct Module { 1200 submodules: BTreeMap<String, Module>, 1201 contents: Vec<String>, 1202 } 1203 let mut map = Module::default(); 1204 for (_, module, name) in modules { 1205 let path = match name { 1206 InterfaceName::Remapped { local_path, .. } => local_path, 1207 InterfaceName::Path(path) => path, 1208 }; 1209 let mut cur = &mut map; 1210 for name in path[..path.len() - 1].iter() { 1211 cur = cur 1212 .submodules 1213 .entry(name.clone()) 1214 .or_insert(Module::default()); 1215 } 1216 cur.contents.push(module); 1217 } 1218 1219 emit(&mut self.src, map); 1220 1221 fn emit(me: &mut Source, module: Module) { 1222 for (name, submodule) in module.submodules { 1223 uwriteln!(me, "pub mod {name} {{"); 1224 emit(me, submodule); 1225 uwriteln!(me, "}}"); 1226 } 1227 for submodule in module.contents { 1228 uwriteln!(me, "{submodule}"); 1229 } 1230 } 1231 } 1232 1233 /// Attempts to find the `key`, possibly with the resource projection 1234 /// `item`, within the `with` map provided to bindings configuration. 1235 fn lookup_replacement( 1236 &mut self, 1237 resolve: &Resolve, 1238 key: &WorldKey, 1239 item: Option<&str>, 1240 ) -> Option<String> { 1241 let item = match item { 1242 Some(item) => LookupItem::Name(item), 1243 None => LookupItem::None, 1244 }; 1245 1246 for (lookup, mut projection) in lookup_keys(resolve, key, item) { 1247 if let Some(renamed) = self.opts.with.get(&lookup) { 1248 projection.push(renamed.clone()); 1249 projection.reverse(); 1250 self.used_with_opts.insert(lookup); 1251 return Some(projection.join("::")); 1252 } 1253 } 1254 1255 None 1256 } 1257 1258 fn wasmtime_path(&self) -> String { 1259 self.opts 1260 .wasmtime_crate 1261 .clone() 1262 .unwrap_or("wasmtime".to_string()) 1263 } 1264 } 1265 1266 enum LookupItem<'a> { 1267 None, 1268 Name(&'a str), 1269 InterfaceNoPop, 1270 } 1271 1272 fn lookup_keys( 1273 resolve: &Resolve, 1274 key: &WorldKey, 1275 item: LookupItem<'_>, 1276 ) -> Vec<(String, Vec<String>)> { 1277 struct Name<'a> { 1278 prefix: Prefix, 1279 item: Option<&'a str>, 1280 } 1281 1282 #[derive(Copy, Clone)] 1283 enum Prefix { 1284 Namespace(PackageId), 1285 UnversionedPackage(PackageId), 1286 VersionedPackage(PackageId), 1287 UnversionedInterface(InterfaceId), 1288 VersionedInterface(InterfaceId), 1289 } 1290 1291 let prefix = match key { 1292 WorldKey::Interface(id) => Prefix::VersionedInterface(*id), 1293 1294 // Non-interface-keyed names don't get the lookup logic below, 1295 // they're relatively uncommon so only lookup the precise key here. 1296 WorldKey::Name(key) => { 1297 let to_lookup = match item { 1298 LookupItem::Name(item) => format!("{key}/{item}"), 1299 LookupItem::None | LookupItem::InterfaceNoPop => key.to_string(), 1300 }; 1301 return vec![(to_lookup, Vec::new())]; 1302 } 1303 }; 1304 1305 // Here names are iteratively attempted as `key` + `item` is "walked to 1306 // its root" and each attempt is consulted in `self.opts.with`. This 1307 // loop will start at the leaf, the most specific path, and then walk to 1308 // the root, popping items, trying to find a result. 1309 // 1310 // Each time a name is "popped" the projection from the next path is 1311 // pushed onto `projection`. This means that if we actually find a match 1312 // then `projection` is a collection of namespaces that results in the 1313 // final replacement name. 1314 let (interface_required, item) = match item { 1315 LookupItem::None => (false, None), 1316 LookupItem::Name(s) => (false, Some(s)), 1317 LookupItem::InterfaceNoPop => (true, None), 1318 }; 1319 let mut name = Name { prefix, item }; 1320 let mut projection = Vec::new(); 1321 let mut ret = Vec::new(); 1322 loop { 1323 let lookup = name.lookup_key(resolve); 1324 ret.push((lookup, projection.clone())); 1325 if !name.pop(resolve, &mut projection) { 1326 break; 1327 } 1328 if interface_required { 1329 match name.prefix { 1330 Prefix::VersionedInterface(_) | Prefix::UnversionedInterface(_) => {} 1331 _ => break, 1332 } 1333 } 1334 } 1335 1336 return ret; 1337 1338 impl<'a> Name<'a> { 1339 fn lookup_key(&self, resolve: &Resolve) -> String { 1340 let mut s = self.prefix.lookup_key(resolve); 1341 if let Some(item) = self.item { 1342 s.push_str("/"); 1343 s.push_str(item); 1344 } 1345 s 1346 } 1347 1348 fn pop(&mut self, resolve: &'a Resolve, projection: &mut Vec<String>) -> bool { 1349 match (self.item, self.prefix) { 1350 // If this is a versioned resource name, try the unversioned 1351 // resource name next. 1352 (Some(_), Prefix::VersionedInterface(id)) => { 1353 self.prefix = Prefix::UnversionedInterface(id); 1354 true 1355 } 1356 // If this is an unversioned resource name then time to 1357 // ignore the resource itself and move on to the next most 1358 // specific item, versioned interface names. 1359 (Some(item), Prefix::UnversionedInterface(id)) => { 1360 self.prefix = Prefix::VersionedInterface(id); 1361 self.item = None; 1362 projection.push(item.to_upper_camel_case()); 1363 true 1364 } 1365 (Some(_), _) => unreachable!(), 1366 (None, _) => self.prefix.pop(resolve, projection), 1367 } 1368 } 1369 } 1370 1371 impl Prefix { 1372 fn lookup_key(&self, resolve: &Resolve) -> String { 1373 match *self { 1374 Prefix::Namespace(id) => resolve.packages[id].name.namespace.clone(), 1375 Prefix::UnversionedPackage(id) => { 1376 let mut name = resolve.packages[id].name.clone(); 1377 name.version = None; 1378 name.to_string() 1379 } 1380 Prefix::VersionedPackage(id) => resolve.packages[id].name.to_string(), 1381 Prefix::UnversionedInterface(id) => { 1382 let id = resolve.id_of(id).unwrap(); 1383 match id.find('@') { 1384 Some(i) => id[..i].to_string(), 1385 None => id, 1386 } 1387 } 1388 Prefix::VersionedInterface(id) => resolve.id_of(id).unwrap(), 1389 } 1390 } 1391 1392 fn pop(&mut self, resolve: &Resolve, projection: &mut Vec<String>) -> bool { 1393 *self = match *self { 1394 // try the unversioned interface next 1395 Prefix::VersionedInterface(id) => Prefix::UnversionedInterface(id), 1396 // try this interface's versioned package next 1397 Prefix::UnversionedInterface(id) => { 1398 let iface = &resolve.interfaces[id]; 1399 let name = iface.name.as_ref().unwrap(); 1400 projection.push(to_rust_ident(name)); 1401 Prefix::VersionedPackage(iface.package.unwrap()) 1402 } 1403 // try the unversioned package next 1404 Prefix::VersionedPackage(id) => Prefix::UnversionedPackage(id), 1405 // try this package's namespace next 1406 Prefix::UnversionedPackage(id) => { 1407 let name = &resolve.packages[id].name; 1408 projection.push(to_rust_ident(&name.name)); 1409 Prefix::Namespace(id) 1410 } 1411 // nothing left to try any more 1412 Prefix::Namespace(_) => return false, 1413 }; 1414 true 1415 } 1416 } 1417 } 1418 1419 impl Wasmtime { 1420 fn has_world_imports_trait(&self, resolve: &Resolve, world: WorldId) -> bool { 1421 !self.import_functions.is_empty() || get_world_resources(resolve, world).count() > 0 1422 } 1423 1424 fn world_imports_trait(&mut self, resolve: &Resolve, world: WorldId) { 1425 if !self.has_world_imports_trait(resolve, world) { 1426 return; 1427 } 1428 1429 let wt = self.wasmtime_path(); 1430 let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name); 1431 if let CallStyle::Async = self.opts.call_style() { 1432 uwriteln!( 1433 self.src, 1434 "#[{wt}::component::__internal::trait_variant_make(::core::marker::Send)]" 1435 ) 1436 } 1437 uwrite!(self.src, "pub trait {world_camel}Imports"); 1438 let mut supertraits = vec![]; 1439 if let CallStyle::Async = self.opts.call_style() { 1440 supertraits.push("Send".to_string()); 1441 } 1442 for (_, name) in get_world_resources(resolve, world) { 1443 supertraits.push(format!("Host{}", name.to_upper_camel_case())); 1444 } 1445 if !supertraits.is_empty() { 1446 uwrite!(self.src, ": {}", supertraits.join(" + ")); 1447 } 1448 uwriteln!(self.src, " {{"); 1449 1450 let has_concurrent_function = self.import_functions.iter().any(|func| { 1451 matches!(func.func.kind, FunctionKind::Freestanding) 1452 && matches!( 1453 self.opts.import_call_style(None, &func.func.name), 1454 CallStyle::Concurrent 1455 ) 1456 }); 1457 1458 if has_concurrent_function { 1459 self.src.push_str("type Data;\n"); 1460 } 1461 1462 for f in self.import_functions.iter() { 1463 if let Some(sig) = &f.sig { 1464 self.src.push_str(sig); 1465 self.src.push_str(";\n"); 1466 } 1467 } 1468 uwriteln!(self.src, "}}"); 1469 1470 let get_host_bounds = if let CallStyle::Concurrent = self.opts.call_style() { 1471 let constraints = world_imports_concurrent_constraints(resolve, world, &self.opts); 1472 1473 format!("{world_camel}Imports{}", constraints("D")) 1474 } else { 1475 format!("{world_camel}Imports") 1476 }; 1477 1478 uwriteln!( 1479 self.src, 1480 " 1481 pub trait {world_camel}ImportsGetHost<T, D>: 1482 Fn(T) -> <Self as {world_camel}ImportsGetHost<T, D>>::Host 1483 + Send 1484 + Sync 1485 + Copy 1486 + 'static 1487 {{ 1488 type Host: {get_host_bounds}; 1489 }} 1490 1491 impl<F, T, D, O> {world_camel}ImportsGetHost<T, D> for F 1492 where 1493 F: Fn(T) -> O + Send + Sync + Copy + 'static, 1494 O: {get_host_bounds}, 1495 {{ 1496 type Host = O; 1497 }} 1498 " 1499 ); 1500 1501 // Generate impl WorldImports for &mut WorldImports 1502 let maybe_send = if let CallStyle::Async = self.opts.call_style() { 1503 "+ Send" 1504 } else { 1505 "" 1506 }; 1507 if !self.opts.skip_mut_forwarding_impls { 1508 let maybe_maybe_sized = if let CallStyle::Concurrent = self.opts.call_style() { 1509 "" 1510 } else { 1511 "+ ?Sized" 1512 }; 1513 uwriteln!( 1514 self.src, 1515 "impl<_T: {world_camel}Imports {maybe_maybe_sized} {maybe_send}> {world_camel}Imports for &mut _T {{" 1516 ); 1517 let has_concurrent_function = self.import_functions.iter().any(|f| { 1518 matches!( 1519 self.opts.import_call_style(None, &f.func.name), 1520 CallStyle::Concurrent 1521 ) 1522 }); 1523 1524 if has_concurrent_function { 1525 self.src.push_str("type Data = _T::Data;\n"); 1526 } 1527 // Forward each method call to &mut T 1528 for f in self.import_functions.iter() { 1529 if let Some(sig) = &f.sig { 1530 self.src.push_str(sig); 1531 let call_style = self.opts.import_call_style(None, &f.func.name); 1532 if let CallStyle::Concurrent = &call_style { 1533 uwrite!( 1534 self.src, 1535 "{{ <_T as {world_camel}Imports>::{}(store,", 1536 rust_function_name(&f.func) 1537 ); 1538 } else { 1539 uwrite!( 1540 self.src, 1541 "{{ {world_camel}Imports::{}(*self,", 1542 rust_function_name(&f.func) 1543 ); 1544 } 1545 for (name, _) in f.func.params.iter() { 1546 uwrite!(self.src, "{},", to_rust_ident(name)); 1547 } 1548 uwrite!(self.src, ")"); 1549 if let CallStyle::Async = &call_style { 1550 uwrite!(self.src, ".await"); 1551 } 1552 uwriteln!(self.src, "}}"); 1553 } 1554 } 1555 uwriteln!(self.src, "}}"); 1556 } 1557 } 1558 1559 fn import_interface_paths(&self) -> Vec<(InterfaceId, String)> { 1560 self.import_interfaces 1561 .iter() 1562 .map(|(_, id, _, name)| { 1563 let path = match name { 1564 InterfaceName::Path(path) => path.join("::"), 1565 InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(), 1566 }; 1567 (*id, path) 1568 }) 1569 .collect() 1570 } 1571 1572 fn import_interface_path(&self, id: &InterfaceId) -> String { 1573 match &self.interface_names[id] { 1574 InterfaceName::Path(path) => path.join("::"), 1575 InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(), 1576 } 1577 } 1578 1579 fn world_host_traits(&self, resolve: &Resolve, world: WorldId) -> Vec<String> { 1580 let mut traits = self 1581 .import_interface_paths() 1582 .iter() 1583 .map(|(_, path)| format!("{path}::Host")) 1584 .collect::<Vec<_>>(); 1585 if self.has_world_imports_trait(resolve, world) { 1586 let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name); 1587 traits.push(format!("{world_camel}Imports")); 1588 } 1589 if let CallStyle::Async = self.opts.call_style() { 1590 traits.push("Send".to_string()); 1591 } 1592 traits 1593 } 1594 1595 fn world_add_to_linker(&mut self, resolve: &Resolve, world: WorldId) { 1596 let has_world_imports_trait = self.has_world_imports_trait(resolve, world); 1597 if self.import_interfaces.is_empty() && !has_world_imports_trait { 1598 return; 1599 } 1600 1601 let (options_param, options_arg) = if self.world_link_options.has_any() { 1602 ("options: &LinkOptions,", ", options") 1603 } else { 1604 ("", "") 1605 }; 1606 1607 let camel = to_rust_upper_camel_case(&resolve.worlds[world].name); 1608 1609 let data_bounds = if self.opts.is_store_data_send() { 1610 if let CallStyle::Concurrent = self.opts.call_style() { 1611 "T: Send + 'static," 1612 } else { 1613 "T: Send," 1614 } 1615 } else { 1616 "" 1617 }; 1618 let wt = self.wasmtime_path(); 1619 if has_world_imports_trait { 1620 let host_bounds = if let CallStyle::Concurrent = self.opts.call_style() { 1621 let constraints = world_imports_concurrent_constraints(resolve, world, &self.opts); 1622 1623 format!("{camel}Imports{}", constraints("T")) 1624 } else { 1625 format!("{camel}Imports") 1626 }; 1627 1628 uwrite!( 1629 self.src, 1630 " 1631 pub fn add_to_linker_imports_get_host< 1632 T, 1633 G: for<'a> {camel}ImportsGetHost<&'a mut T, T, Host: {host_bounds}> 1634 >( 1635 linker: &mut {wt}::component::Linker<T>, 1636 {options_param} 1637 host_getter: G, 1638 ) -> {wt}::Result<()> 1639 where {data_bounds} 1640 {{ 1641 let mut linker = linker.root(); 1642 " 1643 ); 1644 let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability); 1645 for (ty, name) in get_world_resources(resolve, world) { 1646 Self::generate_add_resource_to_linker( 1647 None, 1648 &mut self.src, 1649 &self.opts, 1650 &wt, 1651 "linker", 1652 name, 1653 &resolve.types[ty].stability, 1654 ); 1655 } 1656 for f in self.import_functions.iter() { 1657 self.src.push_str(&f.add_to_linker); 1658 self.src.push_str("\n"); 1659 } 1660 gate.close(&mut self.src); 1661 uwriteln!(self.src, "Ok(())\n}}"); 1662 } 1663 1664 let (host_bounds, data_bounds) = if let CallStyle::Concurrent = self.opts.call_style() { 1665 let bounds = self 1666 .import_interfaces 1667 .iter() 1668 .map(|(key, id, _, name)| { 1669 ( 1670 key, 1671 id, 1672 match name { 1673 InterfaceName::Path(path) => path.join("::"), 1674 InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(), 1675 }, 1676 ) 1677 }) 1678 .map(|(key, id, path)| { 1679 format!( 1680 " + {path}::Host{}", 1681 concurrent_constraints( 1682 resolve, 1683 &self.opts, 1684 Some(&resolve.name_world_key(key)), 1685 *id 1686 )("T") 1687 ) 1688 }) 1689 .chain(if self.has_world_imports_trait(resolve, world) { 1690 let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name); 1691 let constraints = 1692 world_imports_concurrent_constraints(resolve, world, &self.opts); 1693 Some(format!(" + {world_camel}Imports{}", constraints("T"))) 1694 } else { 1695 None 1696 }) 1697 .collect::<Vec<_>>() 1698 .concat(); 1699 1700 ( 1701 format!("U: Send{bounds}"), 1702 format!("T: Send{bounds} + 'static,"), 1703 ) 1704 } else { 1705 ( 1706 format!("U: {}", self.world_host_traits(resolve, world).join(" + ")), 1707 data_bounds.to_string(), 1708 ) 1709 }; 1710 1711 if !self.opts.skip_mut_forwarding_impls { 1712 uwriteln!( 1713 self.src, 1714 " 1715 pub fn add_to_linker<T, U>( 1716 linker: &mut {wt}::component::Linker<T>, 1717 {options_param} 1718 get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, 1719 ) -> {wt}::Result<()> 1720 where 1721 {data_bounds} 1722 {host_bounds} 1723 {{ 1724 " 1725 ); 1726 let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability); 1727 if has_world_imports_trait { 1728 uwriteln!( 1729 self.src, 1730 "Self::add_to_linker_imports_get_host(linker {options_arg}, get)?;" 1731 ); 1732 } 1733 for (interface_id, path) in self.import_interface_paths() { 1734 let options_arg = if self.interface_link_options[&interface_id].has_any() { 1735 ", &options.into()" 1736 } else { 1737 "" 1738 }; 1739 1740 let import_stability = resolve.worlds[world] 1741 .imports 1742 .iter() 1743 .filter_map(|(_, i)| match i { 1744 WorldItem::Interface { id, stability } if *id == interface_id => { 1745 Some(stability.clone()) 1746 } 1747 _ => None, 1748 }) 1749 .next() 1750 .unwrap_or(Stability::Unknown); 1751 1752 let gate = FeatureGate::open(&mut self.src, &import_stability); 1753 uwriteln!( 1754 self.src, 1755 "{path}::add_to_linker(linker {options_arg}, get)?;" 1756 ); 1757 gate.close(&mut self.src); 1758 } 1759 gate.close(&mut self.src); 1760 uwriteln!(self.src, "Ok(())\n}}"); 1761 } 1762 } 1763 1764 fn generate_add_resource_to_linker( 1765 qualifier: Option<&str>, 1766 src: &mut Source, 1767 opts: &Opts, 1768 wt: &str, 1769 inst: &str, 1770 name: &str, 1771 stability: &Stability, 1772 ) { 1773 let gate = FeatureGate::open(src, stability); 1774 let camel = name.to_upper_camel_case(); 1775 if let CallStyle::Async = opts.drop_call_style(qualifier, name) { 1776 uwriteln!( 1777 src, 1778 "{inst}.resource_async( 1779 \"{name}\", 1780 {wt}::component::ResourceType::host::<{camel}>(), 1781 move |mut store, rep| {{ 1782 {wt}::component::__internal::Box::new(async move {{ 1783 Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)).await 1784 }}) 1785 }}, 1786 )?;" 1787 ) 1788 } else { 1789 uwriteln!( 1790 src, 1791 "{inst}.resource( 1792 \"{name}\", 1793 {wt}::component::ResourceType::host::<{camel}>(), 1794 move |mut store, rep| -> {wt}::Result<()> {{ 1795 Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)) 1796 }}, 1797 )?;" 1798 ) 1799 } 1800 gate.close(src); 1801 } 1802 } 1803 1804 struct InterfaceGenerator<'a> { 1805 src: Source, 1806 generator: &'a mut Wasmtime, 1807 resolve: &'a Resolve, 1808 current_interface: Option<(InterfaceId, &'a WorldKey, bool)>, 1809 } 1810 1811 impl<'a> InterfaceGenerator<'a> { 1812 fn new(generator: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> { 1813 InterfaceGenerator { 1814 src: Source::default(), 1815 generator, 1816 resolve, 1817 current_interface: None, 1818 } 1819 } 1820 1821 fn types_imported(&self) -> bool { 1822 match self.current_interface { 1823 Some((_, _, is_export)) => !is_export, 1824 None => true, 1825 } 1826 } 1827 1828 fn types(&mut self, id: InterfaceId) { 1829 for (name, id) in self.resolve.interfaces[id].types.iter() { 1830 self.define_type(name, *id); 1831 } 1832 } 1833 1834 fn define_type(&mut self, name: &str, id: TypeId) { 1835 let ty = &self.resolve.types[id]; 1836 match &ty.kind { 1837 TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs), 1838 TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs), 1839 TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs), 1840 TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs), 1841 TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs), 1842 TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs), 1843 TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs), 1844 TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs), 1845 TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs), 1846 TypeDefKind::Future(t) => self.type_future(id, name, t.as_ref(), &ty.docs), 1847 TypeDefKind::Stream(t) => self.type_stream(id, name, t.as_ref(), &ty.docs), 1848 TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs), 1849 TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs), 1850 TypeDefKind::Unknown => unreachable!(), 1851 } 1852 } 1853 1854 fn type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs) { 1855 self.rustdoc(docs); 1856 let name = name.to_upper_camel_case(); 1857 uwriteln!(self.src, "pub type {name} = "); 1858 self.print_handle(handle); 1859 self.push_str(";\n"); 1860 self.assert_type(id, &name); 1861 } 1862 1863 fn type_resource(&mut self, id: TypeId, name: &str, resource: &TypeDef, docs: &Docs) { 1864 let camel = name.to_upper_camel_case(); 1865 let wt = self.generator.wasmtime_path(); 1866 1867 if self.types_imported() { 1868 self.rustdoc(docs); 1869 1870 let replacement = match self.current_interface { 1871 Some((_, key, _)) => { 1872 self.generator 1873 .lookup_replacement(self.resolve, key, Some(name)) 1874 } 1875 None => { 1876 self.generator.used_with_opts.insert(name.into()); 1877 self.generator.opts.with.get(name).cloned() 1878 } 1879 }; 1880 match replacement { 1881 Some(path) => { 1882 uwriteln!( 1883 self.src, 1884 "pub use {}{path} as {camel};", 1885 self.path_to_root() 1886 ); 1887 } 1888 None => { 1889 uwriteln!(self.src, "pub enum {camel} {{}}"); 1890 } 1891 } 1892 1893 // Generate resource trait 1894 if let CallStyle::Async = self.generator.opts.call_style() { 1895 uwriteln!( 1896 self.src, 1897 "#[{wt}::component::__internal::trait_variant_make(::core::marker::Send)]" 1898 ) 1899 } 1900 1901 uwriteln!(self.src, "pub trait Host{camel}: Sized {{"); 1902 1903 let mut functions = match resource.owner { 1904 TypeOwner::World(id) => self.resolve.worlds[id] 1905 .imports 1906 .values() 1907 .filter_map(|item| match item { 1908 WorldItem::Function(f) => Some(f), 1909 _ => None, 1910 }) 1911 .collect(), 1912 TypeOwner::Interface(id) => self.resolve.interfaces[id] 1913 .functions 1914 .values() 1915 .collect::<Vec<_>>(), 1916 TypeOwner::None => { 1917 panic!("A resource must be owned by a world or interface"); 1918 } 1919 }; 1920 1921 functions.retain(|func| func.kind.resource() == Some(id)); 1922 1923 let has_concurrent_function = functions.iter().any(|func| { 1924 matches!( 1925 self.generator 1926 .opts 1927 .import_call_style(self.qualifier().as_deref(), &func.name), 1928 CallStyle::Concurrent 1929 ) 1930 }); 1931 1932 if has_concurrent_function { 1933 uwriteln!(self.src, "type {camel}Data;"); 1934 } 1935 1936 for func in &functions { 1937 self.generate_function_trait_sig(func, &format!("{camel}Data")); 1938 self.push_str(";\n"); 1939 } 1940 1941 if let CallStyle::Async = self 1942 .generator 1943 .opts 1944 .drop_call_style(self.qualifier().as_deref(), name) 1945 { 1946 uwrite!(self.src, "async "); 1947 } 1948 uwrite!( 1949 self.src, 1950 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()>;" 1951 ); 1952 1953 uwriteln!(self.src, "}}"); 1954 1955 // Generate impl HostResource for &mut HostResource 1956 if !self.generator.opts.skip_mut_forwarding_impls { 1957 let maybe_send = if let CallStyle::Async = self.generator.opts.call_style() { 1958 "+ Send" 1959 } else { 1960 "" 1961 }; 1962 let maybe_maybe_sized = if has_concurrent_function { 1963 "" 1964 } else { 1965 "+ ?Sized" 1966 }; 1967 uwriteln!( 1968 self.src, 1969 "impl <_T: Host{camel} {maybe_maybe_sized} {maybe_send}> Host{camel} for &mut _T {{" 1970 ); 1971 if has_concurrent_function { 1972 uwriteln!(self.src, "type {camel}Data = _T::{camel}Data;"); 1973 } 1974 for func in &functions { 1975 let call_style = self 1976 .generator 1977 .opts 1978 .import_call_style(self.qualifier().as_deref(), &func.name); 1979 self.generate_function_trait_sig(func, &format!("{camel}Data")); 1980 if let CallStyle::Concurrent = call_style { 1981 uwrite!( 1982 self.src, 1983 "{{ <_T as Host{camel}>::{}(store,", 1984 rust_function_name(func) 1985 ); 1986 } else { 1987 uwrite!( 1988 self.src, 1989 "{{ Host{camel}::{}(*self,", 1990 rust_function_name(func) 1991 ); 1992 } 1993 for (name, _) in func.params.iter() { 1994 uwrite!(self.src, "{},", to_rust_ident(name)); 1995 } 1996 uwrite!(self.src, ")"); 1997 if let CallStyle::Async = call_style { 1998 uwrite!(self.src, ".await"); 1999 } 2000 uwriteln!(self.src, "}}"); 2001 } 2002 if let CallStyle::Async = self 2003 .generator 2004 .opts 2005 .drop_call_style(self.qualifier().as_deref(), name) 2006 { 2007 uwriteln!(self.src, " 2008 async fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{ 2009 Host{camel}::drop(*self, rep).await 2010 }}", 2011 ); 2012 } else { 2013 uwriteln!(self.src, " 2014 fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{ 2015 Host{camel}::drop(*self, rep) 2016 }}", 2017 ); 2018 } 2019 uwriteln!(self.src, "}}"); 2020 } 2021 } else { 2022 self.rustdoc(docs); 2023 uwriteln!( 2024 self.src, 2025 " 2026 pub type {camel} = {wt}::component::ResourceAny; 2027 2028 pub struct Guest{camel}<'a> {{ 2029 funcs: &'a Guest, 2030 }} 2031 " 2032 ); 2033 } 2034 } 2035 2036 fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) { 2037 let info = self.info(id); 2038 let wt = self.generator.wasmtime_path(); 2039 2040 // We use a BTree set to make sure we don't have any duplicates and we have a stable order 2041 let additional_derives: BTreeSet<String> = self 2042 .generator 2043 .opts 2044 .additional_derive_attributes 2045 .iter() 2046 .cloned() 2047 .collect(); 2048 2049 for (name, mode) in self.modes_of(id) { 2050 let lt = self.lifetime_for(&info, mode); 2051 self.rustdoc(docs); 2052 2053 let mut derives = additional_derives.clone(); 2054 2055 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 2056 if lt.is_none() { 2057 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 2058 } 2059 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 2060 self.push_str("#[component(record)]\n"); 2061 if let Some(path) = &self.generator.opts.wasmtime_crate { 2062 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 2063 } 2064 2065 if info.is_copy() { 2066 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string())); 2067 } else if info.is_clone() { 2068 derives.insert("Clone".to_string()); 2069 } 2070 2071 if !derives.is_empty() { 2072 self.push_str("#[derive("); 2073 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 2074 self.push_str(")]\n") 2075 } 2076 2077 self.push_str(&format!("pub struct {name}")); 2078 self.print_generics(lt); 2079 self.push_str(" {\n"); 2080 for field in record.fields.iter() { 2081 self.rustdoc(&field.docs); 2082 self.push_str(&format!("#[component(name = \"{}\")]\n", field.name)); 2083 self.push_str("pub "); 2084 self.push_str(&to_rust_ident(&field.name)); 2085 self.push_str(": "); 2086 self.print_ty(&field.ty, mode); 2087 self.push_str(",\n"); 2088 } 2089 self.push_str("}\n"); 2090 2091 self.push_str("impl"); 2092 self.print_generics(lt); 2093 self.push_str(" core::fmt::Debug for "); 2094 self.push_str(&name); 2095 self.print_generics(lt); 2096 self.push_str(" {\n"); 2097 self.push_str( 2098 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 2099 ); 2100 self.push_str(&format!("f.debug_struct(\"{name}\")")); 2101 for field in record.fields.iter() { 2102 self.push_str(&format!( 2103 ".field(\"{}\", &self.{})", 2104 field.name, 2105 to_rust_ident(&field.name) 2106 )); 2107 } 2108 self.push_str(".finish()\n"); 2109 self.push_str("}\n"); 2110 self.push_str("}\n"); 2111 2112 if info.error { 2113 self.push_str("impl"); 2114 self.print_generics(lt); 2115 self.push_str(" core::fmt::Display for "); 2116 self.push_str(&name); 2117 self.print_generics(lt); 2118 self.push_str(" {\n"); 2119 self.push_str( 2120 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 2121 ); 2122 self.push_str("write!(f, \"{:?}\", self)\n"); 2123 self.push_str("}\n"); 2124 self.push_str("}\n"); 2125 2126 self.push_str("impl core::error::Error for "); 2127 self.push_str(&name); 2128 self.push_str("{}\n"); 2129 } 2130 self.assert_type(id, &name); 2131 } 2132 } 2133 2134 fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) { 2135 let info = self.info(id); 2136 for (name, mode) in self.modes_of(id) { 2137 let lt = self.lifetime_for(&info, mode); 2138 self.rustdoc(docs); 2139 self.push_str(&format!("pub type {name}")); 2140 self.print_generics(lt); 2141 self.push_str(" = ("); 2142 for ty in tuple.types.iter() { 2143 self.print_ty(ty, mode); 2144 self.push_str(","); 2145 } 2146 self.push_str(");\n"); 2147 self.assert_type(id, &name); 2148 } 2149 } 2150 2151 fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) { 2152 self.rustdoc(docs); 2153 let wt = self.generator.wasmtime_path(); 2154 let rust_name = to_rust_upper_camel_case(name); 2155 uwriteln!(self.src, "{wt}::component::flags!(\n"); 2156 self.src.push_str(&format!("{rust_name} {{\n")); 2157 for flag in flags.flags.iter() { 2158 // TODO wasmtime-component-macro doesn't support docs for flags rn 2159 uwrite!( 2160 self.src, 2161 "#[component(name=\"{}\")] const {};\n", 2162 flag.name, 2163 flag.name.to_shouty_snake_case() 2164 ); 2165 } 2166 self.src.push_str("}\n"); 2167 self.src.push_str(");\n\n"); 2168 self.assert_type(id, &rust_name); 2169 } 2170 2171 fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) { 2172 self.print_rust_enum( 2173 id, 2174 variant.cases.iter().map(|c| { 2175 ( 2176 c.name.to_upper_camel_case(), 2177 Some(c.name.clone()), 2178 &c.docs, 2179 c.ty.as_ref(), 2180 ) 2181 }), 2182 docs, 2183 "variant", 2184 ); 2185 } 2186 2187 fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) { 2188 let info = self.info(id); 2189 2190 for (name, mode) in self.modes_of(id) { 2191 self.rustdoc(docs); 2192 let lt = self.lifetime_for(&info, mode); 2193 self.push_str(&format!("pub type {name}")); 2194 self.print_generics(lt); 2195 self.push_str("= Option<"); 2196 self.print_ty(payload, mode); 2197 self.push_str(">;\n"); 2198 self.assert_type(id, &name); 2199 } 2200 } 2201 2202 // Emit a double-check that the wit-parser-understood size of a type agrees 2203 // with the Wasmtime-understood size of a type. 2204 fn assert_type(&mut self, id: TypeId, name: &str) { 2205 self.push_str("const _: () = {\n"); 2206 let wt = self.generator.wasmtime_path(); 2207 uwriteln!( 2208 self.src, 2209 "assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);", 2210 self.generator.sizes.size(&Type::Id(id)).size_wasm32(), 2211 ); 2212 uwriteln!( 2213 self.src, 2214 "assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);", 2215 self.generator.sizes.align(&Type::Id(id)).align_wasm32(), 2216 ); 2217 self.push_str("};\n"); 2218 } 2219 2220 fn print_rust_enum<'b>( 2221 &mut self, 2222 id: TypeId, 2223 cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone, 2224 docs: &Docs, 2225 derive_component: &str, 2226 ) where 2227 Self: Sized, 2228 { 2229 let info = self.info(id); 2230 let wt = self.generator.wasmtime_path(); 2231 2232 // We use a BTree set to make sure we don't have any duplicates and we have a stable order 2233 let additional_derives: BTreeSet<String> = self 2234 .generator 2235 .opts 2236 .additional_derive_attributes 2237 .iter() 2238 .cloned() 2239 .collect(); 2240 2241 for (name, mode) in self.modes_of(id) { 2242 let name = to_rust_upper_camel_case(&name); 2243 2244 let mut derives = additional_derives.clone(); 2245 2246 self.rustdoc(docs); 2247 let lt = self.lifetime_for(&info, mode); 2248 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 2249 if lt.is_none() { 2250 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 2251 } 2252 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 2253 self.push_str(&format!("#[component({derive_component})]\n")); 2254 if let Some(path) = &self.generator.opts.wasmtime_crate { 2255 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 2256 } 2257 if info.is_copy() { 2258 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string())); 2259 } else if info.is_clone() { 2260 derives.insert("Clone".to_string()); 2261 } 2262 2263 if !derives.is_empty() { 2264 self.push_str("#[derive("); 2265 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 2266 self.push_str(")]\n") 2267 } 2268 2269 self.push_str(&format!("pub enum {name}")); 2270 self.print_generics(lt); 2271 self.push_str("{\n"); 2272 for (case_name, component_name, docs, payload) in cases.clone() { 2273 self.rustdoc(docs); 2274 if let Some(n) = component_name { 2275 self.push_str(&format!("#[component(name = \"{n}\")] ")); 2276 } 2277 self.push_str(&case_name); 2278 if let Some(ty) = payload { 2279 self.push_str("("); 2280 self.print_ty(ty, mode); 2281 self.push_str(")") 2282 } 2283 self.push_str(",\n"); 2284 } 2285 self.push_str("}\n"); 2286 2287 self.print_rust_enum_debug( 2288 id, 2289 mode, 2290 &name, 2291 cases 2292 .clone() 2293 .into_iter() 2294 .map(|(name, _attr, _docs, ty)| (name, ty)), 2295 ); 2296 2297 if info.error { 2298 self.push_str("impl"); 2299 self.print_generics(lt); 2300 self.push_str(" core::fmt::Display for "); 2301 self.push_str(&name); 2302 self.print_generics(lt); 2303 self.push_str(" {\n"); 2304 self.push_str( 2305 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 2306 ); 2307 self.push_str("write!(f, \"{:?}\", self)\n"); 2308 self.push_str("}\n"); 2309 self.push_str("}\n"); 2310 2311 self.push_str("impl"); 2312 self.print_generics(lt); 2313 self.push_str(" core::error::Error for "); 2314 self.push_str(&name); 2315 self.print_generics(lt); 2316 self.push_str(" {}\n"); 2317 } 2318 2319 self.assert_type(id, &name); 2320 } 2321 } 2322 2323 fn print_rust_enum_debug<'b>( 2324 &mut self, 2325 id: TypeId, 2326 mode: TypeMode, 2327 name: &str, 2328 cases: impl IntoIterator<Item = (String, Option<&'b Type>)>, 2329 ) where 2330 Self: Sized, 2331 { 2332 let info = self.info(id); 2333 let lt = self.lifetime_for(&info, mode); 2334 self.push_str("impl"); 2335 self.print_generics(lt); 2336 self.push_str(" core::fmt::Debug for "); 2337 self.push_str(name); 2338 self.print_generics(lt); 2339 self.push_str(" {\n"); 2340 self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n"); 2341 self.push_str("match self {\n"); 2342 for (case_name, payload) in cases { 2343 self.push_str(name); 2344 self.push_str("::"); 2345 self.push_str(&case_name); 2346 if payload.is_some() { 2347 self.push_str("(e)"); 2348 } 2349 self.push_str(" => {\n"); 2350 self.push_str(&format!("f.debug_tuple(\"{name}::{case_name}\")")); 2351 if payload.is_some() { 2352 self.push_str(".field(e)"); 2353 } 2354 self.push_str(".finish()\n"); 2355 self.push_str("}\n"); 2356 } 2357 self.push_str("}\n"); 2358 self.push_str("}\n"); 2359 self.push_str("}\n"); 2360 } 2361 2362 fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) { 2363 let info = self.info(id); 2364 2365 for (name, mode) in self.modes_of(id) { 2366 self.rustdoc(docs); 2367 let lt = self.lifetime_for(&info, mode); 2368 self.push_str(&format!("pub type {name}")); 2369 self.print_generics(lt); 2370 self.push_str("= Result<"); 2371 self.print_optional_ty(result.ok.as_ref(), mode); 2372 self.push_str(","); 2373 self.print_optional_ty(result.err.as_ref(), mode); 2374 self.push_str(">;\n"); 2375 self.assert_type(id, &name); 2376 } 2377 } 2378 2379 fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) { 2380 let info = self.info(id); 2381 let wt = self.generator.wasmtime_path(); 2382 2383 // We use a BTree set to make sure we don't have any duplicates and have a stable order 2384 let mut derives: BTreeSet<String> = self 2385 .generator 2386 .opts 2387 .additional_derive_attributes 2388 .iter() 2389 .cloned() 2390 .collect(); 2391 2392 derives.extend( 2393 ["Clone", "Copy", "PartialEq", "Eq"] 2394 .into_iter() 2395 .map(|s| s.to_string()), 2396 ); 2397 2398 let name = to_rust_upper_camel_case(name); 2399 self.rustdoc(docs); 2400 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 2401 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 2402 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 2403 self.push_str("#[component(enum)]\n"); 2404 if let Some(path) = &self.generator.opts.wasmtime_crate { 2405 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 2406 } 2407 2408 self.push_str("#[derive("); 2409 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 2410 self.push_str(")]\n"); 2411 2412 let repr = match enum_.cases.len().ilog2() { 2413 0..=7 => "u8", 2414 8..=15 => "u16", 2415 _ => "u32", 2416 }; 2417 uwriteln!(self.src, "#[repr({repr})]"); 2418 2419 self.push_str(&format!("pub enum {name} {{\n")); 2420 for case in enum_.cases.iter() { 2421 self.rustdoc(&case.docs); 2422 self.push_str(&format!("#[component(name = \"{}\")]", case.name)); 2423 self.push_str(&case.name.to_upper_camel_case()); 2424 self.push_str(",\n"); 2425 } 2426 self.push_str("}\n"); 2427 2428 // Auto-synthesize an implementation of the standard `Error` trait for 2429 // error-looking types based on their name. 2430 if info.error { 2431 self.push_str("impl "); 2432 self.push_str(&name); 2433 self.push_str("{\n"); 2434 2435 self.push_str("pub fn name(&self) -> &'static str {\n"); 2436 self.push_str("match self {\n"); 2437 for case in enum_.cases.iter() { 2438 self.push_str(&name); 2439 self.push_str("::"); 2440 self.push_str(&case.name.to_upper_camel_case()); 2441 self.push_str(" => \""); 2442 self.push_str(case.name.as_str()); 2443 self.push_str("\",\n"); 2444 } 2445 self.push_str("}\n"); 2446 self.push_str("}\n"); 2447 2448 self.push_str("pub fn message(&self) -> &'static str {\n"); 2449 self.push_str("match self {\n"); 2450 for case in enum_.cases.iter() { 2451 self.push_str(&name); 2452 self.push_str("::"); 2453 self.push_str(&case.name.to_upper_camel_case()); 2454 self.push_str(" => \""); 2455 if let Some(contents) = &case.docs.contents { 2456 self.push_str(contents.trim()); 2457 } 2458 self.push_str("\",\n"); 2459 } 2460 self.push_str("}\n"); 2461 self.push_str("}\n"); 2462 2463 self.push_str("}\n"); 2464 2465 self.push_str("impl core::fmt::Debug for "); 2466 self.push_str(&name); 2467 self.push_str( 2468 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 2469 ); 2470 self.push_str("f.debug_struct(\""); 2471 self.push_str(&name); 2472 self.push_str("\")\n"); 2473 self.push_str(".field(\"code\", &(*self as i32))\n"); 2474 self.push_str(".field(\"name\", &self.name())\n"); 2475 self.push_str(".field(\"message\", &self.message())\n"); 2476 self.push_str(".finish()\n"); 2477 self.push_str("}\n"); 2478 self.push_str("}\n"); 2479 2480 self.push_str("impl core::fmt::Display for "); 2481 self.push_str(&name); 2482 self.push_str( 2483 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 2484 ); 2485 self.push_str("write!(f, \"{} (error {})\", self.name(), *self as i32)"); 2486 self.push_str("}\n"); 2487 self.push_str("}\n"); 2488 self.push_str("\n"); 2489 self.push_str("impl core::error::Error for "); 2490 self.push_str(&name); 2491 self.push_str("{}\n"); 2492 } else { 2493 self.print_rust_enum_debug( 2494 id, 2495 TypeMode::Owned, 2496 &name, 2497 enum_ 2498 .cases 2499 .iter() 2500 .map(|c| (c.name.to_upper_camel_case(), None)), 2501 ) 2502 } 2503 self.assert_type(id, &name); 2504 } 2505 2506 fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { 2507 let info = self.info(id); 2508 for (name, mode) in self.modes_of(id) { 2509 self.rustdoc(docs); 2510 self.push_str(&format!("pub type {name}")); 2511 let lt = self.lifetime_for(&info, mode); 2512 self.print_generics(lt); 2513 self.push_str(" = "); 2514 self.print_ty(ty, mode); 2515 self.push_str(";\n"); 2516 let def_id = resolve_type_definition_id(self.resolve, id); 2517 if !matches!(self.resolve().types[def_id].kind, TypeDefKind::Resource) { 2518 self.assert_type(id, &name); 2519 } 2520 } 2521 } 2522 2523 fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { 2524 let info = self.info(id); 2525 for (name, mode) in self.modes_of(id) { 2526 let lt = self.lifetime_for(&info, mode); 2527 self.rustdoc(docs); 2528 self.push_str(&format!("pub type {name}")); 2529 self.print_generics(lt); 2530 self.push_str(" = "); 2531 self.print_list(ty, mode); 2532 self.push_str(";\n"); 2533 self.assert_type(id, &name); 2534 } 2535 } 2536 2537 fn type_stream(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) { 2538 self.rustdoc(docs); 2539 self.push_str(&format!("pub type {name}")); 2540 self.print_generics(None); 2541 self.push_str(" = "); 2542 self.print_stream(ty); 2543 self.push_str(";\n"); 2544 self.assert_type(id, &name); 2545 } 2546 2547 fn type_future(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) { 2548 self.rustdoc(docs); 2549 self.push_str(&format!("pub type {name}")); 2550 self.print_generics(None); 2551 self.push_str(" = "); 2552 self.print_future(ty); 2553 self.push_str(";\n"); 2554 self.assert_type(id, &name); 2555 } 2556 2557 fn print_result_ty(&mut self, result: Option<Type>, mode: TypeMode) { 2558 match result { 2559 Some(ty) => self.print_ty(&ty, mode), 2560 None => self.push_str("()"), 2561 } 2562 } 2563 2564 fn print_result_ty_tuple(&mut self, result: Option<Type>, mode: TypeMode) { 2565 self.push_str("("); 2566 if let Some(ty) = result { 2567 self.print_ty(&ty, mode); 2568 self.push_str(","); 2569 } 2570 self.push_str(")"); 2571 } 2572 2573 fn special_case_trappable_error( 2574 &mut self, 2575 func: &Function, 2576 ) -> Option<(&'a Result_, TypeId, String)> { 2577 self.generator 2578 .used_trappable_imports_opts 2579 .insert(func.name.clone()); 2580 2581 let result = func.result?; 2582 2583 // We fillin a special trappable error type in the case when a function has just one 2584 // result, which is itself a `result<a, e>`, and the `e` is *not* a primitive 2585 // (i.e. defined in std) type, and matches the typename given by the user. 2586 let id = match result { 2587 Type::Id(id) => id, 2588 _ => return None, 2589 }; 2590 let result = match &self.resolve.types[id].kind { 2591 TypeDefKind::Result(r) => r, 2592 _ => return None, 2593 }; 2594 let error_typeid = match result.err? { 2595 Type::Id(id) => resolve_type_definition_id(&self.resolve, id), 2596 _ => return None, 2597 }; 2598 2599 let name = self.generator.trappable_errors.get(&error_typeid)?; 2600 2601 let mut path = self.path_to_root(); 2602 uwrite!(path, "{name}"); 2603 Some((result, error_typeid, path)) 2604 } 2605 2606 fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) { 2607 let iface = &self.resolve.interfaces[id]; 2608 let owner = TypeOwner::Interface(id); 2609 let wt = self.generator.wasmtime_path(); 2610 2611 let is_maybe_async = matches!(self.generator.opts.call_style(), CallStyle::Async); 2612 if is_maybe_async { 2613 uwriteln!( 2614 self.src, 2615 "#[{wt}::component::__internal::trait_variant_make(::core::marker::Send)]" 2616 ) 2617 } 2618 // Generate the `pub trait` which represents the host functionality for 2619 // this import which additionally inherits from all resource traits 2620 // for this interface defined by `type_resource`. 2621 2622 uwrite!(self.src, "pub trait Host"); 2623 let mut host_supertraits = vec![]; 2624 if is_maybe_async { 2625 host_supertraits.push("Send".to_string()); 2626 } 2627 let mut saw_resources = false; 2628 for (_, name) in get_resources(self.resolve, id) { 2629 saw_resources = true; 2630 host_supertraits.push(format!("Host{}", name.to_upper_camel_case())); 2631 } 2632 if saw_resources { 2633 host_supertraits.push("Sized".to_string()); 2634 } 2635 if !host_supertraits.is_empty() { 2636 uwrite!(self.src, ": {}", host_supertraits.join(" + ")); 2637 } 2638 uwriteln!(self.src, " {{"); 2639 2640 let has_concurrent_function = iface.functions.iter().any(|(_, func)| { 2641 matches!(func.kind, FunctionKind::Freestanding) 2642 && matches!( 2643 self.generator 2644 .opts 2645 .import_call_style(self.qualifier().as_deref(), &func.name), 2646 CallStyle::Concurrent 2647 ) 2648 }); 2649 2650 if has_concurrent_function { 2651 self.push_str("type Data;\n"); 2652 } 2653 2654 for (_, func) in iface.functions.iter() { 2655 match func.kind { 2656 FunctionKind::Freestanding => {} 2657 _ => continue, 2658 } 2659 self.generate_function_trait_sig(func, "Data"); 2660 self.push_str(";\n"); 2661 } 2662 2663 // Generate `convert_*` functions to convert custom trappable errors 2664 // into the representation required by Wasmtime's component API. 2665 let mut required_conversion_traits = IndexSet::new(); 2666 let mut errors_converted = IndexMap::new(); 2667 let mut my_error_types = iface 2668 .types 2669 .iter() 2670 .filter(|(_, id)| self.generator.trappable_errors.contains_key(*id)) 2671 .map(|(_, id)| *id) 2672 .collect::<Vec<_>>(); 2673 my_error_types.extend( 2674 iface 2675 .functions 2676 .iter() 2677 .filter_map(|(_, func)| self.special_case_trappable_error(func)) 2678 .map(|(_, id, _)| id), 2679 ); 2680 let root = self.path_to_root(); 2681 for err_id in my_error_types { 2682 let custom_name = &self.generator.trappable_errors[&err_id]; 2683 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err_id)]; 2684 let err_name = err.name.as_ref().unwrap(); 2685 let err_snake = err_name.to_snake_case(); 2686 let err_camel = err_name.to_upper_camel_case(); 2687 let owner = match err.owner { 2688 TypeOwner::Interface(i) => i, 2689 _ => unimplemented!(), 2690 }; 2691 match self.path_to_interface(owner) { 2692 Some(path) => { 2693 required_conversion_traits.insert(format!("{path}::Host")); 2694 } 2695 None => { 2696 if errors_converted.insert(err_name, err_id).is_none() { 2697 uwriteln!( 2698 self.src, 2699 "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{err_camel}>;" 2700 ); 2701 } 2702 } 2703 } 2704 } 2705 uwriteln!(self.src, "}}"); 2706 2707 let (data_bounds, mut host_bounds, mut get_host_bounds) = 2708 match self.generator.opts.call_style() { 2709 CallStyle::Async => ( 2710 "T: Send,".to_string(), 2711 "Host + Send".to_string(), 2712 "Host + Send".to_string(), 2713 ), 2714 CallStyle::Concurrent => { 2715 let constraints = concurrent_constraints( 2716 self.resolve, 2717 &self.generator.opts, 2718 self.qualifier().as_deref(), 2719 id, 2720 ); 2721 2722 ( 2723 "T: Send + 'static,".to_string(), 2724 format!("Host{} + Send", constraints("T")), 2725 format!("Host{} + Send", constraints("D")), 2726 ) 2727 } 2728 CallStyle::Sync => (String::new(), "Host".to_string(), "Host".to_string()), 2729 }; 2730 2731 for ty in required_conversion_traits { 2732 uwrite!(host_bounds, " + {ty}"); 2733 uwrite!(get_host_bounds, " + {ty}"); 2734 } 2735 2736 let (options_param, options_arg) = if self.generator.interface_link_options[&id].has_any() { 2737 ("options: &LinkOptions,", ", options") 2738 } else { 2739 ("", "") 2740 }; 2741 2742 uwriteln!( 2743 self.src, 2744 " 2745 pub trait GetHost<T, D>: 2746 Fn(T) -> <Self as GetHost<T, D>>::Host 2747 + Send 2748 + Sync 2749 + Copy 2750 + 'static 2751 {{ 2752 type Host: {get_host_bounds}; 2753 }} 2754 2755 impl<F, T, D, O> GetHost<T, D> for F 2756 where 2757 F: Fn(T) -> O + Send + Sync + Copy + 'static, 2758 O: {get_host_bounds}, 2759 {{ 2760 type Host = O; 2761 }} 2762 2763 pub fn add_to_linker_get_host<T, G: for<'a> GetHost<&'a mut T, T, Host: {host_bounds}>>( 2764 linker: &mut {wt}::component::Linker<T>, 2765 {options_param} 2766 host_getter: G, 2767 ) -> {wt}::Result<()> 2768 where {data_bounds} 2769 {{ 2770 " 2771 ); 2772 let gate = FeatureGate::open(&mut self.src, &iface.stability); 2773 uwriteln!(self.src, "let mut inst = linker.instance(\"{name}\")?;"); 2774 2775 for (ty, name) in get_resources(self.resolve, id) { 2776 Wasmtime::generate_add_resource_to_linker( 2777 self.qualifier().as_deref(), 2778 &mut self.src, 2779 &self.generator.opts, 2780 &wt, 2781 "inst", 2782 name, 2783 &self.resolve.types[ty].stability, 2784 ); 2785 } 2786 2787 for (_, func) in iface.functions.iter() { 2788 self.generate_add_function_to_linker(owner, func, "inst"); 2789 } 2790 gate.close(&mut self.src); 2791 uwriteln!(self.src, "Ok(())"); 2792 uwriteln!(self.src, "}}"); 2793 2794 if !self.generator.opts.skip_mut_forwarding_impls { 2795 // Generate add_to_linker (with closure) 2796 uwriteln!( 2797 self.src, 2798 " 2799 pub fn add_to_linker<T, U>( 2800 linker: &mut {wt}::component::Linker<T>, 2801 {options_param} 2802 get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, 2803 ) -> {wt}::Result<()> 2804 where 2805 U: {host_bounds}, {data_bounds} 2806 {{ 2807 add_to_linker_get_host(linker {options_arg}, get) 2808 }} 2809 " 2810 ); 2811 2812 // Generate impl Host for &mut Host 2813 let maybe_send = if is_maybe_async { "+ Send" } else { "" }; 2814 2815 let maybe_maybe_sized = if has_concurrent_function { 2816 "" 2817 } else { 2818 "+ ?Sized" 2819 }; 2820 2821 uwriteln!( 2822 self.src, 2823 "impl<_T: Host {maybe_maybe_sized} {maybe_send}> Host for &mut _T {{" 2824 ); 2825 2826 if has_concurrent_function { 2827 self.push_str("type Data = _T::Data;\n"); 2828 } 2829 2830 // Forward each method call to &mut T 2831 for (_, func) in iface.functions.iter() { 2832 match func.kind { 2833 FunctionKind::Freestanding => {} 2834 _ => continue, 2835 } 2836 let call_style = self 2837 .generator 2838 .opts 2839 .import_call_style(self.qualifier().as_deref(), &func.name); 2840 self.generate_function_trait_sig(func, "Data"); 2841 if let CallStyle::Concurrent = call_style { 2842 uwrite!( 2843 self.src, 2844 "{{ <_T as Host>::{}(store,", 2845 rust_function_name(func) 2846 ); 2847 } else { 2848 uwrite!(self.src, "{{ Host::{}(*self,", rust_function_name(func)); 2849 } 2850 for (name, _) in func.params.iter() { 2851 uwrite!(self.src, "{},", to_rust_ident(name)); 2852 } 2853 uwrite!(self.src, ")"); 2854 if let CallStyle::Async = call_style { 2855 uwrite!(self.src, ".await"); 2856 } 2857 uwriteln!(self.src, "}}"); 2858 } 2859 for (err_name, err_id) in errors_converted { 2860 uwriteln!( 2861 self.src, 2862 "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{err_camel}> {{ 2863 Host::convert_{err_snake}(*self, err) 2864 }}", 2865 custom_name = self.generator.trappable_errors[&err_id], 2866 err_snake = err_name.to_snake_case(), 2867 err_camel = err_name.to_upper_camel_case(), 2868 ); 2869 } 2870 uwriteln!(self.src, "}}"); 2871 } 2872 } 2873 2874 fn qualifier(&self) -> Option<String> { 2875 self.current_interface 2876 .map(|(_, key, _)| self.resolve.name_world_key(key)) 2877 } 2878 2879 fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) { 2880 let gate = FeatureGate::open(&mut self.src, &func.stability); 2881 uwrite!( 2882 self.src, 2883 "{linker}.{}(\"{}\", ", 2884 match self 2885 .generator 2886 .opts 2887 .import_call_style(self.qualifier().as_deref(), &func.name) 2888 { 2889 CallStyle::Sync => "func_wrap", 2890 CallStyle::Async => "func_wrap_async", 2891 CallStyle::Concurrent => "func_wrap_concurrent", 2892 }, 2893 func.name 2894 ); 2895 self.generate_guest_import_closure(owner, func); 2896 uwriteln!(self.src, ")?;"); 2897 gate.close(&mut self.src); 2898 } 2899 2900 fn generate_guest_import_closure(&mut self, owner: TypeOwner, func: &Function) { 2901 // Generate the closure that's passed to a `Linker`, the final piece of 2902 // codegen here. 2903 2904 let wt = self.generator.wasmtime_path(); 2905 uwrite!( 2906 self.src, 2907 "move |mut caller: {wt}::StoreContextMut<'_, T>, (" 2908 ); 2909 for (i, _param) in func.params.iter().enumerate() { 2910 uwrite!(self.src, "arg{},", i); 2911 } 2912 self.src.push_str(") : ("); 2913 2914 for (_, ty) in func.params.iter() { 2915 // Lift is required to be implied for this type, so we can't use 2916 // a borrowed type: 2917 self.print_ty(ty, TypeMode::Owned); 2918 self.src.push_str(", "); 2919 } 2920 self.src.push_str(")| {\n"); 2921 2922 let style = self 2923 .generator 2924 .opts 2925 .import_call_style(self.qualifier().as_deref(), &func.name); 2926 2927 if self.generator.opts.tracing { 2928 if let CallStyle::Async = style { 2929 self.src.push_str("use tracing::Instrument;\n"); 2930 } 2931 2932 uwrite!( 2933 self.src, 2934 " 2935 let span = tracing::span!( 2936 tracing::Level::TRACE, 2937 \"wit-bindgen import\", 2938 module = \"{}\", 2939 function = \"{}\", 2940 ); 2941 ", 2942 match owner { 2943 TypeOwner::Interface(id) => self.resolve.interfaces[id] 2944 .name 2945 .as_deref() 2946 .unwrap_or("<no module>"), 2947 TypeOwner::World(id) => &self.resolve.worlds[id].name, 2948 TypeOwner::None => "<no owner>", 2949 }, 2950 func.name, 2951 ); 2952 } 2953 2954 if let CallStyle::Async = &style { 2955 uwriteln!( 2956 self.src, 2957 " {wt}::component::__internal::Box::new(async move {{ " 2958 ); 2959 } else { 2960 // Only directly enter the span if the function is sync. Otherwise 2961 // we use tracing::Instrument to ensure that the span is not entered 2962 // across an await point. 2963 if self.generator.opts.tracing { 2964 self.push_str("let _enter = span.enter();\n"); 2965 } 2966 } 2967 2968 if self.generator.opts.tracing { 2969 let mut event_fields = func 2970 .params 2971 .iter() 2972 .enumerate() 2973 .map(|(i, (name, ty))| { 2974 let name = to_rust_ident(&name); 2975 formatting_for_arg(&name, i, *ty, &self.generator.opts, &self.resolve) 2976 }) 2977 .collect::<Vec<String>>(); 2978 event_fields.push(format!("\"call\"")); 2979 uwrite!( 2980 self.src, 2981 "tracing::event!(tracing::Level::TRACE, {});\n", 2982 event_fields.join(", ") 2983 ); 2984 } 2985 2986 self.src.push_str(if let CallStyle::Concurrent = &style { 2987 "let host = caller;\n" 2988 } else { 2989 "let host = &mut host_getter(caller.data_mut());\n" 2990 }); 2991 let func_name = rust_function_name(func); 2992 let host_trait = match func.kind.resource() { 2993 None => match owner { 2994 TypeOwner::World(id) => format!( 2995 "{}Imports", 2996 rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name) 2997 ), 2998 _ => "Host".to_string(), 2999 }, 3000 Some(id) => { 3001 let resource = self.resolve.types[id] 3002 .name 3003 .as_ref() 3004 .unwrap() 3005 .to_upper_camel_case(); 3006 format!("Host{resource}") 3007 } 3008 }; 3009 3010 if let CallStyle::Concurrent = &style { 3011 uwrite!( 3012 self.src, 3013 "let r = <G::Host as {host_trait}>::{func_name}(host, " 3014 ); 3015 } else { 3016 uwrite!(self.src, "let r = {host_trait}::{func_name}(host, "); 3017 } 3018 3019 for (i, _) in func.params.iter().enumerate() { 3020 uwrite!(self.src, "arg{},", i); 3021 } 3022 3023 self.src.push_str(match &style { 3024 CallStyle::Sync | CallStyle::Concurrent => ");\n", 3025 CallStyle::Async => ").await;\n", 3026 }); 3027 3028 if let CallStyle::Concurrent = &style { 3029 self.src.push_str( 3030 "Box::pin(async move { 3031 let fun = r.await; 3032 Box::new(move |mut caller: wasmtime::StoreContextMut<'_, T>| { 3033 let r = fun(caller); 3034 ", 3035 ); 3036 } 3037 3038 if self.generator.opts.tracing { 3039 uwrite!( 3040 self.src, 3041 "tracing::event!(tracing::Level::TRACE, {}, \"return\");", 3042 formatting_for_results(func.result, &self.generator.opts, &self.resolve) 3043 ); 3044 } 3045 3046 if !self.generator.opts.trappable_imports.can_trap(&func) { 3047 if func.result.is_some() { 3048 uwrite!(self.src, "Ok((r,))\n"); 3049 } else { 3050 uwrite!(self.src, "Ok(r)\n"); 3051 } 3052 } else if let Some((_, err, _)) = self.special_case_trappable_error(func) { 3053 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)]; 3054 let err_name = err.name.as_ref().unwrap(); 3055 let owner = match err.owner { 3056 TypeOwner::Interface(i) => i, 3057 _ => unimplemented!(), 3058 }; 3059 let convert_trait = match self.path_to_interface(owner) { 3060 Some(path) => format!("{path}::Host"), 3061 None => format!("Host"), 3062 }; 3063 let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case()); 3064 uwrite!( 3065 self.src, 3066 "Ok((match r {{ 3067 Ok(a) => Ok(a), 3068 Err(e) => Err({convert}(host, e)?), 3069 }},))" 3070 ); 3071 } else if func.result.is_some() { 3072 uwrite!(self.src, "Ok((r?,))\n"); 3073 } else { 3074 uwrite!(self.src, "r\n"); 3075 } 3076 3077 match &style { 3078 CallStyle::Sync => (), 3079 CallStyle::Async => { 3080 if self.generator.opts.tracing { 3081 self.src.push_str("}.instrument(span))\n"); 3082 } else { 3083 self.src.push_str("})\n"); 3084 } 3085 } 3086 CallStyle::Concurrent => { 3087 let old_source = mem::take(&mut self.src); 3088 self.print_result_ty_tuple(func.result, TypeMode::Owned); 3089 let result_type = String::from(mem::replace(&mut self.src, old_source)); 3090 let box_fn = format!( 3091 "Box<dyn FnOnce(wasmtime::StoreContextMut<'_, T>) -> \ 3092 wasmtime::Result<{result_type}> + Send + Sync>" 3093 ); 3094 uwriteln!( 3095 self.src, 3096 " }}) as {box_fn} 3097 }}) as ::core::pin::Pin<Box<dyn ::core::future::Future<Output = {box_fn}> \ 3098 + Send + Sync + 'static>> 3099 " 3100 ); 3101 } 3102 } 3103 self.src.push_str("}\n"); 3104 } 3105 3106 fn generate_function_trait_sig(&mut self, func: &Function, data: &str) { 3107 let wt = self.generator.wasmtime_path(); 3108 self.rustdoc(&func.docs); 3109 3110 let style = self 3111 .generator 3112 .opts 3113 .import_call_style(self.qualifier().as_deref(), &func.name); 3114 if let CallStyle::Async = &style { 3115 self.push_str("async "); 3116 } 3117 self.push_str("fn "); 3118 self.push_str(&rust_function_name(func)); 3119 self.push_str(&if let CallStyle::Concurrent = &style { 3120 format!("(store: wasmtime::StoreContextMut<'_, Self::{data}>, ") 3121 } else { 3122 "(&mut self, ".to_string() 3123 }); 3124 for (name, param) in func.params.iter() { 3125 let name = to_rust_ident(name); 3126 self.push_str(&name); 3127 self.push_str(": "); 3128 self.print_ty(param, TypeMode::Owned); 3129 self.push_str(","); 3130 } 3131 self.push_str(")"); 3132 self.push_str(" -> "); 3133 3134 if let CallStyle::Concurrent = &style { 3135 uwrite!(self.src, "impl ::core::future::Future<Output = impl FnOnce(wasmtime::StoreContextMut<'_, Self::{data}>) -> "); 3136 } 3137 3138 if !self.generator.opts.trappable_imports.can_trap(func) { 3139 self.print_result_ty(func.result, TypeMode::Owned); 3140 } else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) { 3141 // Functions which have a single result `result<ok,err>` get special 3142 // cased to use the host_wasmtime_rust::Error<err>, making it possible 3143 // for them to trap or use `?` to propagate their errors 3144 self.push_str("Result<"); 3145 if let Some(ok) = r.ok { 3146 self.print_ty(&ok, TypeMode::Owned); 3147 } else { 3148 self.push_str("()"); 3149 } 3150 self.push_str(","); 3151 self.push_str(&error_typename); 3152 self.push_str(">"); 3153 } else { 3154 // All other functions get their return values wrapped in an wasmtime::Result. 3155 // Returning the anyhow::Error case can be used to trap. 3156 uwrite!(self.src, "{wt}::Result<"); 3157 self.print_result_ty(func.result, TypeMode::Owned); 3158 self.push_str(">"); 3159 } 3160 3161 if let CallStyle::Concurrent = &style { 3162 self.push_str(" + Send + Sync + 'static> + Send + Sync + 'static where Self: Sized"); 3163 } 3164 } 3165 3166 fn extract_typed_function(&mut self, func: &Function) -> (String, String) { 3167 let prev = mem::take(&mut self.src); 3168 let snake = func_field_name(self.resolve, func); 3169 uwrite!(self.src, "*_instance.get_typed_func::<("); 3170 for (_, ty) in func.params.iter() { 3171 self.print_ty(ty, TypeMode::AllBorrowed("'_")); 3172 self.push_str(", "); 3173 } 3174 self.src.push_str("), ("); 3175 if let Some(ty) = func.result { 3176 self.print_ty(&ty, TypeMode::Owned); 3177 self.push_str(", "); 3178 } 3179 uwriteln!(self.src, ")>(&mut store, &self.{snake})?.func()"); 3180 3181 let ret = (snake, mem::take(&mut self.src).to_string()); 3182 self.src = prev; 3183 ret 3184 } 3185 3186 fn define_rust_guest_export( 3187 &mut self, 3188 resolve: &Resolve, 3189 ns: Option<&WorldKey>, 3190 func: &Function, 3191 ) { 3192 // Exports must be async if anything could be async, it's just imports 3193 // that get to be optionally async/sync. 3194 let style = self.generator.opts.call_style(); 3195 let (async_, async__, await_, concurrent) = match &style { 3196 CallStyle::Async | CallStyle::Concurrent => { 3197 if self.generator.opts.concurrent_exports { 3198 ("async", "INVALID", "INVALID", true) 3199 } else { 3200 ("async", "_async", ".await", false) 3201 } 3202 } 3203 CallStyle::Sync => ("", "", "", false), 3204 }; 3205 3206 self.rustdoc(&func.docs); 3207 let wt = self.generator.wasmtime_path(); 3208 3209 uwrite!( 3210 self.src, 3211 "pub {async_} fn call_{}<S: {wt}::AsContextMut>(&self, mut store: S, ", 3212 func.item_name().to_snake_case(), 3213 ); 3214 3215 let param_mode = if let CallStyle::Concurrent = &style { 3216 TypeMode::Owned 3217 } else { 3218 TypeMode::AllBorrowed("'_") 3219 }; 3220 3221 for (i, param) in func.params.iter().enumerate() { 3222 uwrite!(self.src, "arg{}: ", i); 3223 self.print_ty(¶m.1, param_mode); 3224 self.push_str(","); 3225 } 3226 3227 uwrite!(self.src, ") -> {wt}::Result<"); 3228 if concurrent { 3229 uwrite!(self.src, "{wt}::component::Promise<"); 3230 } 3231 self.print_result_ty(func.result, TypeMode::Owned); 3232 if concurrent { 3233 uwrite!(self.src, ">"); 3234 } 3235 3236 let maybe_static = if concurrent { " + 'static" } else { "" }; 3237 3238 uwrite!( 3239 self.src, 3240 "> where <S as {wt}::AsContext>::Data: Send{maybe_static} {{\n" 3241 ); 3242 3243 // TODO: support tracing concurrent calls 3244 if self.generator.opts.tracing && !concurrent { 3245 if let CallStyle::Async = &style { 3246 self.src.push_str("use tracing::Instrument;\n"); 3247 } 3248 3249 let ns = match ns { 3250 Some(key) => resolve.name_world_key(key), 3251 None => "default".to_string(), 3252 }; 3253 self.src.push_str(&format!( 3254 " 3255 let span = tracing::span!( 3256 tracing::Level::TRACE, 3257 \"wit-bindgen export\", 3258 module = \"{ns}\", 3259 function = \"{}\", 3260 ); 3261 ", 3262 func.name, 3263 )); 3264 3265 if !matches!(&style, CallStyle::Async) { 3266 self.src.push_str( 3267 " 3268 let _enter = span.enter(); 3269 ", 3270 ); 3271 } 3272 } 3273 3274 self.src.push_str("let callee = unsafe {\n"); 3275 uwrite!(self.src, "{wt}::component::TypedFunc::<("); 3276 for (_, ty) in func.params.iter() { 3277 self.print_ty(ty, param_mode); 3278 self.push_str(", "); 3279 } 3280 self.src.push_str("), ("); 3281 if let Some(ty) = func.result { 3282 self.print_ty(&ty, TypeMode::Owned); 3283 self.push_str(", "); 3284 } 3285 let projection_to_func = match &func.kind { 3286 FunctionKind::Freestanding => "", 3287 _ => ".funcs", 3288 }; 3289 uwriteln!( 3290 self.src, 3291 ")>::new_unchecked(self{projection_to_func}.{})", 3292 func_field_name(self.resolve, func), 3293 ); 3294 self.src.push_str("};\n"); 3295 3296 if concurrent { 3297 uwrite!( 3298 self.src, 3299 "let promise = callee.call_concurrent(store.as_context_mut(), (" 3300 ); 3301 for (i, _) in func.params.iter().enumerate() { 3302 uwrite!(self.src, "arg{i}, "); 3303 } 3304 self.src.push_str(")).await?;"); 3305 3306 if func.result.is_some() { 3307 self.src.push_str("Ok(promise.map(|(v,)| v))\n"); 3308 } else { 3309 self.src.push_str("Ok(promise)"); 3310 } 3311 } else { 3312 self.src.push_str("let ("); 3313 if func.result.is_some() { 3314 uwrite!(self.src, "ret0,"); 3315 } 3316 uwrite!( 3317 self.src, 3318 ") = callee.call{async__}(store.as_context_mut(), (" 3319 ); 3320 for (i, _) in func.params.iter().enumerate() { 3321 uwrite!(self.src, "arg{}, ", i); 3322 } 3323 3324 let instrument = if matches!(&style, CallStyle::Async) && self.generator.opts.tracing { 3325 ".instrument(span.clone())" 3326 } else { 3327 "" 3328 }; 3329 uwriteln!(self.src, ")){instrument}{await_}?;"); 3330 3331 let instrument = if matches!(&style, CallStyle::Async) && self.generator.opts.tracing { 3332 ".instrument(span)" 3333 } else { 3334 "" 3335 }; 3336 3337 uwriteln!( 3338 self.src, 3339 "callee.post_return{async__}(store.as_context_mut()){instrument}{await_}?;" 3340 ); 3341 3342 self.src.push_str("Ok("); 3343 if func.result.is_some() { 3344 self.src.push_str("ret0"); 3345 } else { 3346 self.src.push_str("()"); 3347 } 3348 self.src.push_str(")\n"); 3349 } 3350 3351 // End function body 3352 self.src.push_str("}\n"); 3353 } 3354 3355 fn rustdoc(&mut self, docs: &Docs) { 3356 let docs = match &docs.contents { 3357 Some(docs) => docs, 3358 None => return, 3359 }; 3360 for line in docs.trim().lines() { 3361 self.push_str("/// "); 3362 self.push_str(line); 3363 self.push_str("\n"); 3364 } 3365 } 3366 3367 fn path_to_root(&self) -> String { 3368 let mut path_to_root = String::new(); 3369 if let Some((_, key, is_export)) = self.current_interface { 3370 match key { 3371 WorldKey::Name(_) => { 3372 path_to_root.push_str("super::"); 3373 } 3374 WorldKey::Interface(_) => { 3375 path_to_root.push_str("super::super::super::"); 3376 } 3377 } 3378 if is_export { 3379 path_to_root.push_str("super::"); 3380 } 3381 } 3382 path_to_root 3383 } 3384 } 3385 3386 impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> { 3387 fn resolve(&self) -> &'a Resolve { 3388 self.resolve 3389 } 3390 3391 fn ownership(&self) -> Ownership { 3392 self.generator.opts.ownership 3393 } 3394 3395 fn path_to_interface(&self, interface: InterfaceId) -> Option<String> { 3396 if let Some((cur, _, _)) = self.current_interface { 3397 if cur == interface { 3398 return None; 3399 } 3400 } 3401 let mut path_to_root = self.path_to_root(); 3402 match &self.generator.interface_names[&interface] { 3403 InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root), 3404 InterfaceName::Path(path) => { 3405 for (i, name) in path.iter().enumerate() { 3406 if i > 0 { 3407 path_to_root.push_str("::"); 3408 } 3409 path_to_root.push_str(name); 3410 } 3411 } 3412 } 3413 Some(path_to_root) 3414 } 3415 3416 fn push_str(&mut self, s: &str) { 3417 self.src.push_str(s); 3418 } 3419 3420 fn info(&self, ty: TypeId) -> TypeInfo { 3421 self.generator.types.get(ty) 3422 } 3423 3424 fn is_imported_interface(&self, interface: InterfaceId) -> bool { 3425 self.generator.interface_last_seen_as_import[&interface] 3426 } 3427 3428 fn wasmtime_path(&self) -> String { 3429 self.generator.wasmtime_path() 3430 } 3431 } 3432 3433 #[derive(Default)] 3434 struct LinkOptionsBuilder { 3435 unstable_features: BTreeSet<String>, 3436 } 3437 impl LinkOptionsBuilder { 3438 fn has_any(&self) -> bool { 3439 !self.unstable_features.is_empty() 3440 } 3441 fn add_world(&mut self, resolve: &Resolve, id: &WorldId) { 3442 let world = &resolve.worlds[*id]; 3443 3444 self.add_stability(&world.stability); 3445 3446 for (_, import) in world.imports.iter() { 3447 match import { 3448 WorldItem::Interface { id, stability } => { 3449 self.add_stability(stability); 3450 self.add_interface(resolve, id); 3451 } 3452 WorldItem::Function(f) => { 3453 self.add_stability(&f.stability); 3454 } 3455 WorldItem::Type(t) => { 3456 self.add_type(resolve, t); 3457 } 3458 } 3459 } 3460 } 3461 fn add_interface(&mut self, resolve: &Resolve, id: &InterfaceId) { 3462 let interface = &resolve.interfaces[*id]; 3463 3464 self.add_stability(&interface.stability); 3465 3466 for (_, t) in interface.types.iter() { 3467 self.add_type(resolve, t); 3468 } 3469 for (_, f) in interface.functions.iter() { 3470 self.add_stability(&f.stability); 3471 } 3472 } 3473 fn add_type(&mut self, resolve: &Resolve, id: &TypeId) { 3474 let t = &resolve.types[*id]; 3475 self.add_stability(&t.stability); 3476 } 3477 fn add_stability(&mut self, stability: &Stability) { 3478 match stability { 3479 Stability::Unstable { feature, .. } => { 3480 self.unstable_features.insert(feature.clone()); 3481 } 3482 Stability::Stable { .. } | Stability::Unknown => {} 3483 } 3484 } 3485 fn write_struct(&self, src: &mut Source) { 3486 if !self.has_any() { 3487 return; 3488 } 3489 3490 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>(); 3491 unstable_features.sort(); 3492 3493 uwriteln!( 3494 src, 3495 " 3496 /// Link-time configurations. 3497 #[derive(Clone, Debug, Default)] 3498 pub struct LinkOptions {{ 3499 " 3500 ); 3501 3502 for feature in unstable_features.iter() { 3503 let feature_rust_name = feature.to_snake_case(); 3504 uwriteln!(src, "{feature_rust_name}: bool,"); 3505 } 3506 3507 uwriteln!(src, "}}"); 3508 uwriteln!(src, "impl LinkOptions {{"); 3509 3510 for feature in unstable_features.iter() { 3511 let feature_rust_name = feature.to_snake_case(); 3512 uwriteln!( 3513 src, 3514 " 3515 /// Enable members marked as `@unstable(feature = {feature})` 3516 pub fn {feature_rust_name}(&mut self, enabled: bool) -> &mut Self {{ 3517 self.{feature_rust_name} = enabled; 3518 self 3519 }} 3520 " 3521 ); 3522 } 3523 3524 uwriteln!(src, "}}"); 3525 } 3526 fn write_impl_from_world(&self, src: &mut Source, path: &str) { 3527 if !self.has_any() { 3528 return; 3529 } 3530 3531 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>(); 3532 unstable_features.sort(); 3533 3534 uwriteln!( 3535 src, 3536 " 3537 impl core::convert::From<LinkOptions> for {path}::LinkOptions {{ 3538 fn from(src: LinkOptions) -> Self {{ 3539 (&src).into() 3540 }} 3541 }} 3542 3543 impl core::convert::From<&LinkOptions> for {path}::LinkOptions {{ 3544 fn from(src: &LinkOptions) -> Self {{ 3545 let mut dest = Self::default(); 3546 " 3547 ); 3548 3549 for feature in unstable_features.iter() { 3550 let feature_rust_name = feature.to_snake_case(); 3551 uwriteln!(src, "dest.{feature_rust_name}(src.{feature_rust_name});"); 3552 } 3553 3554 uwriteln!( 3555 src, 3556 " 3557 dest 3558 }} 3559 }} 3560 " 3561 ); 3562 } 3563 } 3564 3565 struct FeatureGate { 3566 close: bool, 3567 } 3568 impl FeatureGate { 3569 fn open(src: &mut Source, stability: &Stability) -> FeatureGate { 3570 let close = if let Stability::Unstable { feature, .. } = stability { 3571 let feature_rust_name = feature.to_snake_case(); 3572 uwrite!(src, "if options.{feature_rust_name} {{"); 3573 true 3574 } else { 3575 false 3576 }; 3577 Self { close } 3578 } 3579 3580 fn close(self, src: &mut Source) { 3581 if self.close { 3582 uwriteln!(src, "}}"); 3583 } 3584 } 3585 } 3586 3587 /// Produce a string for tracing a function argument. 3588 fn formatting_for_arg( 3589 name: &str, 3590 index: usize, 3591 ty: Type, 3592 opts: &Opts, 3593 resolve: &Resolve, 3594 ) -> String { 3595 if !opts.verbose_tracing && type_contains_lists(ty, resolve) { 3596 return format!("{name} = tracing::field::debug(\"...\")"); 3597 } 3598 3599 // Normal tracing. 3600 format!("{name} = tracing::field::debug(&arg{index})") 3601 } 3602 3603 /// Produce a string for tracing function results. 3604 fn formatting_for_results(result: Option<Type>, opts: &Opts, resolve: &Resolve) -> String { 3605 let contains_lists = match result { 3606 Some(ty) => type_contains_lists(ty, resolve), 3607 None => false, 3608 }; 3609 3610 if !opts.verbose_tracing && contains_lists { 3611 return format!("result = tracing::field::debug(\"...\")"); 3612 } 3613 3614 // Normal tracing. 3615 format!("result = tracing::field::debug(&r)") 3616 } 3617 3618 /// Test whether the given type contains lists. 3619 /// 3620 /// Here, a `string` is not considered a list. 3621 fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool { 3622 match ty { 3623 Type::Id(id) => match &resolve.types[id].kind { 3624 TypeDefKind::Resource 3625 | TypeDefKind::Unknown 3626 | TypeDefKind::Flags(_) 3627 | TypeDefKind::Handle(_) 3628 | TypeDefKind::Enum(_) 3629 | TypeDefKind::Stream(_) 3630 | TypeDefKind::Future(_) => false, 3631 TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve), 3632 TypeDefKind::Result(Result_ { ok, err }) => { 3633 option_type_contains_lists(*ok, resolve) 3634 || option_type_contains_lists(*err, resolve) 3635 } 3636 TypeDefKind::Record(record) => record 3637 .fields 3638 .iter() 3639 .any(|field| type_contains_lists(field.ty, resolve)), 3640 TypeDefKind::Tuple(tuple) => tuple 3641 .types 3642 .iter() 3643 .any(|ty| type_contains_lists(*ty, resolve)), 3644 TypeDefKind::Variant(variant) => variant 3645 .cases 3646 .iter() 3647 .any(|case| option_type_contains_lists(case.ty, resolve)), 3648 TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve), 3649 TypeDefKind::List(_) => true, 3650 }, 3651 3652 // Technically strings are lists too, but we ignore that here because 3653 // they're usually short. 3654 _ => false, 3655 } 3656 } 3657 3658 fn option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool { 3659 match ty { 3660 Some(ty) => type_contains_lists(ty, resolve), 3661 None => false, 3662 } 3663 } 3664 3665 /// When an interface `use`s a type from another interface, it creates a new TypeId 3666 /// referring to the definition TypeId. Chase this chain of references down to 3667 /// a TypeId for type's definition. 3668 fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId { 3669 loop { 3670 match resolve.types[id].kind { 3671 TypeDefKind::Type(Type::Id(def_id)) => id = def_id, 3672 _ => return id, 3673 } 3674 } 3675 } 3676 3677 fn rust_function_name(func: &Function) -> String { 3678 match func.kind { 3679 FunctionKind::Constructor(_) => "new".to_string(), 3680 FunctionKind::Method(_) 3681 | FunctionKind::Static(_) 3682 | FunctionKind::AsyncMethod(_) 3683 | FunctionKind::AsyncStatic(_) 3684 | FunctionKind::Freestanding 3685 | FunctionKind::AsyncFreestanding => to_rust_ident(func.item_name()), 3686 } 3687 } 3688 3689 fn func_field_name(resolve: &Resolve, func: &Function) -> String { 3690 let mut name = String::new(); 3691 match func.kind { 3692 FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => { 3693 name.push_str("method-"); 3694 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3695 name.push_str("-"); 3696 } 3697 FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => { 3698 name.push_str("static-"); 3699 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3700 name.push_str("-"); 3701 } 3702 FunctionKind::Constructor(id) => { 3703 name.push_str("constructor-"); 3704 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3705 name.push_str("-"); 3706 } 3707 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {} 3708 } 3709 name.push_str(func.item_name()); 3710 name.to_snake_case() 3711 } 3712 3713 fn get_resources<'a>( 3714 resolve: &'a Resolve, 3715 id: InterfaceId, 3716 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a { 3717 resolve.interfaces[id] 3718 .types 3719 .iter() 3720 .filter_map(move |(name, ty)| match &resolve.types[*ty].kind { 3721 TypeDefKind::Resource => Some((*ty, name.as_str())), 3722 _ => None, 3723 }) 3724 } 3725 3726 fn get_world_resources<'a>( 3727 resolve: &'a Resolve, 3728 id: WorldId, 3729 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a { 3730 resolve.worlds[id] 3731 .imports 3732 .iter() 3733 .filter_map(move |(name, item)| match item { 3734 WorldItem::Type(id) => match resolve.types[*id].kind { 3735 TypeDefKind::Resource => Some(match name { 3736 WorldKey::Name(s) => (*id, s.as_str()), 3737 WorldKey::Interface(_) => unreachable!(), 3738 }), 3739 _ => None, 3740 }, 3741 _ => None, 3742 }) 3743 } 3744 3745 fn concurrent_constraints<'a>( 3746 resolve: &'a Resolve, 3747 opts: &Opts, 3748 qualifier: Option<&str>, 3749 id: InterfaceId, 3750 ) -> impl Fn(&str) -> String + use<'a> { 3751 let has_concurrent_function = resolve.interfaces[id].functions.iter().any(|(_, func)| { 3752 matches!(func.kind, FunctionKind::Freestanding) 3753 && matches!( 3754 opts.import_call_style(qualifier, &func.name), 3755 CallStyle::Concurrent 3756 ) 3757 }); 3758 3759 let types = resolve.interfaces[id] 3760 .types 3761 .iter() 3762 .filter_map(|(name, ty)| match resolve.types[*ty].kind { 3763 TypeDefKind::Resource 3764 if resolve.interfaces[id].functions.values().any(|func| { 3765 match func.kind.resource() { 3766 None => false, 3767 Some(resource) => { 3768 *ty == resource 3769 && matches!( 3770 opts.import_call_style(qualifier, &func.name), 3771 CallStyle::Concurrent 3772 ) 3773 } 3774 } 3775 }) => 3776 { 3777 Some(format!("{}Data", name.to_upper_camel_case())) 3778 } 3779 _ => None, 3780 }) 3781 .chain(has_concurrent_function.then_some("Data".to_string())) 3782 .collect::<Vec<_>>(); 3783 3784 move |v| { 3785 if types.is_empty() { 3786 String::new() 3787 } else { 3788 format!( 3789 "<{}>", 3790 types 3791 .iter() 3792 .map(|s| format!("{s} = {v}")) 3793 .collect::<Vec<_>>() 3794 .join(", ") 3795 ) 3796 } 3797 } 3798 } 3799 3800 fn world_imports_concurrent_constraints<'a>( 3801 resolve: &'a Resolve, 3802 world: WorldId, 3803 opts: &Opts, 3804 ) -> impl Fn(&str) -> String + use<'a> { 3805 let has_concurrent_function = resolve.worlds[world] 3806 .imports 3807 .values() 3808 .any(|item| match item { 3809 WorldItem::Function(func) => { 3810 matches!(func.kind, FunctionKind::Freestanding) 3811 && matches!( 3812 opts.import_call_style(None, &func.name), 3813 CallStyle::Concurrent 3814 ) 3815 } 3816 WorldItem::Interface { .. } | WorldItem::Type(_) => false, 3817 }); 3818 3819 let types = resolve.worlds[world] 3820 .imports 3821 .iter() 3822 .filter_map(|(name, item)| match (name, item) { 3823 (WorldKey::Name(name), WorldItem::Type(ty)) => match resolve.types[*ty].kind { 3824 TypeDefKind::Resource 3825 if resolve.worlds[world] 3826 .imports 3827 .values() 3828 .any(|item| match item { 3829 WorldItem::Function(func) => match func.kind.resource() { 3830 None => false, 3831 Some(resource) => { 3832 *ty == resource 3833 && matches!( 3834 opts.import_call_style(None, &func.name), 3835 CallStyle::Concurrent 3836 ) 3837 } 3838 }, 3839 WorldItem::Interface { .. } | WorldItem::Type(_) => false, 3840 }) => 3841 { 3842 Some(format!("{}Data", name.to_upper_camel_case())) 3843 } 3844 _ => None, 3845 }, 3846 _ => None, 3847 }) 3848 .chain(has_concurrent_function.then_some("Data".to_string())) 3849 .collect::<Vec<_>>(); 3850 3851 move |v| { 3852 if types.is_empty() { 3853 String::new() 3854 } else { 3855 format!( 3856 "<{}>", 3857 types 3858 .iter() 3859 .map(|s| format!("{s} = {v}")) 3860 .collect::<Vec<_>>() 3861 .join(", ") 3862 ) 3863 } 3864 } 3865 } 3866