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