Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions crates/guest-rust/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ impl Parse for Config {
.map(|p| p.into_token_stream().to_string())
.collect()
}
Opt::AdditionalDerivesIgnore(list) => {
opts.additional_derive_ignore =
list.into_iter().map(|i| i.value()).collect()
}
Opt::With(with) => opts.with.extend(with),
Opt::GenerateAll => {
opts.generate_all = true;
Expand Down Expand Up @@ -323,6 +327,7 @@ mod kw {
syn::custom_keyword!(stubs);
syn::custom_keyword!(export_prefix);
syn::custom_keyword!(additional_derives);
syn::custom_keyword!(additional_derives_ignore);
syn::custom_keyword!(with);
syn::custom_keyword!(generate_all);
syn::custom_keyword!(type_section_suffix);
Expand Down Expand Up @@ -383,6 +388,7 @@ enum Opt {
ExportPrefix(syn::LitStr),
// Parse as paths so we can take the concrete types/macro names rather than raw strings
AdditionalDerives(Vec<syn::Path>),
AdditionalDerivesIgnore(Vec<syn::LitStr>),
With(HashMap<String, WithOption>),
GenerateAll,
TypeSectionSuffix(syn::LitStr),
Expand Down Expand Up @@ -496,6 +502,13 @@ impl Parse for Opt {
syn::bracketed!(contents in input);
let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
Ok(Opt::AdditionalDerives(list.iter().cloned().collect()))
} else if l.peek(kw::additional_derives_ignore) {
input.parse::<kw::additional_derives_ignore>()?;
input.parse::<Token![:]>()?;
let contents;
syn::bracketed!(contents in input);
let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
Ok(Opt::AdditionalDerivesIgnore(list.iter().cloned().collect()))
} else if l.peek(kw::with) {
input.parse::<kw::with>()?;
input.parse::<Token![:]>()?;
Expand Down
32 changes: 25 additions & 7 deletions crates/rust/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1821,7 +1821,15 @@ pub mod vtable{ordinal} {{
.collect();
for (name, mode) in self.modes_of(id) {
self.rustdoc(docs);
let mut derives = additional_derives.clone();
let mut derives = BTreeSet::new();
if !self
.gen
.opts
.additional_derive_ignore
.contains(&name.to_kebab_case())
{
derives.extend(additional_derives.clone());
}
if info.is_copy() {
self.push_str("#[repr(C)]\n");
derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
Expand Down Expand Up @@ -1924,7 +1932,15 @@ pub mod vtable{ordinal} {{
.collect();
for (name, mode) in self.modes_of(id) {
self.rustdoc(docs);
let mut derives = additional_derives.clone();
let mut derives = BTreeSet::new();
if !self
.gen
.opts
.additional_derive_ignore
.contains(&name.to_kebab_case())
{
derives.extend(additional_derives.clone());
}
if info.is_copy() {
derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
} else if info.is_clone() {
Expand Down Expand Up @@ -2072,13 +2088,15 @@ pub mod vtable{ordinal} {{
self.int_repr(enum_.tag());
self.push_str(")]\n");
// We use a BTree set to make sure we don't have any duplicates and a stable order
let mut derives: BTreeSet<String> = self
let mut derives: BTreeSet<String> = BTreeSet::new();
if !self
.gen
.opts
.additional_derive_attributes
.iter()
.cloned()
.collect();
.additional_derive_ignore
.contains(&name.to_kebab_case())
{
derives.extend(self.gen.opts.additional_derive_attributes.to_vec());
}
derives.extend(
["Clone", "Copy", "PartialEq", "Eq", "PartialOrd", "Ord"]
.into_iter()
Expand Down
16 changes: 16 additions & 0 deletions crates/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,15 @@ pub struct Opts {
#[cfg_attr(feature = "clap", arg(long = "additional_derive_attribute", short = 'd', default_values_t = Vec::<String>::new()))]
pub additional_derive_attributes: Vec<String>,

/// Variants and records to ignore when applying additional derive attributes.
///
/// These names are specified as they are listed in the wit file, i.e. in kebab case.
/// This feature allows some variants and records to use types for which adding traits will cause
/// compilation to fail, such as serde::Deserialize on wasi:io/streams.
///
#[cfg_attr(feature = "clap", arg(long = "additional_derive_ignore", default_values_t = Vec::<String>::new()))]
pub additional_derive_ignore: Vec<String>,

/// Remapping of wit interface and type names to Rust module names and types.
///
/// Argument must be of the form `k=v` and this option can be passed
Expand Down Expand Up @@ -1030,6 +1039,13 @@ impl WorldGenerator for RustWasm {
self.opts.additional_derive_attributes
);
}
if !self.opts.additional_derive_ignore.is_empty() {
uwriteln!(
self.src_preamble,
"// * additional derives ignored {:?}",
self.opts.additional_derive_ignore
);
}
for (k, v) in self.opts.with.iter() {
uwriteln!(self.src_preamble, "// * with {k:?} = {v}");
}
Expand Down
21 changes: 20 additions & 1 deletion crates/rust/tests/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,13 +388,26 @@ mod custom_derives {
inline: "
package my:inline;

interface blag {
resource input-stream {
read: func(len: u64) -> list<u8>;
}
}

interface blah {
use blag.{input-stream};
record foo {
field1: string,
field2: list<u32>
}

bar: func(cool: foo);

variant ignoreme {
stream-type(input-stream),
}

barry: func(warm: ignoreme);
}

world baz {
Expand All @@ -405,9 +418,10 @@ mod custom_derives {
// Clone is included by default almost everywhere, so include it here to make sure it
// doesn't conflict
additional_derives: [serde::Serialize, serde::Deserialize, Hash, Clone, PartialEq, Eq],
additional_derives_ignore: ["ignoreme"],
});

use exports::my::inline::blah::Foo;
use exports::my::inline::blah::{Foo, Ignoreme};

struct Component;

Expand All @@ -423,6 +437,11 @@ mod custom_derives {
// compilation will fail here
let _ = serde_json::to_string(&cool);
}

fn barry(warm: Ignoreme) {
// Compilation would fail if serde::Deserialize was applied to Ignoreme
let _ = warm;
}
}

export!(Component);
Expand Down
Loading