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