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.

  1. À 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.