liveBook · Manning

Rename attribute

As explained in Write Powerful Rust Macros

A rename attribute is the book-specific helper attribute that specifies an alternate property name for generated builder code.

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

How Write Powerful Rust Macros covers it

How deep it goes
Traces helper-attribute declaration, field lookup, metadata parsing, and method-name generation, with malformed forms handled by panic and unwrap.
Examples
Uses a Gleipnir field named roots_of and generates the alternate tops_of setter.
What it assumes
Assumes Rust derive-macro and syn basics while identifying field attributes and metadata during implementation.
What you can do after
Build a derive macro that accepts rename and emits a setter using its string argument.
How it connects
Connects derive macros, procedural macro helper attributes, struct fields, metadata parsing, and builder method generation.

This explainer was generated by Manning's knowledge graph from the text of Write Powerful Rust Macros. The section links point to the parts of the book it draws on.