Generating documentation in macros
Asked Answered
K

2

49

I have a couple of macros to reduce boilerplate when defining certain tuple-structs of the form:

macro_rules! new_type (($name:ident, $bytes:expr) => (
    pub struct $name(pub [u8; $bytes]);
    // some common operations on $name
));

However, I would also like to document these new structs. The best thing would be if I could write my documentation right before my macro invocation.

/// A certain type
new_type!(CertainType, 42);

However, Rust won't generate documentation for CertainType when this happens.

Another (not as flexible) alternative would be to do something like:

macro_rules! new_type (($name:ident, $bytes:expr) => (
    /// Some more generic documentation for $name 
    pub struct $name(pub [u8; $bytes]);
    // some common operations on $name
));

However, when doing that the Rust macro system doesn't expand the token $name in the documentation comment. The only alternative left is to write very generic documentation in the macro, but that would lead to my library being a lot worse documented than it could be.

What are your recommendations for handling this? The best solution for me would be to be able to write specific documentation for each macro invocation, but if that's not possible I would be grateful for hints on how to expand tokens in documentation comments.

Kostman answered 30/11, 2015 at 13:4 Comment(2)
generated documentation has no informational value, because it is generated. make a section in your documentation that describes the pattern, but don't bloat your documentation.Hairdresser
@arn This is not strictly the case. The comments may be coming from a different source, like a COM TypeLib. In other words: They can be authored by humans but still need to be written by a tool.Lovel
K
74

It is possible to capture doc comments in macro invocations. It is not widely-known, but Rust documentation is actually represented as a special kind of attribute on an item. For example:

/// Some documentation comment
pub fn function() {}

// is equivalent to

#[doc="Some documentation comment"]
pub fn function() {}

And it is possible to capture attributes in macros. There are already several macros which use this ability, the most used probably being bitflags!:

macro_rules! bitflags {
    (
        $(#[$outer:meta])*
        pub struct $BitFlags:ident: $T:ty {
            $(
                $(#[$inner:ident $($args:tt)*])*
                const $Flag:ident = $value:expr;
            )+
        }
    ) => { /* ... */ };
    // ...
}

Note the $(#[$outer:meta])* and $(#[$inner:meta])* parts of the pattern. These capture all attributes placed before the respective item in the pattern. If you write a doc comment there, it will be converted to the doc attribute and will be passed to rustdoc, as usual.

The following is an example from the quick_error crate which also uses this approach:

quick_error! {
    #[derive(Debug)]
    pub enum SomeError {
        /// IO Error
        Io(err: io::Error) {}
        /// Arbitrary system error
        Sys(errno: nix::Errno) {}
    }
}

It does work — here is an example of the structure generated by quick_error macro, and here is its definition.

Klenk answered 30/11, 2015 at 13:20 Comment(3)
Thanks. That solves my problem. I knew that doc-comments were translated to attributes, but I didn't realize that I could match on them in the macro definition.Kostman
The example's definition link is broken -- can we get it fixed?Guglielmo
@ErichGubler fixedKlenk
B
1

This worked for me:

macro_rules! make_my_fn {
    ($name:ident, $t:ty) => {
        #[doc = concat!("This is documentation for ", stringify!($name), ".
# Errors
  * Makes some Error when bad things happen
        ")]
        pub fn $name(&self) -> Result<$t, Error> {
          // do something to make result
          Ok(result)
        }
    };
}
Brainy answered 3/5 at 19:22 Comment(1)
Note that this was not working when this question was initially asked (but it works now).Aborn

© 2022 - 2024 — McMap. All rights reserved.