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