* implement wasmtime::component::flags! per #4308 This is the last macro needed to complete #4308. It supports generating a Rust type that represents a `flags` component type, analogous to how the [bitflags crate](https://crates.io/crates/bitflags) operates. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * wrap `format_flags` output in parens This ensures we generate non-empty output even when no flags are set. Empty output for a `Debug` implementation would be confusing. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * unconditionally derive `Lift` and `Lower` in wasmtime::component::flags! Per feedback on #4414, we now derive impls for those traits unconditionally, which simplifies the syntax of the macro. Also, I happened to notice an alignment bug in `LowerExpander::expand_variant`, so I fixed that and cleaned up some related code. Finally, I used @jameysharp's trick to calculate bit masks without looping. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * fix shift overflow regression in previous commit Jamey pointed out my mistake: I didn't consider the case when the flag count was evenly divisible by the representation size. This fixes the problem and adds test cases to cover it. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::parse_macro_input;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::{parse_macro_input, Error, Result, Token};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn add_variants(
|
||||
@@ -32,3 +33,46 @@ fn expand_variants(count: &syn::LitInt, mut ty: syn::ItemEnum) -> syn::Result<To
|
||||
|
||||
Ok(quote!(#ty))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FlagsTest {
|
||||
name: String,
|
||||
flag_count: usize,
|
||||
}
|
||||
|
||||
impl Parse for FlagsTest {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let name = input.parse::<syn::Ident>()?.to_string();
|
||||
input.parse::<Token![,]>()?;
|
||||
let flag_count = input.parse::<syn::LitInt>()?.base10_parse()?;
|
||||
|
||||
Ok(Self { name, flag_count })
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn flags_test(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
expand_flags_test(&parse_macro_input!(input as FlagsTest))
|
||||
.unwrap_or_else(Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn expand_flags_test(test: &FlagsTest) -> Result<TokenStream> {
|
||||
let name = format_ident!("{}", test.name);
|
||||
let flags = (0..test.flag_count)
|
||||
.map(|index| {
|
||||
let name = format_ident!("F{}", index);
|
||||
quote!(const #name;)
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let expanded = quote! {
|
||||
wasmtime::component::flags! {
|
||||
#name {
|
||||
#flags
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(expanded)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user