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