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