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