Macros: Filling text in comments

Hi everybody,
I am using macros to define a number of structures for which I would like to add specific documentation.
I have created a simple example to illustrate what I mean below.
In this example, I would like that in the docs appears something like Pin 0 for P0.
At the moment all I can get is Pin $i.
Is there a way to achieve this?

macro_rules! define {
    ( $( $S:ident, $i:expr ),* ) => {
        $(
            /// Pin $i
            struct $S;
        )*
    };
}

define!(P0, 0);

fn main() {
    let _p0 = P0;
    println!("Hello, world!");
}

(Playground)

I don't think this works (currently).

Documentation docs
Documentation text in that form is a sugared syntax for documentation attributes.

/// Documentation text
/// after newline
struct Item;

becomes

#[doc = "Documentation text"]
#[doc = "after newline"]
struct Item;

Both forms take string literals as parameters, there is no pass that expands provided variables first. Maybe this is easily doable in macro context, maybe not; I think a new syntax will be necessary to achieve this effect.

The macros std::include! and variants suffer from a similar problem; they take an expression but only an actual string literal works. This means that you cannot call them 'dynamically' from another macro.

There is a way to make it work, though it requires two macro invocations. Basically, #[doc = concat!("stuff")] doesn't parse, while #[doc = $doc] does.

This is not regarded as a bug.

macro_rules! define {
    ( $( $S:ident, $i:expr ),* ) => {
        define!{@gen $([ $S, $i, concat!("Pin ", stringify!($i))])*}
    };

    (@gen $( [$S:ident, $i:expr, $doc:expr] ),*) => {
        $(
            #[doc = $doc]
            pub struct $S;
        )*
    };
}

define!(P0, 0);

5 Likes

Thank you for the concise solution!