Skip to content

Commit 0fdc730

Browse files
authored
[Rust] flip the generation default for non-local interfaces (#972)
* Flip the default for non-local interfaces Signed-off-by: Ryan Levick <ryan.levick@fermyon.com> * Add option to generate all interfaces Signed-off-by: Ryan Levick <ryan.levick@fermyon.com> * Track generated interfaces are used as well Signed-off-by: Ryan Levick <ryan.levick@fermyon.com> * Fix rustdoc errors Signed-off-by: Ryan Levick <ryan.levick@fermyon.com> --------- Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
1 parent 58ade72 commit 0fdc730

File tree

16 files changed

+236
-59
lines changed

16 files changed

+236
-59
lines changed

crates/c/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl WorldGenerator for C {
176176
name: &WorldKey,
177177
id: InterfaceId,
178178
_files: &mut Files,
179-
) {
179+
) -> Result<()> {
180180
let wasm_import_module = resolve.name_world_key(name);
181181
let mut gen = self.interface(resolve, true, Some(&wasm_import_module));
182182
gen.interface = Some((id, name));
@@ -192,6 +192,8 @@ impl WorldGenerator for C {
192192
}
193193

194194
gen.gen.src.append(&gen.src);
195+
196+
Ok(())
195197
}
196198

197199
fn import_funcs(

crates/core/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ pub trait WorldGenerator {
3737
for (name, import) in world.imports.iter() {
3838
match import {
3939
WorldItem::Function(f) => funcs.push((unwrap_name(name), f)),
40-
WorldItem::Interface { id, .. } => self.import_interface(resolve, name, *id, files),
40+
WorldItem::Interface { id, .. } => {
41+
self.import_interface(resolve, name, *id, files)?
42+
}
4143
WorldItem::Type(id) => types.push((unwrap_name(name), *id)),
4244
}
4345
}
@@ -91,7 +93,7 @@ pub trait WorldGenerator {
9193
name: &WorldKey,
9294
iface: InterfaceId,
9395
files: &mut Files,
94-
);
96+
) -> Result<()>;
9597

9698
/// Called before any exported interfaces are generated.
9799
fn pre_export_interface(&mut self, resolve: &Resolve, files: &mut Files) -> Result<()> {

crates/csharp/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ impl WorldGenerator for CSharp {
196196
key: &WorldKey,
197197
id: InterfaceId,
198198
_files: &mut Files,
199-
) {
199+
) -> Result<()> {
200200
let name = interface_name(self, resolve, key, Direction::Import);
201201
self.interface_names.insert(id, name.clone());
202202
let mut gen = self.interface(resolve, &name, Direction::Import);
@@ -232,6 +232,8 @@ impl WorldGenerator for CSharp {
232232
gen.define_interface_types(id);
233233

234234
gen.add_interface_fragment(false);
235+
236+
Ok(())
235237
}
236238

237239
fn import_funcs(

crates/go/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ impl WorldGenerator for TinyGo {
169169
name: &WorldKey,
170170
id: InterfaceId,
171171
_files: &mut Files,
172-
) {
172+
) -> Result<()> {
173173
let name_raw = &resolve.name_world_key(name);
174174
self.src
175175
.push_str(&format!("// Import functions from {name_raw}\n"));
@@ -187,6 +187,8 @@ impl WorldGenerator for TinyGo {
187187
let preamble = mem::take(&mut gen.preamble);
188188
self.src.push_str(&src);
189189
self.preamble.append_src(&preamble);
190+
191+
Ok(())
190192
}
191193

192194
fn import_funcs(

crates/guest-rust/macro/src/lib.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use syn::parse::{Error, Parse, ParseStream, Result};
77
use syn::punctuated::Punctuated;
88
use syn::{braced, token, Token};
99
use wit_bindgen_core::wit_parser::{PackageId, Resolve, UnresolvedPackage, WorldId};
10-
use wit_bindgen_rust::{Opts, Ownership};
10+
use wit_bindgen_rust::{Opts, Ownership, WithOption};
1111

1212
#[proc_macro]
1313
pub fn generate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
@@ -99,6 +99,9 @@ impl Parse for Config {
9999
.collect()
100100
}
101101
Opt::With(with) => opts.with.extend(with),
102+
Opt::GenerateAll => {
103+
opts.with.generate_by_default = true;
104+
}
102105
Opt::TypeSectionSuffix(suffix) => {
103106
opts.type_section_suffix = Some(suffix.value());
104107
}
@@ -234,6 +237,7 @@ mod kw {
234237
syn::custom_keyword!(export_prefix);
235238
syn::custom_keyword!(additional_derives);
236239
syn::custom_keyword!(with);
240+
syn::custom_keyword!(generate_all);
237241
syn::custom_keyword!(type_section_suffix);
238242
syn::custom_keyword!(disable_run_ctors_once_workaround);
239243
syn::custom_keyword!(default_bindings_module);
@@ -284,7 +288,8 @@ enum Opt {
284288
ExportPrefix(syn::LitStr),
285289
// Parse as paths so we can take the concrete types/macro names rather than raw strings
286290
AdditionalDerives(Vec<syn::Path>),
287-
With(HashMap<String, String>),
291+
With(HashMap<String, WithOption>),
292+
GenerateAll,
288293
TypeSectionSuffix(syn::LitStr),
289294
DisableRunCtorsOnceWorkaround(syn::LitBool),
290295
DefaultBindingsModule(syn::LitStr),
@@ -390,6 +395,9 @@ impl Parse for Opt {
390395
let fields: Punctuated<_, Token![,]> =
391396
contents.parse_terminated(with_field_parse, Token![,])?;
392397
Ok(Opt::With(HashMap::from_iter(fields.into_iter())))
398+
} else if l.peek(kw::generate_all) {
399+
input.parse::<kw::generate_all>()?;
400+
Ok(Opt::GenerateAll)
393401
} else if l.peek(kw::type_section_suffix) {
394402
input.parse::<kw::type_section_suffix>()?;
395403
input.parse::<Token![:]>()?;
@@ -427,7 +435,7 @@ impl Parse for Opt {
427435
}
428436
}
429437

430-
fn with_field_parse(input: ParseStream<'_>) -> Result<(String, String)> {
438+
fn with_field_parse(input: ParseStream<'_>) -> Result<(String, WithOption)> {
431439
let interface = input.parse::<syn::LitStr>()?.value();
432440
input.parse::<Token![:]>()?;
433441
let start = input.span();
@@ -438,6 +446,10 @@ fn with_field_parse(input: ParseStream<'_>) -> Result<(String, String)> {
438446
.join(path.segments.last().unwrap().ident.span())
439447
.unwrap_or(start);
440448

449+
if path.is_ident("generate") {
450+
return Ok((interface, WithOption::Generate));
451+
}
452+
441453
let mut buf = String::new();
442454
let append = |buf: &mut String, segment: syn::PathSegment| -> Result<()> {
443455
if !segment.arguments.is_none() {
@@ -467,7 +479,7 @@ fn with_field_parse(input: ParseStream<'_>) -> Result<(String, String)> {
467479
append(&mut buf, segment)?;
468480
}
469481

470-
Ok((interface, buf))
482+
Ok((interface, WithOption::Path(buf)))
471483
}
472484

473485
/// Format a valid Rust string

crates/guest-rust/src/examples/_1_interface_imports.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ crate::generate!({
2424
"#,
2525

2626
path: "wasi-cli@0.2.0.wasm",
27+
28+
// specify that this interface dependency should be generated as well.
29+
with: {
30+
"wasi:cli/environment@0.2.0": generate,
31+
}
2732
});

crates/guest-rust/src/examples/_3_world_exports.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,11 @@ crate::generate!({
3737

3838
// provided to specify the path to `wasi:*` dependencies referenced above.
3939
path: "wasi-cli@0.2.0.wasm",
40+
41+
// specify that these interface dependencies should be generated as well.
42+
with: {
43+
"wasi:random/insecure@0.2.0": generate,
44+
"wasi:clocks/monotonic-clock@0.2.0": generate,
45+
"wasi:io/poll@0.2.0": generate
46+
}
4047
});

crates/guest-rust/src/lib.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -668,25 +668,30 @@
668668
/// // By default this set is empty.
669669
/// additional_derives: [PartialEq, Eq, Hash, Clone],
670670
///
671-
/// // When generating bindings for imports it might be the case that
672-
/// // bindings were already generated in a different crate. For example
673-
/// // if your world refers to WASI types then the `wasi` crate already
674-
/// // has generated bindings for all WASI types and structures. In this
671+
/// // When generating bindings for interfaces that are not defined in the
672+
/// // same package as `world`, this option can be used to either generate
673+
/// // those bindings or point to already generated bindings.
674+
/// // For example, if your world refers to WASI types then the `wasi` crate
675+
/// // already has generated bindings for all WASI types and structures. In this
675676
/// // situation the key `with` here can be used to use those types
676677
/// // elsewhere rather than regenerating types.
677678
/// //
678-
/// // The `with` key here only works for interfaces referred to by imported
679-
/// // functions. Additionally it only supports replacing types at the
680-
/// // interface level at this time.
679+
/// // If, however, your world refers to interfaces for which you don't have
680+
/// // already generated bindings then you can use the special `generate` value
681+
/// // to have those bindings generated.
681682
/// //
682-
/// // When an interface is specified here no bindings will be generated at
683-
/// // all. It's assumed bindings are fully generated upstream. This is an
683+
/// // The `with` key only supports replacing types at the interface level
684+
/// // at this time.
685+
/// //
686+
/// // When an interface is specified no bindings will be generated at
687+
/// // all. It's assumed bindings are fully generated somewhere else. This is an
684688
/// // indicator that any further references to types defined in these
685689
/// // interfaces should use the upstream paths specified here instead.
686690
/// //
687691
/// // Any unused keys in this map are considered an error.
688692
/// with: {
689693
/// "wasi:io/poll": wasi::io::poll,
694+
/// "some:package/my-interface": generate,
690695
/// },
691696
///
692697
/// // An optional list of function names to skip generating bindings for.

crates/markdown/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ impl WorldGenerator for Markdown {
117117
name: &WorldKey,
118118
id: InterfaceId,
119119
_files: &mut Files,
120-
) {
120+
) -> Result<()> {
121121
let name = resolve.name_world_key(name);
122122
uwriteln!(
123123
self.src,
@@ -131,6 +131,8 @@ impl WorldGenerator for Markdown {
131131
gen.push_str("\n");
132132
gen.types(id);
133133
gen.funcs(id);
134+
135+
Ok(())
134136
}
135137

136138
fn import_funcs(

0 commit comments

Comments
 (0)