articles

Any donation is very welcome

Using macro to generate generic docs?

We were recently able to finally make the docs for integer primitive types much more accurate (thanks to @antoyo!). Now, the code examples match the type for which they're written. No more i32 examples for i128 (I think you got the idea at this point)!

Now, I think a few people might be interested by the method we used to achieve such a result so let's talk about it.

The not very well known #[doc] attribute

All this was possible thanks to this attribute. Since it's not very well-known, let's explain a bit first how this attribute works:

In Rust, you have two ways to add a doc comment over an item:

Run/// The classic one.
///
/// Fancy and everything.
fn some_function() {}

And the second one is:

Run#[doc = "The not so classic.

But works just as fine!"]
fn some_function() {}

Now why is not possible to generate generic documentation using "///"?

Macro limitations

I invite you to test this (or at least try to make it work):

Runmacro_rules! doc_comment {
    ($x:expr, $($tt:tt)*) => {
        $x
        $($tt)*
    };
}

struct Foo;

impl Foo {
    doc_comment! {
        concat!("/// ", "something else", stringify!(u32)),
        fn foo() {}
    }
}

fn main() {
}

To the adventurous ones: good luck! For the others, here's the solution with #[doc]:

Runmacro_rules! doc_comment {
    ($x:expr, $($tt:tt)*) => {
        #[doc = $x]
        $($tt)*
    };
}

struct Foo;

impl Foo {
    doc_comment! {
        concat!("something else", stringify!(u32)),
        fn foo() {}
    }
}

fn main() {
}

Magical! The advantage of $($tt:tt)* is that it works with basically every kind of items you might want to put:

Rundoc_comment! {
    concat!("something else", stringify!(u32)),
    #[doc = "why not another doc comment?"]
    #[inline]
    fn foo() {}
}

Again, it's been possible thanks to @antoyo's huge help!

Posted on the 19/02/2018 at 22:00