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 Host{camel}WithStore::drop(accessor, {wt}::component::Resource::new_own(rep)).await 1538 }}) 1539 }}, 1540 )?;" 1541 ) 1542 } else { 1543 uwriteln!( 1544 src, 1545 "{inst}.resource_async( 1546 \"{name}\", 1547 {wt}::component::ResourceType::host::<{camel}>(), 1548 move |mut store, rep| {{ 1549 {wt}::component::__internal::Box::new(async move {{ 1550 Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)).await 1551 }}) 1552 }}, 1553 )?;" 1554 ) 1555 } 1556 } else { 1557 let (first_arg, trait_suffix) = if flags.contains(FunctionFlags::STORE) { 1558 ( 1559 format!("{wt}::component::Access::new(store, host_getter)"), 1560 "WithStore", 1561 ) 1562 } else { 1563 ("&mut host_getter(store.data_mut())".to_string(), "") 1564 }; 1565 uwriteln!( 1566 src, 1567 "{inst}.resource( 1568 \"{name}\", 1569 {wt}::component::ResourceType::host::<{camel}>(), 1570 move |mut store, rep| -> {wt}::Result<()> {{ 1571 1572 let resource = {wt}::component::Resource::new_own(rep); 1573 Host{camel}{trait_suffix}::drop({first_arg}, resource) 1574 }}, 1575 )?;", 1576 ) 1577 } 1578 gate.close(src); 1579 } 1580 } 1581 1582 struct InterfaceGenerator<'a> { 1583 src: Source, 1584 generator: &'a mut Wasmtime, 1585 resolve: &'a Resolve, 1586 current_interface: Option<(InterfaceId, &'a WorldKey, bool)>, 1587 all_func_flags: FunctionFlags, 1588 } 1589 1590 impl<'a> InterfaceGenerator<'a> { 1591 fn new(generator: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> { 1592 InterfaceGenerator { 1593 src: Source::default(), 1594 generator, 1595 resolve, 1596 current_interface: None, 1597 all_func_flags: FunctionFlags::empty(), 1598 } 1599 } 1600 1601 fn types_imported(&self) -> bool { 1602 match self.current_interface { 1603 Some((_, _, is_export)) => !is_export, 1604 None => true, 1605 } 1606 } 1607 1608 fn types(&mut self, id: InterfaceId) { 1609 for (name, id) in self.resolve.interfaces[id].types.iter() { 1610 self.define_type(name, *id); 1611 } 1612 } 1613 1614 fn define_type(&mut self, name: &str, id: TypeId) { 1615 let ty = &self.resolve.types[id]; 1616 match &ty.kind { 1617 TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs), 1618 TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs), 1619 TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs), 1620 TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs), 1621 TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs), 1622 TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs), 1623 TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs), 1624 TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs), 1625 TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs), 1626 TypeDefKind::Future(t) => self.type_future(id, name, t.as_ref(), &ty.docs), 1627 TypeDefKind::Stream(t) => self.type_stream(id, name, t.as_ref(), &ty.docs), 1628 TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs), 1629 TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs), 1630 TypeDefKind::Unknown => unreachable!(), 1631 TypeDefKind::FixedLengthList(..) => todo!(), 1632 TypeDefKind::Map(..) => todo!(), 1633 } 1634 } 1635 1636 fn type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs) { 1637 self.rustdoc(docs); 1638 let name = name.to_upper_camel_case(); 1639 uwriteln!(self.src, "pub type {name} = "); 1640 self.print_handle(handle); 1641 self.push_str(";\n"); 1642 self.assert_type(id, &name); 1643 } 1644 1645 fn type_resource(&mut self, id: TypeId, name: &str, _resource: &TypeDef, docs: &Docs) { 1646 let camel = name.to_upper_camel_case(); 1647 let wt = self.generator.wasmtime_path(); 1648 1649 if self.types_imported() { 1650 self.rustdoc(docs); 1651 1652 let replacement = match self.current_interface { 1653 Some((_, key, _)) => { 1654 self.generator 1655 .lookup_replacement(self.resolve, key, Some(name)) 1656 } 1657 None => { 1658 self.generator.used_with_opts.insert(name.into()); 1659 self.generator.opts.with.get(name).cloned() 1660 } 1661 }; 1662 match replacement { 1663 Some(path) => { 1664 uwriteln!( 1665 self.src, 1666 "pub use {}{path} as {camel};", 1667 self.path_to_root() 1668 ); 1669 } 1670 None => { 1671 uwriteln!(self.src, "pub enum {camel} {{}}"); 1672 } 1673 } 1674 1675 // Generate resource trait 1676 1677 let functions = get_resource_functions(self.resolve, id); 1678 let trait_ = self.generate_trait( 1679 &format!("Host{camel}"), 1680 &functions, 1681 &[ExtraTraitMethod::ResourceDrop { name }], 1682 &[], 1683 ); 1684 self.all_func_flags |= trait_.all_func_flags; 1685 } else { 1686 self.rustdoc(docs); 1687 uwriteln!( 1688 self.src, 1689 " 1690 pub type {camel} = {wt}::component::ResourceAny; 1691 1692 pub struct Guest{camel}<'a> {{ 1693 funcs: &'a Guest, 1694 }} 1695 " 1696 ); 1697 } 1698 } 1699 1700 fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) { 1701 let info = self.info(id); 1702 let wt = self.generator.wasmtime_path(); 1703 1704 // We use a BTree set to make sure we don't have any duplicates and we have a stable order 1705 let additional_derives: BTreeSet<String> = self 1706 .generator 1707 .opts 1708 .additional_derive_attributes 1709 .iter() 1710 .cloned() 1711 .collect(); 1712 1713 for (name, mode) in self.modes_of(id) { 1714 let lt = self.lifetime_for(&info, mode); 1715 self.rustdoc(docs); 1716 1717 let mut derives = additional_derives.clone(); 1718 1719 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 1720 if lt.is_none() { 1721 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 1722 } 1723 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 1724 self.push_str("#[component(record)]\n"); 1725 if let Some(path) = &self.generator.opts.wasmtime_crate { 1726 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 1727 } 1728 1729 if info.is_copy() { 1730 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string())); 1731 } else if info.is_clone() { 1732 derives.insert("Clone".to_string()); 1733 } 1734 1735 if !derives.is_empty() { 1736 self.push_str("#[derive("); 1737 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 1738 self.push_str(")]\n") 1739 } 1740 1741 self.push_str(&format!("pub struct {name}")); 1742 self.print_generics(lt); 1743 self.push_str(" {\n"); 1744 for field in record.fields.iter() { 1745 self.rustdoc(&field.docs); 1746 self.push_str(&format!("#[component(name = \"{}\")]\n", field.name)); 1747 self.push_str("pub "); 1748 self.push_str(&to_rust_ident(&field.name)); 1749 self.push_str(": "); 1750 self.print_ty(&field.ty, mode); 1751 self.push_str(",\n"); 1752 } 1753 self.push_str("}\n"); 1754 1755 self.push_str("impl"); 1756 self.print_generics(lt); 1757 self.push_str(" core::fmt::Debug for "); 1758 self.push_str(&name); 1759 self.print_generics(lt); 1760 self.push_str(" {\n"); 1761 self.push_str( 1762 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1763 ); 1764 self.push_str(&format!("f.debug_struct(\"{name}\")")); 1765 for field in record.fields.iter() { 1766 self.push_str(&format!( 1767 ".field(\"{}\", &self.{})", 1768 field.name, 1769 to_rust_ident(&field.name) 1770 )); 1771 } 1772 self.push_str(".finish()\n"); 1773 self.push_str("}\n"); 1774 self.push_str("}\n"); 1775 1776 if info.error { 1777 self.push_str("impl"); 1778 self.print_generics(lt); 1779 self.push_str(" core::fmt::Display for "); 1780 self.push_str(&name); 1781 self.print_generics(lt); 1782 self.push_str(" {\n"); 1783 self.push_str( 1784 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1785 ); 1786 self.push_str("write!(f, \"{:?}\", self)\n"); 1787 self.push_str("}\n"); 1788 self.push_str("}\n"); 1789 1790 self.push_str("impl core::error::Error for "); 1791 self.push_str(&name); 1792 self.push_str("{}\n"); 1793 } 1794 self.assert_type(id, &name); 1795 } 1796 } 1797 1798 fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) { 1799 let info = self.info(id); 1800 for (name, mode) in self.modes_of(id) { 1801 let lt = self.lifetime_for(&info, mode); 1802 self.rustdoc(docs); 1803 self.push_str(&format!("pub type {name}")); 1804 self.print_generics(lt); 1805 self.push_str(" = ("); 1806 for ty in tuple.types.iter() { 1807 self.print_ty(ty, mode); 1808 self.push_str(","); 1809 } 1810 self.push_str(");\n"); 1811 self.assert_type(id, &name); 1812 } 1813 } 1814 1815 fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) { 1816 self.rustdoc(docs); 1817 let wt = self.generator.wasmtime_path(); 1818 let rust_name = to_rust_upper_camel_case(name); 1819 uwriteln!(self.src, "{wt}::component::flags!(\n"); 1820 self.src.push_str(&format!("{rust_name} {{\n")); 1821 for flag in flags.flags.iter() { 1822 // TODO wasmtime-component-macro doesn't support docs for flags rn 1823 uwrite!( 1824 self.src, 1825 "#[component(name=\"{}\")] const {};\n", 1826 flag.name, 1827 flag.name.to_shouty_snake_case() 1828 ); 1829 } 1830 self.src.push_str("}\n"); 1831 self.src.push_str(");\n\n"); 1832 self.assert_type(id, &rust_name); 1833 } 1834 1835 fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) { 1836 self.print_rust_enum( 1837 id, 1838 variant.cases.iter().map(|c| { 1839 ( 1840 c.name.to_upper_camel_case(), 1841 Some(c.name.clone()), 1842 &c.docs, 1843 c.ty.as_ref(), 1844 ) 1845 }), 1846 docs, 1847 "variant", 1848 ); 1849 } 1850 1851 fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) { 1852 let info = self.info(id); 1853 1854 for (name, mode) in self.modes_of(id) { 1855 self.rustdoc(docs); 1856 let lt = self.lifetime_for(&info, mode); 1857 self.push_str(&format!("pub type {name}")); 1858 self.print_generics(lt); 1859 self.push_str("= Option<"); 1860 self.print_ty(payload, mode); 1861 self.push_str(">;\n"); 1862 self.assert_type(id, &name); 1863 } 1864 } 1865 1866 // Emit a double-check that the wit-parser-understood size of a type agrees 1867 // with the Wasmtime-understood size of a type. 1868 fn assert_type(&mut self, id: TypeId, name: &str) { 1869 self.push_str("const _: () = {\n"); 1870 let wt = self.generator.wasmtime_path(); 1871 uwriteln!( 1872 self.src, 1873 "assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);", 1874 self.generator.sizes.size(&Type::Id(id)).size_wasm32(), 1875 ); 1876 uwriteln!( 1877 self.src, 1878 "assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);", 1879 self.generator.sizes.align(&Type::Id(id)).align_wasm32(), 1880 ); 1881 self.push_str("};\n"); 1882 } 1883 1884 fn print_rust_enum<'b>( 1885 &mut self, 1886 id: TypeId, 1887 cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone, 1888 docs: &Docs, 1889 derive_component: &str, 1890 ) where 1891 Self: Sized, 1892 { 1893 let info = self.info(id); 1894 let wt = self.generator.wasmtime_path(); 1895 1896 // We use a BTree set to make sure we don't have any duplicates and we have a stable order 1897 let additional_derives: BTreeSet<String> = self 1898 .generator 1899 .opts 1900 .additional_derive_attributes 1901 .iter() 1902 .cloned() 1903 .collect(); 1904 1905 for (name, mode) in self.modes_of(id) { 1906 let name = to_rust_upper_camel_case(&name); 1907 1908 let mut derives = additional_derives.clone(); 1909 1910 self.rustdoc(docs); 1911 let lt = self.lifetime_for(&info, mode); 1912 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 1913 if lt.is_none() { 1914 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 1915 } 1916 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 1917 self.push_str(&format!("#[component({derive_component})]\n")); 1918 if let Some(path) = &self.generator.opts.wasmtime_crate { 1919 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 1920 } 1921 if info.is_copy() { 1922 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string())); 1923 } else if info.is_clone() { 1924 derives.insert("Clone".to_string()); 1925 } 1926 1927 if !derives.is_empty() { 1928 self.push_str("#[derive("); 1929 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 1930 self.push_str(")]\n") 1931 } 1932 1933 self.push_str(&format!("pub enum {name}")); 1934 self.print_generics(lt); 1935 self.push_str("{\n"); 1936 for (case_name, component_name, docs, payload) in cases.clone() { 1937 self.rustdoc(docs); 1938 if let Some(n) = component_name { 1939 self.push_str(&format!("#[component(name = \"{n}\")] ")); 1940 } 1941 self.push_str(&case_name); 1942 if let Some(ty) = payload { 1943 self.push_str("("); 1944 self.print_ty(ty, mode); 1945 self.push_str(")") 1946 } 1947 self.push_str(",\n"); 1948 } 1949 self.push_str("}\n"); 1950 1951 self.print_rust_enum_debug( 1952 id, 1953 mode, 1954 &name, 1955 cases 1956 .clone() 1957 .into_iter() 1958 .map(|(name, _attr, _docs, ty)| (name, ty)), 1959 ); 1960 1961 if info.error { 1962 self.push_str("impl"); 1963 self.print_generics(lt); 1964 self.push_str(" core::fmt::Display for "); 1965 self.push_str(&name); 1966 self.print_generics(lt); 1967 self.push_str(" {\n"); 1968 self.push_str( 1969 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 1970 ); 1971 self.push_str("write!(f, \"{:?}\", self)\n"); 1972 self.push_str("}\n"); 1973 self.push_str("}\n"); 1974 1975 self.push_str("impl"); 1976 self.print_generics(lt); 1977 self.push_str(" core::error::Error for "); 1978 self.push_str(&name); 1979 self.print_generics(lt); 1980 self.push_str(" {}\n"); 1981 } 1982 1983 self.assert_type(id, &name); 1984 } 1985 } 1986 1987 fn print_rust_enum_debug<'b>( 1988 &mut self, 1989 id: TypeId, 1990 mode: TypeMode, 1991 name: &str, 1992 cases: impl IntoIterator<Item = (String, Option<&'b Type>)>, 1993 ) where 1994 Self: Sized, 1995 { 1996 let info = self.info(id); 1997 let lt = self.lifetime_for(&info, mode); 1998 self.push_str("impl"); 1999 self.print_generics(lt); 2000 self.push_str(" core::fmt::Debug for "); 2001 self.push_str(name); 2002 self.print_generics(lt); 2003 self.push_str(" {\n"); 2004 self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n"); 2005 self.push_str("match self {\n"); 2006 for (case_name, payload) in cases { 2007 self.push_str(name); 2008 self.push_str("::"); 2009 self.push_str(&case_name); 2010 if payload.is_some() { 2011 self.push_str("(e)"); 2012 } 2013 self.push_str(" => {\n"); 2014 self.push_str(&format!("f.debug_tuple(\"{name}::{case_name}\")")); 2015 if payload.is_some() { 2016 self.push_str(".field(e)"); 2017 } 2018 self.push_str(".finish()\n"); 2019 self.push_str("}\n"); 2020 } 2021 self.push_str("}\n"); 2022 self.push_str("}\n"); 2023 self.push_str("}\n"); 2024 } 2025 2026 fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) { 2027 let info = self.info(id); 2028 2029 for (name, mode) in self.modes_of(id) { 2030 self.rustdoc(docs); 2031 let lt = self.lifetime_for(&info, mode); 2032 self.push_str(&format!("pub type {name}")); 2033 self.print_generics(lt); 2034 self.push_str("= Result<"); 2035 self.print_optional_ty(result.ok.as_ref(), mode); 2036 self.push_str(","); 2037 self.print_optional_ty(result.err.as_ref(), mode); 2038 self.push_str(">;\n"); 2039 self.assert_type(id, &name); 2040 } 2041 } 2042 2043 fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) { 2044 let info = self.info(id); 2045 let wt = self.generator.wasmtime_path(); 2046 2047 // We use a BTree set to make sure we don't have any duplicates and have a stable order 2048 let mut derives: BTreeSet<String> = self 2049 .generator 2050 .opts 2051 .additional_derive_attributes 2052 .iter() 2053 .cloned() 2054 .collect(); 2055 2056 derives.extend( 2057 ["Clone", "Copy", "PartialEq", "Eq"] 2058 .into_iter() 2059 .map(|s| s.to_string()), 2060 ); 2061 2062 let name = to_rust_upper_camel_case(name); 2063 self.rustdoc(docs); 2064 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]"); 2065 uwriteln!(self.src, "#[derive({wt}::component::Lift)]"); 2066 uwriteln!(self.src, "#[derive({wt}::component::Lower)]"); 2067 self.push_str("#[component(enum)]\n"); 2068 if let Some(path) = &self.generator.opts.wasmtime_crate { 2069 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n"); 2070 } 2071 2072 self.push_str("#[derive("); 2073 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", ")); 2074 self.push_str(")]\n"); 2075 2076 let repr = match enum_.cases.len().ilog2() { 2077 0..=7 => "u8", 2078 8..=15 => "u16", 2079 _ => "u32", 2080 }; 2081 uwriteln!(self.src, "#[repr({repr})]"); 2082 2083 self.push_str(&format!("pub enum {name} {{\n")); 2084 for case in enum_.cases.iter() { 2085 self.rustdoc(&case.docs); 2086 self.push_str(&format!("#[component(name = \"{}\")]", case.name)); 2087 self.push_str(&case.name.to_upper_camel_case()); 2088 self.push_str(",\n"); 2089 } 2090 self.push_str("}\n"); 2091 2092 // Auto-synthesize an implementation of the standard `Error` trait for 2093 // error-looking types based on their name. 2094 if info.error { 2095 self.push_str("impl "); 2096 self.push_str(&name); 2097 self.push_str("{\n"); 2098 2099 self.push_str("pub fn name(&self) -> &'static str {\n"); 2100 self.push_str("match self {\n"); 2101 for case in enum_.cases.iter() { 2102 self.push_str(&name); 2103 self.push_str("::"); 2104 self.push_str(&case.name.to_upper_camel_case()); 2105 self.push_str(" => \""); 2106 self.push_str(case.name.as_str()); 2107 self.push_str("\",\n"); 2108 } 2109 self.push_str("}\n"); 2110 self.push_str("}\n"); 2111 2112 self.push_str("pub fn message(&self) -> &'static str {\n"); 2113 self.push_str("match self {\n"); 2114 for case in enum_.cases.iter() { 2115 self.push_str(&name); 2116 self.push_str("::"); 2117 self.push_str(&case.name.to_upper_camel_case()); 2118 self.push_str(" => \""); 2119 if let Some(contents) = &case.docs.contents { 2120 self.push_str(contents.trim()); 2121 } 2122 self.push_str("\",\n"); 2123 } 2124 self.push_str("}\n"); 2125 self.push_str("}\n"); 2126 2127 self.push_str("}\n"); 2128 2129 self.push_str("impl core::fmt::Debug for "); 2130 self.push_str(&name); 2131 self.push_str( 2132 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 2133 ); 2134 self.push_str("f.debug_struct(\""); 2135 self.push_str(&name); 2136 self.push_str("\")\n"); 2137 self.push_str(".field(\"code\", &(*self as i32))\n"); 2138 self.push_str(".field(\"name\", &self.name())\n"); 2139 self.push_str(".field(\"message\", &self.message())\n"); 2140 self.push_str(".finish()\n"); 2141 self.push_str("}\n"); 2142 self.push_str("}\n"); 2143 2144 self.push_str("impl core::fmt::Display for "); 2145 self.push_str(&name); 2146 self.push_str( 2147 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", 2148 ); 2149 self.push_str("write!(f, \"{} (error {})\", self.name(), *self as i32)"); 2150 self.push_str("}\n"); 2151 self.push_str("}\n"); 2152 self.push_str("\n"); 2153 self.push_str("impl core::error::Error for "); 2154 self.push_str(&name); 2155 self.push_str("{}\n"); 2156 } else { 2157 self.print_rust_enum_debug( 2158 id, 2159 TypeMode::Owned, 2160 &name, 2161 enum_ 2162 .cases 2163 .iter() 2164 .map(|c| (c.name.to_upper_camel_case(), None)), 2165 ) 2166 } 2167 self.assert_type(id, &name); 2168 } 2169 2170 fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { 2171 let info = self.info(id); 2172 for (name, mode) in self.modes_of(id) { 2173 self.rustdoc(docs); 2174 self.push_str(&format!("pub type {name}")); 2175 let lt = self.lifetime_for(&info, mode); 2176 self.print_generics(lt); 2177 self.push_str(" = "); 2178 self.print_ty(ty, mode); 2179 self.push_str(";\n"); 2180 let def_id = resolve_type_definition_id(self.resolve, id); 2181 if !matches!(self.resolve().types[def_id].kind, TypeDefKind::Resource) { 2182 self.assert_type(id, &name); 2183 } 2184 } 2185 } 2186 2187 fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { 2188 let info = self.info(id); 2189 for (name, mode) in self.modes_of(id) { 2190 let lt = self.lifetime_for(&info, mode); 2191 self.rustdoc(docs); 2192 self.push_str(&format!("pub type {name}")); 2193 self.print_generics(lt); 2194 self.push_str(" = "); 2195 self.print_list(ty, mode); 2196 self.push_str(";\n"); 2197 self.assert_type(id, &name); 2198 } 2199 } 2200 2201 fn type_stream(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) { 2202 self.rustdoc(docs); 2203 self.push_str(&format!("pub type {name}")); 2204 self.print_generics(None); 2205 self.push_str(" = "); 2206 self.print_stream(ty); 2207 self.push_str(";\n"); 2208 self.assert_type(id, &name); 2209 } 2210 2211 fn type_future(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) { 2212 self.rustdoc(docs); 2213 self.push_str(&format!("pub type {name}")); 2214 self.print_generics(None); 2215 self.push_str(" = "); 2216 self.print_future(ty); 2217 self.push_str(";\n"); 2218 self.assert_type(id, &name); 2219 } 2220 2221 fn print_result_ty(&mut self, result: Option<Type>, mode: TypeMode) { 2222 match result { 2223 Some(ty) => self.print_ty(&ty, mode), 2224 None => self.push_str("()"), 2225 } 2226 } 2227 2228 fn special_case_trappable_error( 2229 &mut self, 2230 func: &Function, 2231 ) -> Option<(&'a Result_, TypeId, String)> { 2232 let result = func.result?; 2233 2234 // We fill in a special trappable error type in the case when a function has just one 2235 // result, which is itself a `result<a, e>`, and the `e` is *not* a primitive 2236 // (i.e. defined in std) type, and matches the typename given by the user. 2237 let id = match result { 2238 Type::Id(id) => id, 2239 _ => return None, 2240 }; 2241 let result = match &self.resolve.types[id].kind { 2242 TypeDefKind::Result(r) => r, 2243 _ => return None, 2244 }; 2245 let error_typeid = match result.err? { 2246 Type::Id(id) => resolve_type_definition_id(&self.resolve, id), 2247 _ => return None, 2248 }; 2249 2250 let name = self.generator.trappable_errors.get(&error_typeid)?; 2251 2252 let mut path = self.path_to_root(); 2253 uwrite!(path, "{name}"); 2254 Some((result, error_typeid, path)) 2255 } 2256 2257 fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) { 2258 let iface = &self.resolve.interfaces[id]; 2259 let owner = TypeOwner::Interface(id); 2260 let wt = self.generator.wasmtime_path(); 2261 2262 let mut required_conversion_traits = IndexSet::new(); 2263 let extra_functions = { 2264 let mut functions = Vec::new(); 2265 let mut errors_converted = IndexMap::new(); 2266 let mut my_error_types = iface 2267 .types 2268 .iter() 2269 .filter(|(_, id)| self.generator.trappable_errors.contains_key(*id)) 2270 .map(|(_, id)| *id) 2271 .collect::<Vec<_>>(); 2272 my_error_types.extend( 2273 iface 2274 .functions 2275 .iter() 2276 .filter_map(|(_, func)| self.special_case_trappable_error(func)) 2277 .map(|(_, id, _)| id), 2278 ); 2279 for err_id in my_error_types { 2280 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err_id)]; 2281 let err_name = err.name.as_ref().unwrap(); 2282 let owner = match err.owner { 2283 TypeOwner::Interface(i) => i, 2284 _ => unimplemented!(), 2285 }; 2286 match self.path_to_interface(owner) { 2287 Some(path) => { 2288 required_conversion_traits.insert(format!("{path}::Host")); 2289 } 2290 None => { 2291 if errors_converted.insert(err_name, err_id).is_none() { 2292 functions.push(ExtraTraitMethod::ErrorConvert { 2293 name: err_name, 2294 id: err_id, 2295 }) 2296 } 2297 } 2298 } 2299 } 2300 functions 2301 }; 2302 2303 // Generate the `pub trait` which represents the host functionality for 2304 // this import which additionally inherits from all resource traits 2305 // for this interface defined by `type_resource`. 2306 let generated_trait = self.generate_trait( 2307 "Host", 2308 &iface 2309 .functions 2310 .iter() 2311 .filter_map(|(_, f)| { 2312 if f.kind.resource().is_none() { 2313 Some(f) 2314 } else { 2315 None 2316 } 2317 }) 2318 .collect::<Vec<_>>(), 2319 &extra_functions, 2320 &get_resources(self.resolve, id).collect::<Vec<_>>(), 2321 ); 2322 2323 let opt_t_send_bound = if generated_trait 2324 .all_func_flags 2325 .contains(FunctionFlags::ASYNC) 2326 { 2327 "+ Send" 2328 } else { 2329 "" 2330 }; 2331 2332 let mut sync_bounds = "Host".to_string(); 2333 2334 for ty in required_conversion_traits { 2335 uwrite!(sync_bounds, " + {ty}"); 2336 } 2337 2338 let options_param = if self.generator.interface_link_options[&id].has_any() { 2339 "options: &LinkOptions," 2340 } else { 2341 "" 2342 }; 2343 2344 uwriteln!( 2345 self.src, 2346 " 2347 pub fn add_to_linker<T, D>( 2348 linker: &mut {wt}::component::Linker<T>, 2349 {options_param} 2350 host_getter: fn(&mut T) -> D::Data<'_>, 2351 ) -> {wt}::Result<()> 2352 where 2353 D: HostWithStore, 2354 for<'a> D::Data<'a>: {sync_bounds}, 2355 T: 'static {opt_t_send_bound}, 2356 {{ 2357 " 2358 ); 2359 2360 let gate = FeatureGate::open(&mut self.src, &iface.stability); 2361 uwriteln!(self.src, "let mut inst = linker.instance(\"{name}\")?;"); 2362 2363 for (ty, _name) in get_resources(self.resolve, id) { 2364 self.generator.generate_add_resource_to_linker( 2365 self.current_interface.map(|p| p.1), 2366 Some(&mut self.src), 2367 "inst", 2368 self.resolve, 2369 ty, 2370 ); 2371 } 2372 2373 for (_, func) in iface.functions.iter() { 2374 self.generate_add_function_to_linker(owner, func, "inst"); 2375 } 2376 gate.close(&mut self.src); 2377 uwriteln!(self.src, "Ok(())"); 2378 uwriteln!(self.src, "}}"); 2379 } 2380 2381 fn import_resource_drop_flags(&mut self, name: &str) -> FunctionFlags { 2382 self.generator.opts.imports.resource_drop_flags( 2383 self.resolve, 2384 self.current_interface.map(|p| p.1), 2385 name, 2386 ) 2387 } 2388 2389 fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) { 2390 let flags = self.generator.opts.imports.flags( 2391 self.resolve, 2392 self.current_interface.map(|p| p.1), 2393 func, 2394 ); 2395 self.all_func_flags |= flags; 2396 let gate = FeatureGate::open(&mut self.src, &func.stability); 2397 uwrite!( 2398 self.src, 2399 "{linker}.{}(\"{}\", ", 2400 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) { 2401 "func_wrap_concurrent" 2402 } else if flags.contains(FunctionFlags::ASYNC) { 2403 "func_wrap_async" 2404 } else { 2405 "func_wrap" 2406 }, 2407 func.name 2408 ); 2409 self.generate_guest_import_closure(owner, func, flags); 2410 uwriteln!(self.src, ")?;"); 2411 gate.close(&mut self.src); 2412 } 2413 2414 fn generate_guest_import_closure( 2415 &mut self, 2416 owner: TypeOwner, 2417 func: &Function, 2418 flags: FunctionFlags, 2419 ) { 2420 // Generate the closure that's passed to a `Linker`, the final piece of 2421 // codegen here. 2422 2423 let wt = self.generator.wasmtime_path(); 2424 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) { 2425 uwrite!(self.src, "move |caller: &{wt}::component::Accessor::<T>, ("); 2426 } else { 2427 uwrite!( 2428 self.src, 2429 "move |mut caller: {wt}::StoreContextMut<'_, T>, (" 2430 ); 2431 } 2432 for (i, _param) in func.params.iter().enumerate() { 2433 uwrite!(self.src, "arg{},", i); 2434 } 2435 self.src.push_str(") : ("); 2436 2437 for param in func.params.iter() { 2438 // Lift is required to be implied for this type, so we can't use 2439 // a borrowed type: 2440 self.print_ty(¶m.ty, TypeMode::Owned); 2441 self.src.push_str(", "); 2442 } 2443 self.src.push_str(")| {\n"); 2444 2445 if flags.contains(FunctionFlags::TRACING) { 2446 if flags.contains(FunctionFlags::ASYNC) { 2447 self.src.push_str("use tracing::Instrument;\n"); 2448 } 2449 2450 uwrite!( 2451 self.src, 2452 " 2453 let span = tracing::span!( 2454 tracing::Level::TRACE, 2455 \"wit-bindgen import\", 2456 module = \"{}\", 2457 function = \"{}\", 2458 ); 2459 ", 2460 match owner { 2461 TypeOwner::Interface(id) => self.resolve.interfaces[id] 2462 .name 2463 .as_deref() 2464 .unwrap_or("<no module>"), 2465 TypeOwner::World(id) => &self.resolve.worlds[id].name, 2466 TypeOwner::None => "<no owner>", 2467 }, 2468 func.name, 2469 ); 2470 } 2471 2472 if flags.contains(FunctionFlags::ASYNC) { 2473 let ctor = if flags.contains(FunctionFlags::STORE) { 2474 "pin" 2475 } else { 2476 "new" 2477 }; 2478 uwriteln!( 2479 self.src, 2480 "{wt}::component::__internal::Box::{ctor}(async move {{" 2481 ); 2482 } else { 2483 // Only directly enter the span if the function is sync. Otherwise 2484 // we use tracing::Instrument to ensure that the span is not entered 2485 // across an await point. 2486 if flags.contains(FunctionFlags::TRACING) { 2487 self.push_str("let _enter = span.enter();\n"); 2488 } 2489 } 2490 2491 if flags.contains(FunctionFlags::TRACING) { 2492 let mut event_fields = func 2493 .params 2494 .iter() 2495 .enumerate() 2496 .map(|(i, param)| { 2497 let name = to_rust_ident(¶m.name); 2498 formatting_for_arg(&name, i, param.ty, &self.resolve, flags) 2499 }) 2500 .collect::<Vec<String>>(); 2501 event_fields.push(format!("\"call\"")); 2502 uwrite!( 2503 self.src, 2504 "tracing::event!(tracing::Level::TRACE, {});\n", 2505 event_fields.join(", ") 2506 ); 2507 } 2508 2509 if flags.contains(FunctionFlags::STORE) { 2510 if flags.contains(FunctionFlags::ASYNC) { 2511 uwriteln!(self.src, "let host = &caller.with_getter(host_getter);"); 2512 } else { 2513 uwriteln!( 2514 self.src, 2515 "let access_cx = {wt}::AsContextMut::as_context_mut(&mut caller);" 2516 ); 2517 uwriteln!( 2518 self.src, 2519 "let host = {wt}::component::Access::new(access_cx, host_getter);" 2520 ); 2521 } 2522 } else { 2523 self.src 2524 .push_str("let host = &mut host_getter(caller.data_mut());\n"); 2525 } 2526 let func_name = rust_function_name(func); 2527 let host_trait = match func.kind.resource() { 2528 None => match owner { 2529 TypeOwner::World(id) => format!( 2530 "{}Imports", 2531 rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name) 2532 ), 2533 _ => "Host".to_string(), 2534 }, 2535 Some(id) => { 2536 let resource = self.resolve.types[id] 2537 .name 2538 .as_ref() 2539 .unwrap() 2540 .to_upper_camel_case(); 2541 format!("Host{resource}") 2542 } 2543 }; 2544 2545 if flags.contains(FunctionFlags::STORE) { 2546 uwrite!( 2547 self.src, 2548 "let r = <D as {host_trait}WithStore>::{func_name}(host, " 2549 ); 2550 } else { 2551 uwrite!(self.src, "let r = {host_trait}::{func_name}(host, "); 2552 } 2553 2554 for (i, _) in func.params.iter().enumerate() { 2555 uwrite!(self.src, "arg{},", i); 2556 } 2557 2558 self.src.push_str(if flags.contains(FunctionFlags::ASYNC) { 2559 ").await;\n" 2560 } else { 2561 ");\n" 2562 }); 2563 2564 if flags.contains(FunctionFlags::TRACING) { 2565 uwrite!( 2566 self.src, 2567 "tracing::event!(tracing::Level::TRACE, {}, \"return\");", 2568 formatting_for_results(func.result, &self.resolve, flags) 2569 ); 2570 } 2571 2572 if !flags.contains(FunctionFlags::TRAPPABLE) { 2573 if func.result.is_some() { 2574 uwrite!(self.src, "Ok((r,))\n"); 2575 } else { 2576 uwrite!(self.src, "Ok(r)\n"); 2577 } 2578 } else if let Some((_, err, _)) = self.special_case_trappable_error(func) { 2579 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)]; 2580 let err_name = err.name.as_ref().unwrap(); 2581 let owner = match err.owner { 2582 TypeOwner::Interface(i) => i, 2583 _ => unimplemented!(), 2584 }; 2585 let convert_trait = match self.path_to_interface(owner) { 2586 Some(path) => format!("{path}::Host"), 2587 None => format!("Host"), 2588 }; 2589 let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case()); 2590 let convert = if flags.contains(FunctionFlags::STORE) { 2591 if flags.contains(FunctionFlags::ASYNC) { 2592 format!("caller.with(|mut host| {convert}(&mut host_getter(host.get()), e))?") 2593 } else { 2594 format!("{convert}(&mut host_getter(caller.data_mut()), e)?") 2595 } 2596 } else { 2597 format!("{convert}(host, e)?") 2598 }; 2599 uwrite!( 2600 self.src, 2601 "Ok((match r {{ 2602 Ok(a) => Ok(a), 2603 Err(e) => Err({convert}), 2604 }},))" 2605 ); 2606 } else if func.result.is_some() { 2607 if self.generator.opts.anyhow { 2608 uwrite!( 2609 self.src, 2610 "Ok(({wt}::ToWasmtimeResult::to_wasmtime_result(r)?,))\n" 2611 ); 2612 } else { 2613 uwrite!(self.src, "Ok((r?,))\n"); 2614 } 2615 } else { 2616 uwrite!(self.src, "r\n"); 2617 } 2618 2619 if flags.contains(FunctionFlags::ASYNC) { 2620 if flags.contains(FunctionFlags::TRACING) { 2621 self.src.push_str("}.instrument(span))\n"); 2622 } else { 2623 self.src.push_str("})\n"); 2624 } 2625 } 2626 2627 self.src.push_str("}\n"); 2628 } 2629 2630 fn generate_function_trait_sig(&mut self, func: &Function, flags: FunctionFlags) { 2631 let wt = self.generator.wasmtime_path(); 2632 self.rustdoc(&func.docs); 2633 2634 self.push_str("fn "); 2635 self.push_str(&rust_function_name(func)); 2636 if flags.contains(FunctionFlags::STORE | FunctionFlags::ASYNC) { 2637 uwrite!( 2638 self.src, 2639 "<T: Send>(accessor: &{wt}::component::Accessor<T, Self>, " 2640 ); 2641 } else if flags.contains(FunctionFlags::STORE) { 2642 uwrite!(self.src, "<T>(host: {wt}::component::Access<T, Self>, "); 2643 } else { 2644 self.push_str("(&mut self, "); 2645 } 2646 self.generate_function_params(func); 2647 self.push_str(")"); 2648 self.push_str(" -> "); 2649 2650 if flags.contains(FunctionFlags::ASYNC) { 2651 uwrite!(self.src, "impl ::core::future::Future<Output = "); 2652 } 2653 2654 self.all_func_flags |= flags; 2655 self.generate_function_result(func, flags); 2656 2657 if flags.contains(FunctionFlags::ASYNC) { 2658 self.push_str("> + Send"); 2659 } 2660 } 2661 2662 fn generate_function_params(&mut self, func: &Function) { 2663 for param in func.params.iter() { 2664 let name = to_rust_ident(¶m.name); 2665 self.push_str(&name); 2666 self.push_str(": "); 2667 self.print_ty(¶m.ty, TypeMode::Owned); 2668 self.push_str(","); 2669 } 2670 } 2671 2672 fn push_wasmtime_or_anyhow_result(&mut self) { 2673 let wt = self.generator.wasmtime_path(); 2674 uwrite!(self.src, "{wt}::"); 2675 if self.generator.opts.anyhow { 2676 self.push_str("anyhow::"); 2677 } 2678 self.push_str("Result"); 2679 } 2680 2681 fn generate_function_result(&mut self, func: &Function, flags: FunctionFlags) { 2682 if !flags.contains(FunctionFlags::TRAPPABLE) { 2683 self.print_result_ty(func.result, TypeMode::Owned); 2684 } else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) { 2685 // Functions which have a single result `result<ok,err>` get special 2686 // cased to use the host_wasmtime_rust::Error<err>, making it possible 2687 // for them to trap or use `?` to propagate their errors 2688 self.push_str("Result<"); 2689 if let Some(ok) = r.ok { 2690 self.print_ty(&ok, TypeMode::Owned); 2691 } else { 2692 self.push_str("()"); 2693 } 2694 self.push_str(","); 2695 self.push_str(&error_typename); 2696 self.push_str(">"); 2697 } else { 2698 // All other functions get their return values wrapped in an wasmtime::Result. 2699 // Returning the anyhow::Error case can be used to trap. 2700 self.push_wasmtime_or_anyhow_result(); 2701 self.push_str("<"); 2702 self.print_result_ty(func.result, TypeMode::Owned); 2703 self.push_str(">"); 2704 } 2705 } 2706 2707 fn extract_typed_function(&mut self, func: &Function) -> (String, String) { 2708 let snake = func_field_name(self.resolve, func); 2709 let sig = self.typedfunc_sig(func, TypeMode::AllBorrowed("'_")); 2710 let extract = 2711 format!("*_instance.get_typed_func::<{sig}>(&mut store, &self.{snake})?.func()"); 2712 (snake, extract) 2713 } 2714 2715 fn define_rust_guest_export( 2716 &mut self, 2717 resolve: &Resolve, 2718 ns: Option<&WorldKey>, 2719 func: &Function, 2720 ) { 2721 let flags = self.generator.opts.exports.flags(resolve, ns, func); 2722 let (async_, async__, await_) = if flags.contains(FunctionFlags::ASYNC) { 2723 ("async", "_async", ".await") 2724 } else { 2725 ("", "", "") 2726 }; 2727 2728 self.rustdoc(&func.docs); 2729 let wt = self.generator.wasmtime_path(); 2730 2731 uwrite!( 2732 self.src, 2733 "pub {async_} fn call_{}", 2734 func.item_name().to_snake_case(), 2735 ); 2736 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) { 2737 uwrite!( 2738 self.src, 2739 "<_T, _D>(&self, accessor: &{wt}::component::Accessor<_T, _D>, ", 2740 ); 2741 } else { 2742 uwrite!(self.src, "<S: {wt}::AsContextMut>(&self, mut store: S, ",); 2743 } 2744 2745 let task_exit = 2746 flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE | FunctionFlags::TASK_EXIT); 2747 2748 let param_mode = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) { 2749 TypeMode::Owned 2750 } else { 2751 TypeMode::AllBorrowed("'_") 2752 }; 2753 2754 for (i, param) in func.params.iter().enumerate() { 2755 uwrite!(self.src, "arg{}: ", i); 2756 self.print_ty(¶m.ty, param_mode); 2757 self.push_str(","); 2758 } 2759 2760 uwrite!(self.src, ") -> {wt}::Result<"); 2761 if task_exit { 2762 self.src.push_str("("); 2763 } 2764 self.print_result_ty(func.result, TypeMode::Owned); 2765 if task_exit { 2766 uwrite!(self.src, ", {wt}::component::TaskExit)"); 2767 } 2768 uwrite!(self.src, ">"); 2769 2770 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) { 2771 uwrite!(self.src, " where _T: Send, _D: {wt}::component::HasData"); 2772 } else if flags.contains(FunctionFlags::ASYNC) { 2773 uwrite!(self.src, " where <S as {wt}::AsContext>::Data: Send"); 2774 } 2775 uwrite!(self.src, "{{\n"); 2776 2777 if flags.contains(FunctionFlags::TRACING) { 2778 if flags.contains(FunctionFlags::ASYNC) { 2779 self.src.push_str("use tracing::Instrument;\n"); 2780 } 2781 2782 let ns = match ns { 2783 Some(key) => resolve.name_world_key(key), 2784 None => "default".to_string(), 2785 }; 2786 self.src.push_str(&format!( 2787 " 2788 let span = tracing::span!( 2789 tracing::Level::TRACE, 2790 \"wit-bindgen export\", 2791 module = \"{ns}\", 2792 function = \"{}\", 2793 ); 2794 ", 2795 func.name, 2796 )); 2797 2798 if !flags.contains(FunctionFlags::ASYNC) { 2799 self.src.push_str( 2800 " 2801 let _enter = span.enter(); 2802 ", 2803 ); 2804 } 2805 } 2806 2807 self.src.push_str("let callee = unsafe {\n"); 2808 uwrite!( 2809 self.src, 2810 "{wt}::component::TypedFunc::<{}>", 2811 self.typedfunc_sig(func, param_mode) 2812 ); 2813 let projection_to_func = if func.kind.resource().is_some() { 2814 ".funcs" 2815 } else { 2816 "" 2817 }; 2818 uwriteln!( 2819 self.src, 2820 "::new_unchecked(self{projection_to_func}.{})", 2821 func_field_name(self.resolve, func), 2822 ); 2823 self.src.push_str("};\n"); 2824 2825 self.src.push_str("let ("); 2826 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) { 2827 self.src.push_str("("); 2828 } 2829 if func.result.is_some() { 2830 uwrite!(self.src, "ret0,"); 2831 } 2832 2833 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) { 2834 let task_exit = if task_exit { "task_exit" } else { "_" }; 2835 uwrite!( 2836 self.src, 2837 "), {task_exit}) = callee.call_concurrent(accessor, (" 2838 ); 2839 } else { 2840 uwrite!( 2841 self.src, 2842 ") = callee.call{async__}(store.as_context_mut(), (" 2843 ); 2844 }; 2845 2846 for (i, _) in func.params.iter().enumerate() { 2847 uwrite!(self.src, "arg{}, ", i); 2848 } 2849 2850 let instrument = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::TRACING) { 2851 ".instrument(span.clone())" 2852 } else { 2853 "" 2854 }; 2855 uwriteln!(self.src, ")){instrument}{await_}?;"); 2856 2857 self.src.push_str("Ok("); 2858 if task_exit { 2859 self.src.push_str("("); 2860 } 2861 if func.result.is_some() { 2862 self.src.push_str("ret0"); 2863 } else { 2864 self.src.push_str("()"); 2865 } 2866 if task_exit { 2867 self.src.push_str(", task_exit)"); 2868 } 2869 self.src.push_str(")\n"); 2870 2871 // End function body 2872 self.src.push_str("}\n"); 2873 } 2874 2875 fn rustdoc(&mut self, docs: &Docs) { 2876 let docs = match &docs.contents { 2877 Some(docs) => docs, 2878 None => return, 2879 }; 2880 for line in docs.trim().lines() { 2881 self.push_str("/// "); 2882 self.push_str(line); 2883 self.push_str("\n"); 2884 } 2885 } 2886 2887 fn path_to_root(&self) -> String { 2888 let mut path_to_root = String::new(); 2889 if let Some((_, key, is_export)) = self.current_interface { 2890 match key { 2891 WorldKey::Name(_) => { 2892 path_to_root.push_str("super::"); 2893 } 2894 WorldKey::Interface(_) => { 2895 path_to_root.push_str("super::super::super::"); 2896 } 2897 } 2898 if is_export { 2899 path_to_root.push_str("super::"); 2900 } 2901 } 2902 path_to_root 2903 } 2904 2905 fn partition_concurrent_funcs<'b>( 2906 &mut self, 2907 funcs: impl IntoIterator<Item = &'b Function>, 2908 ) -> FunctionPartitioning<'b> { 2909 let key = self.current_interface.map(|p| p.1); 2910 let (with_store, without_store) = funcs 2911 .into_iter() 2912 .map(|func| { 2913 let flags = self.generator.opts.imports.flags(self.resolve, key, func); 2914 (func, flags) 2915 }) 2916 .partition(|(_, flags)| flags.contains(FunctionFlags::STORE)); 2917 FunctionPartitioning { 2918 with_store, 2919 without_store, 2920 } 2921 } 2922 2923 fn generate_trait( 2924 &mut self, 2925 trait_name: &str, 2926 functions: &[&Function], 2927 extra_functions: &[ExtraTraitMethod<'_>], 2928 resources: &[(TypeId, &str)], 2929 ) -> GeneratedTrait { 2930 let mut ret = GeneratedTrait::default(); 2931 let wt = self.generator.wasmtime_path(); 2932 let partition = self.partition_concurrent_funcs(functions.iter().copied()); 2933 2934 for (_, flags) in partition.with_store.iter().chain(&partition.without_store) { 2935 ret.all_func_flags |= *flags; 2936 } 2937 2938 let mut with_store_supertraits = vec![format!("{wt}::component::HasData")]; 2939 let mut without_store_supertraits = vec![]; 2940 for (id, name) in resources { 2941 let camel = name.to_upper_camel_case(); 2942 without_store_supertraits.push(format!("Host{camel}")); 2943 let funcs = self.partition_concurrent_funcs(get_resource_functions(self.resolve, *id)); 2944 for (_, flags) in funcs.with_store.iter().chain(&funcs.without_store) { 2945 ret.all_func_flags |= *flags; 2946 } 2947 ret.all_func_flags |= self.import_resource_drop_flags(name); 2948 with_store_supertraits.push(format!("Host{camel}WithStore")); 2949 } 2950 if ret.all_func_flags.contains(FunctionFlags::ASYNC) { 2951 with_store_supertraits.push("Send".to_string()); 2952 without_store_supertraits.push("Send".to_string()); 2953 } 2954 2955 uwriteln!( 2956 self.src, 2957 "pub trait {trait_name}WithStore: {} {{", 2958 with_store_supertraits.join(" + "), 2959 ); 2960 ret.with_store_name = Some(format!("{trait_name}WithStore")); 2961 2962 let mut extra_with_store_function = false; 2963 for extra in extra_functions { 2964 match extra { 2965 ExtraTraitMethod::ResourceDrop { name } => { 2966 let flags = self.import_resource_drop_flags(name); 2967 if !flags.contains(FunctionFlags::STORE) { 2968 continue; 2969 } 2970 let camel = name.to_upper_camel_case(); 2971 2972 if flags.contains(FunctionFlags::ASYNC) { 2973 uwrite!( 2974 self.src, 2975 " 2976 fn drop<T>(accessor: &{wt}::component::Accessor<T, Self>, rep: {wt}::component::Resource<{camel}>) 2977 -> impl ::core::future::Future<Output = 2978 " 2979 ); 2980 self.push_wasmtime_or_anyhow_result(); 2981 self.push_str("<()>> + Send where Self: Sized;"); 2982 } else { 2983 uwrite!( 2984 self.src, 2985 " 2986 fn drop<T>(accessor: {wt}::component::Access<T, Self>, rep: {wt}::component::Resource<{camel}>) 2987 -> 2988 " 2989 ); 2990 self.push_wasmtime_or_anyhow_result(); 2991 self.push_str("<()>;"); 2992 } 2993 2994 extra_with_store_function = true; 2995 } 2996 ExtraTraitMethod::ErrorConvert { .. } => {} 2997 } 2998 } 2999 3000 for (func, flags) in partition.with_store.iter() { 3001 self.generate_function_trait_sig(func, *flags); 3002 self.push_str(";\n"); 3003 } 3004 uwriteln!(self.src, "}}"); 3005 3006 // If `*WithStore` is empty, generate a blanket impl for the trait since 3007 // it's otherwise not necessary to implement it manually. 3008 if partition.with_store.is_empty() && !extra_with_store_function { 3009 uwriteln!(self.src, "impl<_T: ?Sized> {trait_name}WithStore for _T"); 3010 uwriteln!( 3011 self.src, 3012 " where _T: {}", 3013 with_store_supertraits.join(" + ") 3014 ); 3015 3016 uwriteln!(self.src, "{{}}"); 3017 } 3018 3019 uwriteln!( 3020 self.src, 3021 "pub trait {trait_name}: {} {{", 3022 without_store_supertraits.join(" + ") 3023 ); 3024 ret.name = trait_name.to_string(); 3025 for (func, flags) in partition.without_store.iter() { 3026 self.generate_function_trait_sig(func, *flags); 3027 self.push_str(";\n"); 3028 } 3029 3030 for extra in extra_functions { 3031 match extra { 3032 ExtraTraitMethod::ResourceDrop { name } => { 3033 let flags = self.import_resource_drop_flags(name); 3034 ret.all_func_flags |= flags; 3035 if flags.contains(FunctionFlags::STORE) { 3036 continue; 3037 } 3038 let camel = name.to_upper_camel_case(); 3039 uwrite!( 3040 self.src, 3041 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> " 3042 ); 3043 if flags.contains(FunctionFlags::ASYNC) { 3044 uwrite!(self.src, "impl ::core::future::Future<Output ="); 3045 } 3046 self.push_wasmtime_or_anyhow_result(); 3047 self.push_str("<()>"); 3048 if flags.contains(FunctionFlags::ASYNC) { 3049 uwrite!(self.src, "> + Send"); 3050 } 3051 uwrite!(self.src, ";"); 3052 } 3053 ExtraTraitMethod::ErrorConvert { name, id } => { 3054 let root = self.path_to_root(); 3055 let custom_name = &self.generator.trappable_errors[id]; 3056 let snake = name.to_snake_case(); 3057 let camel = name.to_upper_camel_case(); 3058 uwrite!( 3059 self.src, 3060 " 3061 fn convert_{snake}(&mut self, err: {root}{custom_name}) -> 3062 " 3063 ); 3064 self.push_wasmtime_or_anyhow_result(); 3065 uwrite!(self.src, "<{camel}>;"); 3066 } 3067 } 3068 } 3069 3070 uwriteln!(self.src, "}}"); 3071 3072 if self.generator.opts.skip_mut_forwarding_impls { 3073 return ret; 3074 } 3075 3076 // Generate impl HostResource for &mut HostResource 3077 let maybe_send = if ret.all_func_flags.contains(FunctionFlags::ASYNC) { 3078 "+ Send" 3079 } else { 3080 "" 3081 }; 3082 uwriteln!( 3083 self.src, 3084 "impl <_T: {trait_name} + ?Sized {maybe_send}> {trait_name} for &mut _T {{" 3085 ); 3086 for (func, flags) in partition.without_store.iter() { 3087 self.generate_function_trait_sig(func, *flags); 3088 uwriteln!(self.src, "{{"); 3089 if flags.contains(FunctionFlags::ASYNC) { 3090 uwriteln!(self.src, "async move {{"); 3091 } 3092 uwrite!( 3093 self.src, 3094 "{trait_name}::{}(*self,", 3095 rust_function_name(func) 3096 ); 3097 for param in func.params.iter() { 3098 uwrite!(self.src, "{},", to_rust_ident(¶m.name)); 3099 } 3100 uwrite!(self.src, ")"); 3101 if flags.contains(FunctionFlags::ASYNC) { 3102 uwrite!(self.src, ".await\n}}"); 3103 } 3104 uwriteln!(self.src, "}}"); 3105 } 3106 for extra in extra_functions { 3107 match extra { 3108 ExtraTraitMethod::ResourceDrop { name } => { 3109 let flags = self.import_resource_drop_flags(name); 3110 if flags.contains(FunctionFlags::STORE) { 3111 continue; 3112 } 3113 let camel = name.to_upper_camel_case(); 3114 let mut await_ = ""; 3115 if flags.contains(FunctionFlags::ASYNC) { 3116 self.src.push_str("async "); 3117 await_ = ".await"; 3118 } 3119 uwrite!( 3120 self.src, 3121 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> ", 3122 ); 3123 self.push_wasmtime_or_anyhow_result(); 3124 uwriteln!( 3125 self.src, 3126 "<()> {{ 3127 {trait_name}::drop(*self, rep){await_} 3128 }} 3129 ", 3130 ); 3131 } 3132 ExtraTraitMethod::ErrorConvert { name, id } => { 3133 let root = self.path_to_root(); 3134 let custom_name = &self.generator.trappable_errors[id]; 3135 let snake = name.to_snake_case(); 3136 let camel = name.to_upper_camel_case(); 3137 uwrite!( 3138 self.src, 3139 "fn convert_{snake}(&mut self, err: {root}{custom_name}) -> ", 3140 ); 3141 self.push_wasmtime_or_anyhow_result(); 3142 uwriteln!( 3143 self.src, 3144 "<{camel}> {{ 3145 {trait_name}::convert_{snake}(*self, err) 3146 }} 3147 ", 3148 ); 3149 } 3150 } 3151 } 3152 uwriteln!(self.src, "}}"); 3153 3154 ret 3155 } 3156 } 3157 3158 enum ExtraTraitMethod<'a> { 3159 ResourceDrop { name: &'a str }, 3160 ErrorConvert { name: &'a str, id: TypeId }, 3161 } 3162 3163 struct FunctionPartitioning<'a> { 3164 without_store: Vec<(&'a Function, FunctionFlags)>, 3165 with_store: Vec<(&'a Function, FunctionFlags)>, 3166 } 3167 3168 #[derive(Default)] 3169 struct GeneratedTrait { 3170 name: String, 3171 with_store_name: Option<String>, 3172 all_func_flags: FunctionFlags, 3173 } 3174 3175 impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> { 3176 fn resolve(&self) -> &'a Resolve { 3177 self.resolve 3178 } 3179 3180 fn ownership(&self) -> Ownership { 3181 self.generator.opts.ownership 3182 } 3183 3184 fn path_to_interface(&self, interface: InterfaceId) -> Option<String> { 3185 if let Some((cur, _, _)) = self.current_interface { 3186 if cur == interface { 3187 return None; 3188 } 3189 } 3190 let mut path_to_root = self.path_to_root(); 3191 match &self.generator.interface_names[&interface] { 3192 InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root), 3193 InterfaceName::Path(path) => { 3194 for (i, name) in path.iter().enumerate() { 3195 if i > 0 { 3196 path_to_root.push_str("::"); 3197 } 3198 path_to_root.push_str(name); 3199 } 3200 } 3201 } 3202 Some(path_to_root) 3203 } 3204 3205 fn push_str(&mut self, s: &str) { 3206 self.src.push_str(s); 3207 } 3208 3209 fn info(&self, ty: TypeId) -> TypeInfo { 3210 self.generator.types.get(ty) 3211 } 3212 3213 fn is_imported_interface(&self, interface: InterfaceId) -> bool { 3214 self.generator.interface_last_seen_as_import[&interface] 3215 } 3216 3217 fn wasmtime_path(&self) -> String { 3218 self.generator.wasmtime_path() 3219 } 3220 } 3221 3222 #[derive(Default)] 3223 struct LinkOptionsBuilder { 3224 unstable_features: BTreeSet<String>, 3225 } 3226 impl LinkOptionsBuilder { 3227 fn has_any(&self) -> bool { 3228 !self.unstable_features.is_empty() 3229 } 3230 fn add_world(&mut self, resolve: &Resolve, id: &WorldId) { 3231 let world = &resolve.worlds[*id]; 3232 3233 self.add_stability(&world.stability); 3234 3235 for (_, import) in world.imports.iter() { 3236 match import { 3237 WorldItem::Interface { id, stability, .. } => { 3238 self.add_stability(stability); 3239 self.add_interface(resolve, id); 3240 } 3241 WorldItem::Function(f) => { 3242 self.add_stability(&f.stability); 3243 } 3244 WorldItem::Type { id, .. } => { 3245 self.add_type(resolve, id); 3246 } 3247 } 3248 } 3249 } 3250 fn add_interface(&mut self, resolve: &Resolve, id: &InterfaceId) { 3251 let interface = &resolve.interfaces[*id]; 3252 3253 self.add_stability(&interface.stability); 3254 3255 for (_, t) in interface.types.iter() { 3256 self.add_type(resolve, t); 3257 } 3258 for (_, f) in interface.functions.iter() { 3259 self.add_stability(&f.stability); 3260 } 3261 } 3262 fn add_type(&mut self, resolve: &Resolve, id: &TypeId) { 3263 let t = &resolve.types[*id]; 3264 self.add_stability(&t.stability); 3265 } 3266 fn add_stability(&mut self, stability: &Stability) { 3267 match stability { 3268 Stability::Unstable { feature, .. } => { 3269 self.unstable_features.insert(feature.clone()); 3270 } 3271 Stability::Stable { .. } | Stability::Unknown => {} 3272 } 3273 } 3274 fn write_struct(&self, src: &mut Source) { 3275 if !self.has_any() { 3276 return; 3277 } 3278 3279 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>(); 3280 unstable_features.sort(); 3281 3282 uwriteln!( 3283 src, 3284 " 3285 /// Link-time configurations. 3286 #[derive(Clone, Debug, Default)] 3287 pub struct LinkOptions {{ 3288 " 3289 ); 3290 3291 for feature in unstable_features.iter() { 3292 let feature_rust_name = feature.to_snake_case(); 3293 uwriteln!(src, "{feature_rust_name}: bool,"); 3294 } 3295 3296 uwriteln!(src, "}}"); 3297 uwriteln!(src, "impl LinkOptions {{"); 3298 3299 for feature in unstable_features.iter() { 3300 let feature_rust_name = feature.to_snake_case(); 3301 uwriteln!( 3302 src, 3303 " 3304 /// Enable members marked as `@unstable(feature = {feature})` 3305 pub fn {feature_rust_name}(&mut self, enabled: bool) -> &mut Self {{ 3306 self.{feature_rust_name} = enabled; 3307 self 3308 }} 3309 " 3310 ); 3311 } 3312 3313 uwriteln!(src, "}}"); 3314 } 3315 fn write_impl_from_world(&self, src: &mut Source, path: &str) { 3316 if !self.has_any() { 3317 return; 3318 } 3319 3320 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>(); 3321 unstable_features.sort(); 3322 3323 uwriteln!( 3324 src, 3325 " 3326 impl core::convert::From<LinkOptions> for {path}::LinkOptions {{ 3327 fn from(src: LinkOptions) -> Self {{ 3328 (&src).into() 3329 }} 3330 }} 3331 3332 impl core::convert::From<&LinkOptions> for {path}::LinkOptions {{ 3333 fn from(src: &LinkOptions) -> Self {{ 3334 let mut dest = Self::default(); 3335 " 3336 ); 3337 3338 for feature in unstable_features.iter() { 3339 let feature_rust_name = feature.to_snake_case(); 3340 uwriteln!(src, "dest.{feature_rust_name}(src.{feature_rust_name});"); 3341 } 3342 3343 uwriteln!( 3344 src, 3345 " 3346 dest 3347 }} 3348 }} 3349 " 3350 ); 3351 } 3352 } 3353 3354 struct FeatureGate { 3355 close: bool, 3356 } 3357 impl FeatureGate { 3358 fn open(src: &mut Source, stability: &Stability) -> FeatureGate { 3359 let close = if let Stability::Unstable { feature, .. } = stability { 3360 let feature_rust_name = feature.to_snake_case(); 3361 uwrite!(src, "if options.{feature_rust_name} {{"); 3362 true 3363 } else { 3364 false 3365 }; 3366 Self { close } 3367 } 3368 3369 fn close(self, src: &mut Source) { 3370 if self.close { 3371 uwriteln!(src, "}}"); 3372 } 3373 } 3374 } 3375 3376 /// Produce a string for tracing a function argument. 3377 fn formatting_for_arg( 3378 name: &str, 3379 index: usize, 3380 ty: Type, 3381 resolve: &Resolve, 3382 flags: FunctionFlags, 3383 ) -> String { 3384 if !flags.contains(FunctionFlags::VERBOSE_TRACING) && type_contains_lists(ty, resolve) { 3385 return format!("{name} = tracing::field::debug(\"...\")"); 3386 } 3387 3388 // Normal tracing. 3389 format!("{name} = tracing::field::debug(&arg{index})") 3390 } 3391 3392 /// Produce a string for tracing function results. 3393 fn formatting_for_results(result: Option<Type>, resolve: &Resolve, flags: FunctionFlags) -> String { 3394 let contains_lists = match result { 3395 Some(ty) => type_contains_lists(ty, resolve), 3396 None => false, 3397 }; 3398 3399 if !flags.contains(FunctionFlags::VERBOSE_TRACING) && contains_lists { 3400 return format!("result = tracing::field::debug(\"...\")"); 3401 } 3402 3403 // Normal tracing. 3404 format!("result = tracing::field::debug(&r)") 3405 } 3406 3407 /// Test whether the given type contains lists. 3408 /// 3409 /// Here, a `string` is not considered a list. 3410 fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool { 3411 match ty { 3412 Type::Id(id) => match &resolve.types[id].kind { 3413 TypeDefKind::Resource 3414 | TypeDefKind::Unknown 3415 | TypeDefKind::Flags(_) 3416 | TypeDefKind::Handle(_) 3417 | TypeDefKind::Enum(_) 3418 | TypeDefKind::Stream(_) 3419 | TypeDefKind::Future(_) => false, 3420 TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve), 3421 TypeDefKind::Result(Result_ { ok, err }) => { 3422 option_type_contains_lists(*ok, resolve) 3423 || option_type_contains_lists(*err, resolve) 3424 } 3425 TypeDefKind::Record(record) => record 3426 .fields 3427 .iter() 3428 .any(|field| type_contains_lists(field.ty, resolve)), 3429 TypeDefKind::Tuple(tuple) => tuple 3430 .types 3431 .iter() 3432 .any(|ty| type_contains_lists(*ty, resolve)), 3433 TypeDefKind::Variant(variant) => variant 3434 .cases 3435 .iter() 3436 .any(|case| option_type_contains_lists(case.ty, resolve)), 3437 TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve), 3438 TypeDefKind::List(_) => true, 3439 TypeDefKind::FixedLengthList(..) => todo!(), 3440 TypeDefKind::Map(..) => todo!(), 3441 }, 3442 3443 // Technically strings are lists too, but we ignore that here because 3444 // they're usually short. 3445 _ => false, 3446 } 3447 } 3448 3449 fn option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool { 3450 match ty { 3451 Some(ty) => type_contains_lists(ty, resolve), 3452 None => false, 3453 } 3454 } 3455 3456 /// When an interface `use`s a type from another interface, it creates a new TypeId 3457 /// referring to the definition TypeId. Chase this chain of references down to 3458 /// a TypeId for type's definition. 3459 fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId { 3460 loop { 3461 match resolve.types[id].kind { 3462 TypeDefKind::Type(Type::Id(def_id)) => id = def_id, 3463 _ => return id, 3464 } 3465 } 3466 } 3467 3468 fn rust_function_name(func: &Function) -> String { 3469 match func.kind { 3470 FunctionKind::Constructor(_) => "new".to_string(), 3471 FunctionKind::Method(_) 3472 | FunctionKind::Static(_) 3473 | FunctionKind::AsyncMethod(_) 3474 | FunctionKind::AsyncStatic(_) 3475 | FunctionKind::Freestanding 3476 | FunctionKind::AsyncFreestanding => to_rust_ident(func.item_name()), 3477 } 3478 } 3479 3480 fn func_field_name(resolve: &Resolve, func: &Function) -> String { 3481 let mut name = String::new(); 3482 match func.kind { 3483 FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => { 3484 name.push_str("method-"); 3485 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3486 name.push_str("-"); 3487 } 3488 FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => { 3489 name.push_str("static-"); 3490 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3491 name.push_str("-"); 3492 } 3493 FunctionKind::Constructor(id) => { 3494 name.push_str("constructor-"); 3495 name.push_str(resolve.types[id].name.as_ref().unwrap()); 3496 name.push_str("-"); 3497 } 3498 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {} 3499 } 3500 name.push_str(func.item_name()); 3501 name.to_snake_case() 3502 } 3503 3504 fn get_resources<'a>( 3505 resolve: &'a Resolve, 3506 id: InterfaceId, 3507 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a { 3508 resolve.interfaces[id] 3509 .types 3510 .iter() 3511 .filter_map(move |(name, ty)| match &resolve.types[*ty].kind { 3512 TypeDefKind::Resource => Some((*ty, name.as_str())), 3513 _ => None, 3514 }) 3515 } 3516 3517 fn get_resource_functions<'a>(resolve: &'a Resolve, resource_id: TypeId) -> Vec<&'a Function> { 3518 let resource = &resolve.types[resource_id]; 3519 match resource.owner { 3520 TypeOwner::World(id) => resolve.worlds[id] 3521 .imports 3522 .values() 3523 .filter_map(|item| match item { 3524 WorldItem::Function(f) => Some(f), 3525 _ => None, 3526 }) 3527 .filter(|f| f.kind.resource() == Some(resource_id)) 3528 .collect(), 3529 TypeOwner::Interface(id) => resolve.interfaces[id] 3530 .functions 3531 .values() 3532 .filter(|f| f.kind.resource() == Some(resource_id)) 3533 .collect::<Vec<_>>(), 3534 TypeOwner::None => { 3535 panic!("A resource must be owned by a world or interface"); 3536 } 3537 } 3538 } 3539 3540 fn get_world_resources<'a>( 3541 resolve: &'a Resolve, 3542 id: WorldId, 3543 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a { 3544 resolve.worlds[id] 3545 .imports 3546 .iter() 3547 .filter_map(move |(name, item)| match item { 3548 WorldItem::Type { id, .. } => match resolve.types[*id].kind { 3549 TypeDefKind::Resource => Some(match name { 3550 WorldKey::Name(s) => (*id, s.as_str()), 3551 WorldKey::Interface(_) => unreachable!(), 3552 }), 3553 _ => None, 3554 }, 3555 _ => None, 3556 }) 3557 } 3558