A rename attribute specifies an alternate property name for generated builder code, changing the setter method while preserving the original struct field. section 8.1.1
Renaming a builder setter
A field such as #[rename("tops_of")] roots_of: String should produce a builder callable as .tops_of("mountains".to_string()), while the resulting value remains available through gleipnir.roots_of. section 8.1.1
Implement the attribute by:
- Declaring rename as a derive macro helper attribute. section 8.1.1
- Searching each syn::Field's attrs for an attribute whose path is_ident("rename"). section 8.1.2
- Parsing the attribute's list argument as a LitStr and using its value as the generated Ident; otherwise, retaining the field name. section 8.1.2
Listing 8.5 New builder_methods code in fields.rs
// earlier imports
use syn::{Meta, LitStr};
pub fn builder_methods(fields: &Punctuated<Field, Comma>)
-> Vec<TokenStream> {
fields.iter()
.map(|f| {
let (field_name, field_type) = get_name_and_type(f);
let attr = extract_attribute_from_field(f, "rename") #1
.map(|a| &a.meta)
.map(|m| {
match m {
Meta::List(nested) => {
let a: LitStr = nested
.parse_args()
.unwrap();
Ident::new(&a.value(), a.span())
}
Meta::Path(_) => {
panic!(
"expected brackets with name of prop"
)
},
Meta::NameValue(_) => {
panic!(
"did not expect name + value"
)
}
}
}); #2
if let Some(attr) = attr {
quote! { #3
pub fn #attr(mut self, input: #field_type) -> Self {
self.#field_name = Some(input);
self
}
}
} else {
quote! { #4
pub fn #field_name(mut self, input: #field_type) -> Self {
self.#field_name = Some(input);
self
}
}
}
}).collect()
}
Inspect the builder_methods expansion that retrieves rename, parses its argument, and selects the generated setter identifier. section 8.1.2
