Генерация документации в макросах

У меня есть пара макросов, чтобы уменьшить шаблон при определении определенных структур кортежа формы:

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

Однако я также хотел бы задокументировать эти новые структуры. Лучше всего было бы, если бы я мог написать свою документацию прямо перед вызовом макроса.

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

Однако Rust не будет генерировать документацию для CertainType когда это произойдет.

Другой (не такой гибкой) альтернативой было бы сделать что-то вроде:

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
));

Однако при этом макрос-система Rust не расширяет токен $name в комментарии к документации. Единственная альтернатива - написать очень общую документацию в макросе, но это приведет к тому, что моя библиотека будет документирована намного хуже, чем могла бы быть.

Каковы ваши рекомендации по обращению с этим? Лучшее решение для меня - написать конкретную документацию для каждого вызова макроса, но если это невозможно, я буду благодарен за подсказки о том, как расширить токены в комментариях к документации.

1 ответ

Решение

Возможно захватить комментарии документа в вызовах макроса. Он не очень широко известен, но документация Rust фактически представляется как особый вид атрибута для элемента. Например:

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

// is equivalent to

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

И можно захватывать атрибуты в макросах. Уже есть несколько макросов, которые используют эту способность, наиболее часто используемым bitflags!:

macro_rules! bitflags {
    ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
        $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+
    }) =>
    ...
}

Обратите внимание $(#[$attr:meta])* часть шаблона. Он захватывает все атрибуты, помещенные перед соответствующим элементом в шаблоне. Если вы напишете там комментарий к документу, он будет фактически преобразован в атрибут документа и будет передан rustdoc, как обычно. Ниже приведен пример из quick_error ящик, который также использует этот подход:

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

и это работает - вот пример структуры, генерируемой quick_error макрос, и вот его определение.

Другие вопросы по тегам