Rust macros from a beginner point of view
This tracks what I understood writting my first real rust macro.
The goal was to simplify creating test data while writting a text adventure game framework of library in Rust.
The model is a simplifier first version of what I want achieve later.
It starts with just a Book
that contains Chapters
, the Chapters
have an Id
, their own text, plus a list of Choices
that associate some descriptions to the Id of the chapter that must be read if the player make that choice.
The current allows writting this:
#![allow(unused)] fn main() { let l = livre![ //. chapter_one_id: { // This is a chapter "text of chapter one", // This is the text of the chapter chapter_one_id: "Make choice one", // This is a choice chapter_two_id: "Make choice two", chapter_three_id: "Make choice three" }, chapter_two_id: { "texte du chapitre deux", chapter_two_id: "Make choice one" }, chapter_three_id: { "texte du chapitre trois", chapter_three_id: "Make choice one" } ]; }
instead of this:
#![allow(unused)] fn main() { let l = Livre { chapitres: HashMap::from([ ( "chapter_one_id".into(), Chapitre { texte: "text of chapter one".into(), choix: vec![ ("chapter_one_id".into(), "Make choice one".into()), ("chapter_two_id".into(), "Make choice two".into()), ("chapter_three_id".into(), "Make choice three".into()), ], }, ), ( "chapter_two_id".into(), Chapitre { texte: "text of chapter two".into(), choix: vec![("chapter_one_id".into(), "Make choice one".into()),], }, ), ( "chapter_three_id".into(), Chapitre { texte: "text of chapter three".into(), choix: vec![("chapter_three_id".into(), "Make choice one".into()),], }, ), ]), }; }
The original code is available on this version of the code.
development environnement
I used:
- the Rust By Example book
- the specification of the Macro By Example from the Rust Reference
- a nightly version of rust which allows the
trace_macros
feature:
$ rustc --version
rustc 1.84.0-nightly (03ee48451 2024-11-18)
the choice!
macro
I tried to start with a macro to generate Chapter
s, but this one hade two separate problems since the pattern for Choice
s and the text of the chapter where a bit different.
After some attempts, I simplified the problem by starting writting a macro for choices only.
It is used like this:
#![allow(unused)] fn main() { choice! { //. id_chapter_one: "Make first choice", id_chapter_three: "Make second choice", }; }
and produces a code Rust code eauivalent to:
#![allow(unused)] fn main() { vec![ ("id_chapter_one".into(), "Make first choice".into()), ("id_chapter_three".into(), "Make second choice".into()), ] }
truvc dont il faut parler :
stringify!()
- comment il arrive a trouver le type du
into()
et comment j'ai pu virer leString::from()
-la macro peut s'appeler avec des crochet ou des accolades aussi (q: peut on faire des matchings differents pour les trois cas ?)