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