I'd like to use a macro variable in the macro-generated documentation:
macro_rules! impl_foo {
($name:ident) => {
/// Returns a new `$name`.
fn myfoo() -> $name {
}
};
}
However, the variable won't be substituted. I also tried using the #[doc]
attribute:
macro_rules! impl_foo {
($name:ident) => {
#[doc = concat!("Returns a new `", $name, "`.")]
fn myfoo() -> $name {
}
};
}
This one even fails to parse: unexpected token: 'concat'
The most widely used form of macros in Rust is the declarative macro. These are also sometimes referred to as “macros by example,” “ macro_rules! macros,” or just plain “macros.” At their core, declarative macros allow you to write something similar to a Rust match expression.
To write a custom derive macro in Rust, we can use DeriveInput for parsing input to derive macro. We'll also use the proc_macro_derive macro to define a custom derive macro. More advanced procedural macros can be written using syn . Check out this example from syn 's repo.
I'm reading a book about Rust, and start playing with Rust macros. All metavariable types are explained there and have examples, except the last one – tt . According to the book, it is a “a single token tree”.
Procedural macros allow you to run code at compile time that operates over Rust syntax, both consuming and producing Rust syntax. You can sort of think of procedural macros as functions from an AST to another AST. Procedural macros must be defined in a crate with the crate type of proc-macro .
While the answer @mcarton gave does work perfectly fine for simple examples, it breaks a bit for more complicated ones. Rustdoc seems to insert spaces between the different doc
attributes. The markdown processor strips them out most of the time, but sometimes, it transform them to spaces instead. Consider this example:
macro_rules! impl_foo {
($name:ident, $sname:expr) => {
#[doc = "You can call this as `myfoo("]
#[doc = $sname]
#[doc = ")`."]
pub fn myfoo(_: $name) -> $name {
42
}
};
($name:tt) => {
impl_foo!($name, stringify!($name));
};
}
impl_foo!(i32);
fn main() {
println!("Hello, world!");
}
This should generate the documentation "You can call this as myfoo(i32)
.", but in reality, it results in "You can call this as myfoo( i32 )
." (note the additional spaces):
I'm not too sure whether my solution would have worked with the 2017 rustc back when the question was asked, but in modern Rust, this can be done by combining stringify!
with concat!
:
macro_rules! impl_foo {
($name:tt) => {
#[doc = concat!("You can call this as `myfoo(", stringify!($name), ")`.")]
pub fn myfoo(_: $name) -> $name {
42
}
};
}
impl_foo!(i32);
fn main() {
println!("Hello, world!");
}
This results in the documentation you want (so, without superfluous spaces):
This can be done using a recursive macro:
macro_rules! impl_foo {
($name:ident, $sname:expr) => {
#[doc = "Returns a new `"]
#[doc = $sname]
#[doc = "`."]
pub fn myfoo() -> $name {
42
}
};
($name:tt) => {
impl_foo!($name, stringify!($name));
};
}
impl_foo!(u32);
fn main() {
println!("Hello, world!");
}
Which renders as:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With