I'm trying to write a Rust macro that allows me to make use of the field names and types of a struct declaration, but I still need to emit the struct.
I've got it working with optional attributes, visibility of the struct (thanks to The Little Book of Rust Macros), but can't figure out how to deal with the optional presence of pub
in the individual fields.
So far I've got:
macro_rules! with_generic {
($(#[$struct_meta:meta])*
pub struct $name:ident { $($fname:ident : $ftype:ty), *}
) => {
with_generic![(pub) $(#[$struct_meta])* struct $name {$($fname: $ftype) ,*}];
};
($(#[$struct_meta:meta])*
struct $name:ident { $($fname:ident : $ftype:ty), *}
) => {
with_generic![() $(#[$struct_meta])* struct $name {$($fname: $ftype), *}];
};
(
($($vis:tt)*)
$(#[$struct_meta:meta])*
struct $name:ident { $($fname:ident : $ftype:ty), *}
) => {
// emit the struct here
$(#[$struct_meta])*
$($vis)* struct $name {
$($fname: $ftype,)*
}
// I work with fname and ftypes here
}
}
And it works with something like
with_generic! {
#[derive(PartialEq, Eq, Debug)]
pub struct Person {
first_name: String,
last_name: String
}
}
or
with_generic! {
#[derive(PartialEq, Eq, Debug)]
struct PrivatePerson {
first_name: String,
last_name: String
}
}
but doesn't work with
with_generic! {
#[derive(PartialEq, Eq, Debug)]
struct MixedPerson {
pub first_name: String,
last_name: String
}
}
I'd like to get some help on how to make the macro work with that last case. I feel like I might be missing something basic here, such as the type used for binding visibility. If there's a way to bind the whole struct tree while getting the field names and types, that would also be fine.
I'd also like to learn how to get it to work with structs that have lifetime parameters, but maybe that should be a separate question.