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!(self.src, "move |caller: &{wt}::component::Accessor::<T>, ("); 2457 } else { 2458 uwrite!( 2459 self.src, 2460 "move |mut caller: {wt}::StoreContextMut<'_, T>, (" 2461 ); 2462 } 2463 for (i, _param) in func.params.iter().enumerate() { 2464 uwrite!(self.src, "arg{},", i); 2465 } 2466 self.src.push_str(") : ("); 2467 2468 for (_, ty) in func.params.iter() { 2469 // Lift is required to be implied for this type, so we can't use 2470 // a borrowed type: 2471 self.print_ty(ty, TypeMode::Owned); 2472 self.src.push_str(", "); 2473 } 2474 self.src.push_str(")| {\n"); 2475 2476 if self.generator.opts.tracing { 2477 if let CallStyle::Async | CallStyle::Concurrent = style { 2478 self.src.push_str("use tracing::Instrument;\n"); 2479 } 2480 2481 uwrite!( 2482 self.src, 2483 " 2484 let span = tracing::span!( 2485 tracing::Level::TRACE, 2486 \"wit-bindgen import\", 2487 module = \"{}\", 2488 function = \"{}\", 2489 ); 2490 ", 2491 match owner { 2492 TypeOwner::Interface(id) => self.resolve.interfaces[id] 2493 .name 2494 .as_deref() 2495 .unwrap_or("<no module>"), 2496 TypeOwner::World(id) => &self.resolve.worlds[id].name, 2497 TypeOwner::None => "<no owner>", 2498 }, 2499 func.name, 2500 ); 2501 } 2502 2503 match &style { 2504 CallStyle::Async => { 2505 uwriteln!( 2506 self.src, 2507 "{wt}::component::__internal::Box::new(async move {{" 2508 ); 2509 } 2510 CallStyle::Concurrent => { 2511 uwriteln!( 2512 self.src, 2513 "{wt}::component::__internal::Box::pin(async move {{ 2514 let accessor = &mut unsafe {{ caller.with_data(host_getter) }}; 2515 " 2516 ); 2517 } 2518 CallStyle::Sync => { 2519 // Only directly enter the span if the function is sync. Otherwise 2520 // we use tracing::Instrument to ensure that the span is not entered 2521 // across an await point. 2522 if self.generator.opts.tracing { 2523 self.push_str("let _enter = span.enter();\n"); 2524 } 2525 } 2526 } 2527 2528 if self.generator.opts.tracing { 2529 let mut event_fields = func 2530 .params 2531 .iter() 2532 .enumerate() 2533 .map(|(i, (name, ty))| { 2534 let name = to_rust_ident(&name); 2535 formatting_for_arg(&name, i, *ty, &self.generator.opts, &self.resolve) 2536 }) 2537 .collect::<Vec<String>>(); 2538 event_fields.push(format!("\"call\"")); 2539 uwrite!( 2540 self.src, 2541 "tracing::event!(tracing::Level::TRACE, {});\n", 2542 event_fields.join(", ") 2543 ); 2544 } 2545 2546 if !matches!(style, CallStyle::Concurrent) { 2547 self.src 2548 .push_str("let host = &mut host_getter(caller.data_mut());\n"); 2549 } 2550 let func_name = rust_function_name(func); 2551 let host_trait = match func.kind.resource() { 2552 None => match owner { 2553 TypeOwner::World(id) => format!( 2554 "{}Imports", 2555 rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name) 2556 ), 2557 _ => "Host".to_string(), 2558 }, 2559 Some(id) => { 2560 let resource = self.resolve.types[id] 2561 .name 2562 .as_ref() 2563 .unwrap() 2564 .to_upper_camel_case(); 2565 format!("Host{resource}") 2566 } 2567 }; 2568 2569 if let CallStyle::Concurrent = &style { 2570 uwrite!( 2571 self.src, 2572 "let r = <D as {host_trait}Concurrent>::{func_name}(accessor, " 2573 ); 2574 } else { 2575 uwrite!(self.src, "let r = {host_trait}::{func_name}(host, "); 2576 } 2577 2578 for (i, _) in func.params.iter().enumerate() { 2579 uwrite!(self.src, "arg{},", i); 2580 } 2581 2582 self.src.push_str(match &style { 2583 CallStyle::Sync => ");\n", 2584 CallStyle::Async | CallStyle::Concurrent => ").await;\n", 2585 }); 2586 2587 if self.generator.opts.tracing { 2588 uwrite!( 2589 self.src, 2590 "tracing::event!(tracing::Level::TRACE, {}, \"return\");", 2591 formatting_for_results(func.result, &self.generator.opts, &self.resolve) 2592 ); 2593 } 2594 2595 if !self.generator.opts.trappable_imports.can_trap(&func) { 2596 if func.result.is_some() { 2597 uwrite!(self.src, "Ok((r,))\n"); 2598 } else { 2599 uwrite!(self.src, "Ok(r)\n"); 2600 } 2601 } else if let Some((_, err, _)) = self.special_case_trappable_error(func) { 2602 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)]; 2603 let err_name = err.name.as_ref().unwrap(); 2604 let owner = match err.owner { 2605 TypeOwner::Interface(i) => i, 2606 _ => unimplemented!(), 2607 }; 2608 let convert_trait = match self.path_to_interface(owner) { 2609 Some(path) => format!("{path}::Host"), 2610 None => format!("Host"), 2611 }; 2612 let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case()); 2613 uwrite!( 2614 self.src, 2615 "Ok((match r {{ 2616 Ok(a) => Ok(a), 2617 Err(e) => Err({convert}(host, e)?), 2618 }},))" 2619 ); 2620 } else if func.result.is_some() { 2621 uwrite!(self.src, "Ok((r?,))\n"); 2622 } else { 2623 uwrite!(self.src, "r\n"); 2624 } 2625 2626 match &style { 2627 CallStyle::Sync => (), 2628 CallStyle::Async | CallStyle::Concurrent => { 2629 if self.generator.opts.tracing { 2630 self.src.push_str("}.instrument(span))\n"); 2631 } else { 2632 self.src.push_str("})\n"); 2633 } 2634 } 2635 } 2636 2637 self.src.push_str("}\n"); 2638 } 2639 2640 fn generate_function_trait_sig(&mut self, func: &Function, async_sugar: bool) { 2641 let wt = self.generator.wasmtime_path(); 2642 self.rustdoc(&func.docs); 2643 2644 let style = self.import_call_style(func); 2645 if let (CallStyle::Async, _) | (CallStyle::Concurrent, true) = (&style, async_sugar) { 2646 self.push_str("async "); 2647 } 2648 self.push_str("fn "); 2649 self.push_str(&rust_function_name(func)); 2650 self.push_str(&if let CallStyle::Concurrent = &style { 2651 format!("<T: 'static>(accessor: &{wt}::component::Accessor<T, Self>, ") 2652 } else { 2653 "(&mut self, ".to_string() 2654 }); 2655 self.generate_function_params(func); 2656 self.push_str(")"); 2657 self.push_str(" -> "); 2658 2659 if let (CallStyle::Concurrent, false) = (&style, async_sugar) { 2660 uwrite!(self.src, "impl ::core::future::Future<Output = "); 2661 } 2662 2663 self.generate_function_result(func); 2664 2665 if let CallStyle::Concurrent = style { 2666 if !async_sugar { 2667 self.push_str("> + Send where Self: Sized,"); 2668 } 2669 } 2670 } 2671 2672 fn generate_function_params(&mut self, func: &Function) { 2673 for (name, param) in func.params.iter() { 2674 let name = to_rust_ident(name); 2675 self.push_str(&name); 2676 self.push_str(": "); 2677 self.print_ty(param, TypeMode::Owned); 2678 self.push_str(","); 2679 } 2680 } 2681 2682 fn generate_function_result(&mut self, func: &Function) { 2683 if !self.generator.opts.trappable_imports.can_trap(func) { 2684 self.print_result_ty(func.result, TypeMode::Owned); 2685 } else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) { 2686 // Functions which have a single result `result<ok,err>` get special 2687 // cased to use the host_wasmtime_rust::Error<err>, making it possible 2688 // for them to trap or use `?` to propagate their errors 2689 self.push_str("Result<"); 2690 if let Some(ok) = r.ok { 2691 self.print_ty(&ok, TypeMode::Owned); 2692 } else { 2693 self.push_str("()"); 2694 } 2695 self.push_str(","); 2696 self.push_str(&error_typename); 2697 self.push_str(">"); 2698 } else { 2699 // All other functions get their return values wrapped in an wasmtime::Result. 2700 // Returning the anyhow::Error case can be used to trap. 2701 let wt = self.generator.wasmtime_path(); 2702 uwrite!(self.src, "{wt}::Result<"); 2703 self.print_result_ty(func.result, TypeMode::Owned); 2704 self.push_str(">"); 2705 } 2706 } 2707 2708 fn extract_typed_function(&mut self, func: &Function) -> (String, String) { 2709 let snake = func_field_name(self.resolve, func); 2710 let sig = self.typedfunc_sig(func, TypeMode::AllBorrowed("'_")); 2711 let extract = 2712 format!("*_instance.get_typed_func::<{sig}>(&mut store, &self.{snake})?.func()"); 2713 (snake, extract) 2714 } 2715 2716 fn define_rust_guest_export( 2717 &mut self, 2718 resolve: &Resolve, 2719 ns: Option<&WorldKey>, 2720 func: &Function, 2721 ) { 2722 // Exports must be async if anything could be async, it's just imports 2723 // that get to be optionally async/sync. 2724 let style = self.generator.opts.call_style(); 2725 let (async_, async__, await_, concurrent) = match &style { 2726 CallStyle::Async | CallStyle::Concurrent => ( 2727 "async", 2728 "_async", 2729 ".await", 2730 self.generator.opts.concurrent_exports, 2731 ), 2732 CallStyle::Sync => ("", "", "", false), 2733 }; 2734 2735 self.rustdoc(&func.docs); 2736 let wt = self.generator.wasmtime_path(); 2737 2738 uwrite!( 2739 self.src, 2740 "pub {async_} fn call_{}", 2741 func.item_name().to_snake_case(), 2742 ); 2743 if concurrent { 2744 uwrite!( 2745 self.src, 2746 "<_T, _D>(&self, accessor: &{wt}::component::Accessor<_T, _D>, ", 2747 ); 2748 } else { 2749 uwrite!(self.src, "<S: {wt}::AsContextMut>(&self, mut store: S, ",); 2750 } 2751 2752 let param_mode = if let CallStyle::Concurrent = &style { 2753 TypeMode::Owned 2754 } else { 2755 TypeMode::AllBorrowed("'_") 2756 }; 2757 2758 for (i, param) in func.params.iter().enumerate() { 2759 uwrite!(self.src, "arg{}: ", i); 2760 self.print_ty(¶m.1, param_mode); 2761 self.push_str(","); 2762 } 2763 2764 uwrite!(self.src, ") -> {wt}::Result<"); 2765 self.print_result_ty(func.result, TypeMode::Owned); 2766 uwrite!(self.src, ">"); 2767 2768 if concurrent { 2769 uwrite!(self.src, " where _T: Send, _D: {wt}::component::HasData"); 2770 } else { 2771 match style { 2772 CallStyle::Concurrent | CallStyle::Async => { 2773 uwrite!(self.src, " where <S as {wt}::AsContext>::Data: Send"); 2774 } 2775 CallStyle::Sync => {} 2776 } 2777 } 2778 uwrite!(self.src, "{{\n"); 2779 2780 if self.generator.opts.tracing { 2781 if let CallStyle::Async | CallStyle::Concurrent = &style { 2782 self.src.push_str("use tracing::Instrument;\n"); 2783 } 2784 2785 let ns = match ns { 2786 Some(key) => resolve.name_world_key(key), 2787 None => "default".to_string(), 2788 }; 2789 self.src.push_str(&format!( 2790 " 2791 let span = tracing::span!( 2792 tracing::Level::TRACE, 2793 \"wit-bindgen export\", 2794 module = \"{ns}\", 2795 function = \"{}\", 2796 ); 2797 ", 2798 func.name, 2799 )); 2800 2801 if !matches!(&style, CallStyle::Async | CallStyle::Concurrent) { 2802 self.src.push_str( 2803 " 2804 let _enter = span.enter(); 2805 ", 2806 ); 2807 } 2808 } 2809 2810 self.src.push_str("let callee = unsafe {\n"); 2811 uwrite!( 2812 self.src, 2813 "{wt}::component::TypedFunc::<{}>", 2814 self.typedfunc_sig(func, param_mode) 2815 ); 2816 let projection_to_func = if func.kind.resource().is_some() { 2817 ".funcs" 2818 } else { 2819 "" 2820 }; 2821 uwriteln!( 2822 self.src, 2823 "::new_unchecked(self{projection_to_func}.{})", 2824 func_field_name(self.resolve, func), 2825 ); 2826 self.src.push_str("};\n"); 2827 2828 self.src.push_str("let ("); 2829 if func.result.is_some() { 2830 uwrite!(self.src, "ret0,"); 2831 } 2832 if concurrent { 2833 uwrite!(self.src, ") = callee.call_concurrent(accessor, ("); 2834 } else { 2835 uwrite!( 2836 self.src, 2837 ") = callee.call{async__}(store.as_context_mut(), (" 2838 ); 2839 } 2840 for (i, _) in func.params.iter().enumerate() { 2841 uwrite!(self.src, "arg{}, ", i); 2842 } 2843 2844 let instrument = if matches!(&style, CallStyle::Async | CallStyle::Concurrent) 2845 && self.generator.opts.tracing 2846 { 2847 ".instrument(span.clone())" 2848 } else { 2849 "" 2850 }; 2851 uwriteln!(self.src, ")){instrument}{await_}?;"); 2852 2853 let instrument = if matches!(&style, CallStyle::Async | CallStyle::Concurrent) 2854 && self.generator.opts.tracing 2855 { 2856 ".instrument(span)" 2857 } else { 2858 "" 2859 }; 2860 2861 if !concurrent { 2862 uwriteln!( 2863 self.src, 2864 "callee.post_return{async__}(store.as_context_mut()){instrument}{await_}?;" 2865 ); 2866 } 2867 2868 self.src.push_str("Ok("); 2869 if func.result.is_some() { 2870 self.src.push_str("ret0"); 2871 } else { 2872 self.src.push_str("()"); 2873 } 2874 self.src.push_str(")\n"); 2875 2876 // End function body 2877 self.src.push_str("}\n"); 2878 } 2879 2880 fn rustdoc(&mut self, docs: &Docs) { 2881 let docs = match &docs.contents { 2882 Some(docs) => docs, 2883 None => return, 2884 }; 2885 for line in docs.trim().lines() { 2886 self.push_str("/// "); 2887 self.push_str(line); 2888 self.push_str("\n"); 2889 } 2890 } 2891 2892 fn path_to_root(&self) -> String { 2893 let mut path_to_root = String::new(); 2894 if let Some((_, key, is_export)) = self.current_interface { 2895 match key { 2896 WorldKey::Name(_) => { 2897 path_to_root.push_str("super::"); 2898 } 2899 WorldKey::Interface(_) => { 2900 path_to_root.push_str("super::super::super::"); 2901 } 2902 } 2903 if is_export { 2904 path_to_root.push_str("super::"); 2905 } 2906 } 2907 path_to_root 2908 } 2909 2910 fn import_call_style(&self, func: &Function) -> CallStyle { 2911 self.generator 2912 .opts 2913 .import_call_style(self.qualifier().as_deref(), &func.name) 2914 } 2915 2916 fn partition_concurrent_funcs<'b>( 2917 &self, 2918 funcs: impl IntoIterator<Item = &'b Function>, 2919 ) -> FunctionPartitioning<'b> { 2920 let (concurrent, sync) = 2921 funcs 2922 .into_iter() 2923 .partition(|func| match self.import_call_style(func) { 2924 CallStyle::Concurrent => true, 2925 CallStyle::Async | CallStyle::Sync => false, 2926 }); 2927 FunctionPartitioning { concurrent, sync } 2928 } 2929 2930 fn generate_trait( 2931 &mut self, 2932 trait_name: &str, 2933 functions: &[&Function], 2934 extra_functions: &[ExtraTraitMethod<'_>], 2935 resources: &[(TypeId, &str)], 2936 ) -> GeneratedTrait { 2937 let mut ret = GeneratedTrait::default(); 2938 let wt = self.generator.wasmtime_path(); 2939 let is_maybe_async = matches!( 2940 self.generator.opts.call_style(), 2941 CallStyle::Async | CallStyle::Concurrent 2942 ); 2943 let partition = self.partition_concurrent_funcs(functions.iter().copied()); 2944 ret.any_concurrent = !partition.concurrent.is_empty(); 2945 2946 let mut concurrent_supertraits = vec![format!("{wt}::component::HasData")]; 2947 let mut sync_supertraits = vec![]; 2948 if is_maybe_async { 2949 concurrent_supertraits.push("Send".to_string()); 2950 sync_supertraits.push("Send".to_string()); 2951 } 2952 for (id, name) in resources { 2953 let camel = name.to_upper_camel_case(); 2954 sync_supertraits.push(format!("Host{camel}")); 2955 let funcs = self.partition_concurrent_funcs(get_resource_functions(self.resolve, *id)); 2956 if !funcs.concurrent.is_empty() { 2957 ret.any_concurrent = true; 2958 concurrent_supertraits.push(format!("Host{camel}Concurrent")); 2959 } 2960 } 2961 2962 if ret.any_concurrent { 2963 uwriteln!( 2964 self.src, 2965 "#[{wt}::component::__internal::trait_variant_make(::core::marker::Send)]", 2966 ); 2967 uwriteln!( 2968 self.src, 2969 "pub trait {trait_name}Concurrent: {} {{", 2970 concurrent_supertraits.join(" + "), 2971 ); 2972 ret.concurrent_name = Some(format!("{trait_name}Concurrent")); 2973 for func in partition.concurrent.iter() { 2974 self.generate_function_trait_sig(func, false); 2975 self.push_str(";\n"); 2976 } 2977 uwriteln!(self.src, "}}"); 2978 } 2979 2980 if is_maybe_async { 2981 uwriteln!( 2982 self.src, 2983 "#[{wt}::component::__internal::trait_variant_make(::core::marker::Send)]", 2984 ); 2985 } 2986 uwriteln!( 2987 self.src, 2988 "pub trait {trait_name}: {} {{", 2989 sync_supertraits.join(" + ") 2990 ); 2991 ret.name = trait_name.to_string(); 2992 for func in partition.sync.iter() { 2993 self.generate_function_trait_sig(func, false); 2994 self.push_str(";\n"); 2995 } 2996 2997 for extra in extra_functions { 2998 match extra { 2999 ExtraTraitMethod::ResourceDrop { name } => { 3000 let camel = name.to_upper_camel_case(); 3001 if let CallStyle::Async | CallStyle::Concurrent = self 3002 .generator 3003 .opts 3004 .drop_call_style(self.qualifier().as_deref(), name) 3005 { 3006 uwrite!(self.src, "async "); 3007 } 3008 uwrite!( 3009 self.src, 3010 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()>;" 3011 ); 3012 } 3013 ExtraTraitMethod::ErrorConvert { name, id } => { 3014 let root = self.path_to_root(); 3015 let custom_name = &self.generator.trappable_errors[id]; 3016 let snake = name.to_snake_case(); 3017 let camel = name.to_upper_camel_case(); 3018 uwriteln!( 3019 self.src, 3020 " 3021 fn convert_{snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{camel}>; 3022 " 3023 ); 3024 } 3025 } 3026 } 3027 3028 uwriteln!(self.src, "}}"); 3029 3030 if self.generator.opts.skip_mut_forwarding_impls { 3031 return ret; 3032 } 3033 3034 // Generate impl HostResource for &mut HostResource 3035 let maybe_send = if is_maybe_async { "+ Send" } else { "" }; 3036 uwriteln!( 3037 self.src, 3038 "impl <_T: {trait_name} + ?Sized {maybe_send}> {trait_name} for &mut _T {{" 3039 ); 3040 for func in partition.sync.iter() { 3041 let call_style = self.import_call_style(func); 3042 self.generate_function_trait_sig(func, true); 3043 uwrite!( 3044 self.src, 3045 "{{ {trait_name}::{}(*self,", 3046 rust_function_name(func) 3047 ); 3048 for (name, _) in func.params.iter() { 3049 uwrite!(self.src, "{},", to_rust_ident(name)); 3050 } 3051 uwrite!(self.src, ")"); 3052 if let CallStyle::Async = &call_style { 3053 uwrite!(self.src, ".await"); 3054 } 3055 uwriteln!(self.src, "}}"); 3056 } 3057 for extra in extra_functions { 3058 match extra { 3059 ExtraTraitMethod::ResourceDrop { name } => { 3060 let camel = name.to_upper_camel_case(); 3061 let mut await_ = ""; 3062 if let CallStyle::Async | CallStyle::Concurrent = self 3063 .generator 3064 .opts 3065 .drop_call_style(self.qualifier().as_deref(), name) 3066 { 3067 self.src.push_str("async "); 3068 await_ = ".await"; 3069 } 3070 uwriteln!( 3071 self.src, 3072 " 3073 fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{ 3074 {trait_name}::drop(*self, rep){await_} 3075 }} 3076 ", 3077 ); 3078 } 3079 ExtraTraitMethod::ErrorConvert { name, id } => { 3080 let root = self.path_to_root(); 3081 let custom_name = &self.generator.trappable_errors[id]; 3082 let snake = name.to_snake_case(); 3083 let camel = name.to_upper_camel_case(); 3084 uwriteln!( 3085 self.src, 3086 " 3087 fn convert_{snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{camel}> {{ 3088 {trait_name}::convert_{snake}(*self, err) 3089 }} 3090 ", 3091 ); 3092 } 3093 } 3094 } 3095 uwriteln!(self.src, "}}"); 3096 3097 ret 3098 } 3099 } 3100 3101 enum ExtraTraitMethod<'a> { 3102 ResourceDrop { name: &'a str }, 3103 ErrorConvert { name: &'a str, id: TypeId }, 3104 } 3105 3106 struct FunctionPartitioning<'a> { 3107 sync: Vec<&'a Function>, 3108 concurrent: Vec<&'a Function>, 3109 } 3110 3111 #[derive(Default)] 3112 struct GeneratedTrait { 3113 name: String, 3114 concurrent_name: Option<String>, 3115 any_concurrent: bool, 3116 } 3117 3118 impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> { 3119 fn resolve(&self) -> &'a Resolve { 3120 self.resolve 3121 } 3122 3123 fn ownership(&self) -> Ownership { 3124 self.generator.opts.ownership 3125 } 3126 3127 fn path_to_interface(&self, interface: InterfaceId) -> Option<String> { 3128 if let Some((cur, _, _)) = self.current_interface { 3129 if cur == interface { 3130 return None; 3131 } 3132 } 3133 let mut path_to_root = self.path_to_root(); 3134 match &self.generator.interface_names[&interface] { 3135 InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root), 3136 InterfaceName::Path(path) => { 3137 for (i, name) in path.iter().enumerate() { 3138 if i > 0 { 3139 path_to_root.push_str("::"); 3140 } 3141 path_to_root.push_str(name); 3142 } 3143 } 3144 } 3145 Some(path_to_root) 3146 } 3147 3148 fn push_str(&mut self, s: &str) { 3149 self.src.push_str(s); 3150 } 3151 3152 fn info(&self, ty: TypeId) -> TypeInfo { 3153 self.generator.types.get(ty) 3154 } 3155 3156 fn is_imported_interface(&self, interface: InterfaceId) -> bool { 3157 self.generator.interface_last_seen_as_import[&interface] 3158 } 3159 3160 fn wasmtime_path(&self) -> String { 3161 self.generator.wasmtime_path() 3162 } 3163 } 3164 3165 #[derive(Default)] 3166 struct LinkOptionsBuilder { 3167 unstable_features: BTreeSet<String>, 3168 } 3169 impl LinkOptionsBuilder { 3170 fn has_any(&self) -> bool { 3171 !self.unstable_features.is_empty() 3172 } 3173 fn add_world(&mut self, resolve: &Resolve, id: &WorldId) { 3174 let world = &resolve.worlds[*id]; 3175 3176 self.add_stability(&world.stability); 3177 3178 for (_, import) in world.imports.iter() { 3179 match import { 3180 WorldItem::Interface { id, stability } => { 3181 self.add_stability(stability); 3182 self.add_interface(resolve, id); 3183 } 3184 WorldItem::Function(f) => { 3185 self.add_stability(&f.stability); 3186 } 3187 WorldItem::Type(t) => { 3188 self.add_type(resolve, t); 3189 } 3190 } 3191 } 3192 } 3193 fn add_interface(&mut self, resolve: &Resolve, id: &InterfaceId) { 3194 let interface = &resolve.interfaces[*id]; 3195 3196 self.add_stability(&interface.stability); 3197 3198 for (_, t) in interface.types.iter() { 3199 self.add_type(resolve, t); 3200 } 3201 for (_, f) in interface.functions.iter() { 3202 self.add_stability(&f.stability); 3203 } 3204 } 3205 fn add_type(&mut self, resolve: &Resolve, id: &TypeId) { 3206 let t = &resolve.types[*id]; 3207 self.add_stability(&t.stability); 3208 } 3209 fn add_stability(&mut self, stability: &Stability) { 3210 match stability { 3211 Stability::Unstable { feature, .. } => { 3212 self.unstable_features.insert(feature.clone()); 3213 } 3214 Stability::Stable { .. } | Stability::Unknown => {} 3215 } 3216 } 3217 fn write_struct(&self, src: &mut Source) { 3218 if !self.has_any() { 3219 return; 3220 } 3221 3222 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>(); 3223 unstable_features.sort(); 3224 3225 uwriteln!( 3226 src, 3227 " 3228 /// Link-time configurations. 3229 #[derive(Clone, Debug, Default)] 3230 pub struct LinkOptions {{ 3231 " 3232 ); 3233 3234 for feature in unstable_features.iter() { 3235 let feature_rust_name = feature.to_snake_case(); 3236 uwriteln!(src, "{feature_rust_name}: bool,"); 3237 } 3238 3239 uwriteln!(src, "}}"); 3240 uwriteln!(src, "impl LinkOptions {{"); 3241 3242 for feature in unstable_features.iter() { 3243 let feature_rust_name = feature.to_snake_case(); 3244 uwriteln!( 3245 src, 3246 " 3247 /// Enable members marked as `@unstable(feature = {feature})` 3248 pub fn {feature_rust_name}(&mut self, enabled: bool) -> &mut Self {{ 3249 self.{feature_rust_name} = enabled; 3250 self 3251 }} 3252 " 3253 ); 3254 } 3255 3256 uwriteln!(src, "}}"); 3257 } 3258 fn write_impl_from_world(&self, src: &mut Source, path: &str) { 3259 if !self.has_any() { 3260 return; 3261 } 3262 3263 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>(); 3264 unstable_features.sort(); 3265 3266 uwriteln!( 3267 src, 3268 " 3269 impl core::convert::From<LinkOptions> for {path}::LinkOptions {{ 3270 fn from(src: LinkOptions) -> Self {{ 3271 (&src).into() 3272 }} 3273 }} 3274 3275 impl core::convert::From<&LinkOptions> for {path}::LinkOptions {{ 3276 fn from(src: &LinkOptions) -> Self {{ 3277 let mut dest = Self::default(); 3278 " 3279 ); 3280 3281 for feature in unstable_features.iter() { 3282 let feature_rust_name = feature.to_snake_case(); 3283 uwriteln!(src, "dest.{feature_rust_name}(src.{feature_rust_name});"); 3284 } 3285 3286 uwriteln!( 3287 src, 3288 " 3289 dest 3290 }} 3291 }} 3292 " 3293 ); 3294 } 3295 } 3296 3297 struct FeatureGate { 3298 close: bool, 3299 } 3300 impl FeatureGate { 3301 fn open(src: &mut Source, stability: &Stability) -> FeatureGate { 3302 let close = if let Stability::Unstable { feature, .. } = stability { 3303 let feature_rust_name = feature.to_snake_case(); 3304 uwrite!(src, "if options.{feature_rust_name} {{"); 3305 true 3306 } else { 3307 false 3308 }; 3309 Self { close } 3310 } 3311 3312 fn close(self, src: &mut Source) { 3313 if self.close { 3314 uwriteln!(src, "}}"); 3315 } 3316 } 3317 } 3318 3319 /// Produce a string for tracing a function argument. 3320 fn formatting_for_arg( 3321 name: &str, 3322 index: usize, 3323 ty: Type, 3324 opts: &Opts, 3325 resolve: &Resolve, 3326 ) -> String { 3327 if !opts.verbose_tracing && type_contains_lists(ty, resolve) { 3328 return format!("{name} = tracing::field::debug(\"...\")"); 3329 } 3330 3331 // Normal tracing. 3332 format!("{name} = tracing::field::debug(&arg{index})") 3333 } 3334 3335 /// Produce a string for tracing function results. 3336 fn formatting_for_results(result: Option<Type>, opts: &Opts, resolve: &Resolve) -> String { 3337 let contains_lists = match result { 3338 Some(ty) => type_contains_lists(ty, resolve), 3339 None => false, 3340 }; 3341 3342 if !opts.verbose_tracing && contains_lists { 3343 return format!("result = tracing::field::debug(\"...\")"); 3344 } 3345 3346 // Normal tracing. 3347 format!("result = tracing::field::debug(&r)") 3348 } 3349 3350 /// Test whether the given type contains lists. 3351 /// 3352 /// Here, a `string` is not considered a list. 3353 fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool { 3354 match ty { 3355 Type::Id(id) => match &resolve.types[id].kind { 3356 TypeDefKind::Resource 3357 | TypeDefKind::Unknown 3358 | TypeDefKind::Flags(_) 3359 | TypeDefKind::Handle(_) 3360 | TypeDefKind::Enum(_) 3361 | TypeDefKind::Stream(_) 3362 | TypeDefKind::Future(_) => false, 3363 TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve), 3364 TypeDefKind::Result(Result_ { ok, err }) => { 3365 option_type_contains_lists(*ok, resolve) 3366 || option_type_contains_lists(*err, resolve) 3367 } 3368 TypeDefKind::Record(record) => record 3369 .fields 3370 .iter() 3371 .any(|field| type_contains_lists(field.ty, resolve)), 3372 TypeDefKind::Tuple(tuple) => tuple 3373 .types 3374 .iter() 3375 .any(|ty| type_contains_lists(*ty, resolve)), 3376 TypeDefKind::Variant(variant) => variant 3377 .cases 3378 .iter() 3379 .any(|case| option_type_contains_lists(case.ty, resolve)), 3380 TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve), 3381 TypeDefKind::List(_) => true, 3382 TypeDefKind::FixedSizeList(..) => todo!(), 3383 }, 3384 3385 // Technically strings are lists too, but we ignore that here because 3386 // they're usually short. 3387 _ => false, 3388 } 3389 } 3390 3391 fn option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool { 3392 match ty { 3393 Some(ty) => type_contains_lists(ty, resolve), 3394 None => false, 3395 } 3396 } 3397 3398 /// When an interface `use`s a type from another interface, it creates a new TypeId 3399 /// referring to the definition TypeId. Chase this chain of references down to 3400 /// a TypeId for type's definition. 3401 fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId { 3402 loop { 3403 match resolve.types[id].kind { 3404 TypeDefKind::Type(Type::Id(def_id)) => id = def_id, 3405 _ => return id, 3406 } 3407 } 3408 } 3409 3410 fn rust_function_name(func: &Function) -> String { 3411 match func.kind { 3412 FunctionKind::Constructor(_) => "new".to_string(), 3413 FunctionKind::Method(_) 3414 | FunctionKind::Static(_) 3415 | FunctionKind::AsyncMethod(_) 3416 | FunctionKind::AsyncStatic(_) 3417 | FunctionKind::Freestanding 3418 | FunctionKind::AsyncFreestanding => to_rust_ident(func.item_name()), 3419 } 3420 } 3421 3422 fn func_field_name(resolve: &Resolve, func: &Function) -> String { 3423 let mut name = String::new(); 3424 match func.kind { 3425 FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => { 3426 name.push_str("method-"); 3427 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3428 name.push_str("-"); 3429 } 3430 FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => { 3431 name.push_str("static-"); 3432 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3433 name.push_str("-"); 3434 } 3435 FunctionKind::Constructor(id) => { 3436 name.push_str("constructor-"); 3437 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3438 name.push_str("-"); 3439 } 3440 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {} 3441 } 3442 name.push_str(func.item_name()); 3443 name.to_snake_case() 3444 } 3445 3446 fn get_resources<'a>( 3447 resolve: &'a Resolve, 3448 id: InterfaceId, 3449 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a { 3450 resolve.interfaces[id] 3451 .types 3452 .iter() 3453 .filter_map(move |(name, ty)| match &resolve.types[*ty].kind { 3454 TypeDefKind::Resource => Some((*ty, name.as_str())), 3455 _ => None, 3456 }) 3457 } 3458 3459 fn get_resource_functions<'a>(resolve: &'a Resolve, resource_id: TypeId) -> Vec<&'a Function> { 3460 let resource = &resolve.types[resource_id]; 3461 match resource.owner { 3462 TypeOwner::World(id) => resolve.worlds[id] 3463 .imports 3464 .values() 3465 .filter_map(|item| match item { 3466 WorldItem::Function(f) => Some(f), 3467 _ => None, 3468 }) 3469 .filter(|f| f.kind.resource() == Some(resource_id)) 3470 .collect(), 3471 TypeOwner::Interface(id) => resolve.interfaces[id] 3472 .functions 3473 .values() 3474 .filter(|f| f.kind.resource() == Some(resource_id)) 3475 .collect::<Vec<_>>(), 3476 TypeOwner::None => { 3477 panic!("A resource must be owned by a world or interface"); 3478 } 3479 } 3480 } 3481 3482 fn get_world_resources<'a>( 3483 resolve: &'a Resolve, 3484 id: WorldId, 3485 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a { 3486 resolve.worlds[id] 3487 .imports 3488 .iter() 3489 .filter_map(move |(name, item)| match item { 3490 WorldItem::Type(id) => match resolve.types[*id].kind { 3491 TypeDefKind::Resource => Some(match name { 3492 WorldKey::Name(s) => (*id, s.as_str()), 3493 WorldKey::Interface(_) => unreachable!(), 3494 }), 3495 _ => None, 3496 }, 3497 _ => None, 3498 }) 3499 } 3500