
About this workshop
Most Rust codebases depend on procedural macros like #[derive(Serialize)], #[tokio::main], and sqlx::query!. They keep a large amount of repetitive code out of your project by generating it at compile time. The same applies to your own code: custom macros can keep codebases tidy, concise, and consistent.
This workshop teaches you how to write your own macros. You will build all three kinds of procedural macros – derive macros, attribute macros, and function-like macros – parsing Rust syntax with syn and generating code with quote. By the end of the day you will know when a macro is the right call and how to write one your colleagues can use without reading its source.
The workshop is designed for developers who have a good understanding of Rust. If you are new to Rust, start with our "Learn Rust, starting from scratch" workshop for an introduction to the language.
Bookable for teams
Syllabus
Introduction
Rust has three kinds of procedural macros, and you have used all of them already. We will look at derive, function-like, and attribute macros in the wild, expandthiserrorwithcargo expandto see what they generate, and compare macros against plain functions andmacro_rules!so you know when a procedural macro is the right call – and when it is not.The proc-macro toolkit
Time to get your hands dirty. You will set up a proc-macro crate, write a minimal derive macro, and learn what a macro actually receives and returns: tokens and token streams, whyproc-macro2makes your code testable, parsing Rust code withsyn, and generating it withquote. We will also cover the re-export pattern used byserdeandthiserror, and how to test a macro withtrybuild.Derive macros
Where the real work happens: handling every struct field layout and enums, absolute paths and hygienic identifiers so your output compiles in anyone's crate, error reporting frompanic!tocompile_error!to properly spannedsyn::Errors, container and field attributes by hand and then withdarling, and generics with lifetimes andwhereclauses..Function-like macros
Whatever sits between a macro's delimiters is yours to interpret, even if it is not valid Rust. We will cover whyprintln!has to be a macro, how to parse arbitrary token input, how to define your own syntax, and when to prefer this over a declarative macro. You will finish by building a small DSL: aroutes!macro.Attribute macros
Unlike a derive, an attribute macro receives the annotated item and returns its replacement. We will cover the parse-tweak-re-emit loop on a function, graceful error handling by re-emitting the original item to avoid cascading errors, and parsing attribute arguments withdarling'sFromMetato build a#[retry(times = 3, delay_ms = 100)]attribute.Putting it all together
A capstone that draws on the whole day: a#[derive(StateMachine)]macro. Code generation over an enum's variants, custom helper attributes declaring the initial state and the allowed transitions, invalid transitions rejected at compile time with the error spanned on the offending token, and generated identifiers that never clash.
Who we are
Mainmatter has been active in the Rust ecosystem for years, creating the 100 Exercises to Learn Rust course, the C to Rust Migration Book organizing EuroRust, and contributing to open source.
We help teams adopt and build on Rust with confidence via trainings and workshops, hands-on team reinforcement, codebase assessments, and more.
We have trained developers at
Bookable for teams

