Ajout automatique de traces
On souhaite implémenter une macro log_function
qui a l'effet suivant :
log_function! {
#[must_use]
fn mul(a: u32, b: u32) -> u32 {
a * b
}
}
fn main() {
let x = mul(10, 20);
println!("x = {x}");
}
affichera quelque chose comme
$ cargo run
Entering function mul
Leaving function mul after 64ns
x = 200
L'attribut #[must_use]
n'a aucun intérêt ici si ce n'est de montrer qu'on souhaite que le paramètre de la macro soit une fonction quelconque et conserve toutes ses propriétés lors de l'expansion.
- À l'aide des mêmes outils que précédemment, implémentez
macros::log_function
sous la forme d'une macro procédurale.
On cherchera dans le crate syn
le type utilisé pour représenter une fonction complète. On pourra également s'intéresser à la macro syn::parse_quote
qui fonctionne comme la macro quote::quote
mais construit un type dépendant de son contexte plutôt qu'un proc_macro2::TokenStream
comme le fait quote::quote
. Elle est très utile pour construire des constructions intermédiaires, comme celle représentant le corps d'une fonction.
On prendra un soin particulier à ne pas dépendre des entités présentes dans le contexte. Notamment, si on souhaite utiliser un std::time::Instant
, on le qualifiera de ::std::time::Instant
pour indiquer qu'on souhaite partir à la racine de la hiérarchie des modules même si un module local appelé std
existe.