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