Macro_rules macros cannot do this. You would need to implement it as a procedural macro, which is allowed to perform arbitrary Rust code to generate the expanded code. In particular, procedural macros are able to call str::to_uppercase
and str::to_lowercase
.
// [dependencies]
// quote = "1.0"
// syn = "1.0"
use proc_macro::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::{parse_macro_input, Expr, Ident, Token};
struct Input {
flags: Vec<Ident>,
values: Vec<Expr>,
}
// $( $flag:ident = $value:expr; )*
impl Parse for Input {
fn parse(input: ParseStream) -> Result<Self> {
let mut flags = Vec::new();
let mut values = Vec::new();
while !input.is_empty() {
flags.push(input.parse()?);
input.parse::<Token![=]>()?;
values.push(input.parse()?);
input.parse::<Token![;]>()?;
}
Ok(Input { flags, values })
}
}
#[proc_macro]
pub fn sleeping_panda(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as Input);
let camelcase_flags = &input.flags; // assume CamelCase in the input
let bitflag_values = &input.values;
let uppercase_flags = input
.flags
.iter()
.map(|ident| Ident::new(&ident.to_string().to_uppercase(), ident.span()));
// Some copies because these need to appear multiple times in the generated code.
let uppercase_flags2 = uppercase_flags.clone();
let uppercase_flags3 = uppercase_flags.clone();
let lowercase_flags = input
.flags
.iter()
.map(|ident| Ident::new(&ident.to_string().to_lowercase(), ident.span()));
TokenStream::from(quote! {
bitflags::bitflags! (
struct KeyType: u64 {
#(
const #uppercase_flags = #bitflag_values;
)*
}
);
pub struct SleepingPanda {
flags: KeyType,
}
impl SleepingPanda {
pub fn receive_event(&mut self, event: sdl2::event::Event) {
match event {
#(
sdl2::event::Event::KeyDown {
keycode: Some(sdl2::keyboard::Keycode::#camelcase_flags),
..
} => {
self.flags.insert(KeyType::#uppercase_flags2);
}
)*
_ => {}
}
}
#(
pub fn #lowercase_flags(&self) -> bool {
self.flags.contains(KeyType::#uppercase_flags3)
}
)*
}
})
}
Using the macro:
use sleeping_panda::sleeping_panda;
sleeping_panda! {
Backspace = 8;
Tab = 9;
}
fn main() {}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…