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