liveBook · Manning

Derive macro

As explained in Idiomatic Rust

A derive attribute instructs the Rust compiler to generate implementations for specified traits or other derived functionality.

The #[derive(...)] attribute asks the compiler to generate implementations, commonly for traits such as Clone, Debug, and Default. It reduces boilerplate on structs and enums; write a manual implementation when you need behavior the derived one does not provide. section 2.2.5 section 8.3

use std::fmt::Debug;

#[derive(Clone, Debug, Default)]
struct Pumpkin {
    mass: f64,
    diameter: f64,
}

A struct deriving Clone, Debug, and Default shows the attribute in its simplest form. section 2.2.5

A custom derive is a procedural macro written in a separate library crate. It receives Rust syntax and returns generated Rust syntax at compile time; derive macros attach to struct or enum declarations. section 8.3

Listing 8.9 Implementing the PrintName derive macro
#[proc_macro_derive(PrintName)]
pub fn print_name(input: TokenStream) -> TokenStream {   #1
    let input = parse_macro_input!(input as DeriveInput);    #1

    let generics = add_trait_bounds(input.generics);         #2
    let (impl_generics, type_generics, where_clause) =   #3
        generics.split_for_impl();          #3            

    let name = input.ident;

    let expanded = quote! {                 #4
        impl #impl_generics print_name::PrintName for #name #type_generics
                #where_clause {
            fn name() -> &'static str {
                stringify!(#name)       #5
            }
        }
    };

    TokenStream::from(expanded)     #6
}

fn add_trait_bounds(mut generics: Generics) -> Generics {
    for param in &mut generics.params {
        if let GenericParam::Type(ref mut type_param) = *param {
          type_param.bounds.push(                   #7
            parse_quote!(print_name::PrintName)    #7
          );   #7                                     
        }
    }
    generics
}

This implementation parses a derive input and generates a trait implementation, including handling generics. section 8.3

Choose a manual implementation for custom defaults

A derived Default creates a zeroed Pumpkin. To give it a mass of 2.0 and diameter of 5.0 instead, replace the derive with an explicit Default implementation. section 2.2.5

How Idiomatic Rust covers it

How deep it goes
Explains built-in derives and sketches a custom procedural derive, but stops short of broader procedural-macro treatment.
Examples
Uses Clone, Debug, and Default on Pumpkin, contrasts a custom Default implementation, and derives PrintName for a struct.
What you can do after
Build it from scratch by implementing a procedural derive in a separate library crate that generates Rust syntax.
How it connects
Connects traits, procedural macros, generics, and trait bounds.

Also explained in

Compare how 5 books explain derive macro →

Related concepts

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