Это можно сделать с помощью процедурного макроса:
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn with_name(_: TokenStream, item: TokenStream) -> TokenStream {
let mut input = syn::parse_macro_input!(item as syn::ItemFn);
let fn_name = input.ident.to_string();
let const_decl = quote::quote! {
const THIS_FN: &str = #fn_name;
};
input.block.stmts.insert(0, syn::parse(const_decl.into()).unwrap());
let output = quote::quote! {
#input
};
output.into()
}
Cargo.toml:
[package]
name = "with_name"
version = "0.1.0"
edition = "2018"
[lib]
proc-macro = true
[dependencies]
quote = "0.6.12"
syn = { version = "0.15.37", features = ["full"] }
Который может использоваться как:
#[with_name::with_name]
fn foo() {
println!("Name: {}", THIS_FN);
}
fn main() {
foo();
}
Также обратите внимание, что если вы заботитесь только о модуле, для этого есть встроенный макрос :
mod test {
pub fn foo() {
println!("Module: {}", module_path!());
}
}
fn main() {
test::foo();
}
(ссылка на игровую площадку)