attribute macro
- Rust course
- Advanced
- Lesson 50/81
- 4 min
Write an attribute macro with #[proc_macro_attribute].
Attribute macros
Attribute macros take the whole item they mark and put whatever they want in its place. They also take the attribute's own arguments:
#[proc_macro_attribute]
pub fn olcumle(arg: TokenStream, oge: TokenStream) -> TokenStream {
let mut f = syn::parse_macro_input!(oge as syn::ItemFn);
let ad = f.sig.ident.to_string();
let govde = &f.block;
f.block = syn::parse_quote!({
println!("{} çağrıldı", #ad);
#govde
});
quote::quote!(#f).into()
}
// usage:
#[olcumle]
fn kare(x: i32) -> i32 { x * x }#[tokio::main], things like #[test], and #[get("/")] in web frameworks are attribute macros.
Wrapping with macro_rules!
We can do the same transformation with macro_rules! by passing the function to the macro as an argument:
macro_rules! olcumle {
(fn $ad:ident($($arg:ident : $tur:ty),*) -> $don:ty $govde:block) => {
fn $ad($($arg: $tur),*) -> $don {
println!("{} çağrıldı", stringify!($ad));
$govde
}
};
}
olcumle! {
fn kare(x: i32) -> i32 { x * x }
}$govde:block captures the braced body as a single piece.
Practice Report the call
Write the olcumle! macro above and define the function fn kare(x: i32) -> i32 { x * x } with it. In main, print the result of kare(4).
Starter code
fn main() {
// buraya yaz
}Sample solution
macro_rules! olcumle {
(fn $ad:ident($($arg:ident : $tur:ty),*) -> $don:ty $govde:block) => {
fn $ad($($arg: $tur),*) -> $don {
println!("{} çağrıldı", stringify!($ad));
$govde
}
};
}
olcumle! {
fn kare(x: i32) -> i32 {
x * x
}
}
fn main() {
let s = kare(4);
println!("{}", s);
}Expected output
kare çağrıldı 16
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What happens if an attribute macro takes the function but doesn't put it in the output?
- It warns
- The function disappears from the program Correct answer
- The compiler adds it back
- Panic
Explanation: An attribute macro fully replaces the item; preserving the original item is the macro's responsibility.
2 Capture the body
(fn $ad:ident($($arg:ident : $tur:ty),*) -> $don:ty $govde:____) => { .. }
(fn $ad:ident($($arg:ident : $tur:ty),*) -> $don:ty $govde:block) => { .. }
Explanation: The block fragment matches a braced block.
3 Attribute and role
| Term | Meaning |
|---|---|
#[proc_macro_attribute] |
Defines an attribute macro |
arg: TokenStream |
Attribute arguments |
oge: TokenStream |
The marked item |
syn::ItemFn |
Function tree |