Как условно изменить небольшую часть макроса Rust? - PullRequest
0 голосов
/ 27 октября 2018

Я строю ящик, который имеет функцию foo. В этом ящике есть макрос bar!, который делает немного разные вещи в зависимости от того, установлен ли foo.

Я мог бы продублировать весь макрос:

#[cfg(feature = "foo")]
macro_rules! bar {
    // Lots of rules...

    ( A ) => {
        B
    }
}

#[cfg(not(feature = "foo"))]
macro_rules! bar {
    // Lots of rules...

    ( A ) => {
        C
    }
}

Это много подверженных ошибкам дубликатов. Два подхода, которые не работают:

  • Мы не можем переместить cfg внутри макроса, потому что тогда он развернется в области видимости пользователя ящика, у которого нет соответствующей функции foo.

  • Мы не можем использовать вспомогательный макрос #[doc(hidden)] #[macro_export] macro_rules! bar_priv_impl__ и использовать #[cfg] в вспомогательном макросе начиная с Rust 1.30, поскольку теперь пользователи могут запрашивать use mycrate::bar; только для импорта макроса bar!, что приводит к ошибкам как bar_priv_impl__! не определено.

Есть ли способ лучше, чем полное дублирование макросов? Будет очень плохо, если у вас есть N функций, которые вы тестируете, так как вам нужно 2 n дубликатов.

1 Ответ

0 голосов
/ 27 октября 2018

начиная с Rust 1.30 [...], потому что пользователи теперь могут [...] импортировать только макрос bar!

На самом деле, это решение только возможно в Rust 1.30 из-за возможности импортировать макросы как обычно. Помните, что ваш макрос может также иметь use операторов !:

#[macro_export]
macro_rules! bar {
    ($val:expr) => {{
        use $crate::__bar_foo;
        __bar_foo!($val)
    }}
}

#[cfg(feature = "foo")]
#[macro_export]
macro_rules! __bar_foo {
    ($val:expr) => ($val + 1)
}

#[cfg(not(feature = "foo"))]
#[macro_export]
macro_rules! __bar_foo {
    ($val:expr) => ($val - 1)
}

Вы также можете полностью квалифицировать вызов вспомогательного макроса:

#[macro_export]
macro_rules! bar {
    ($val:expr) => ($crate::__bar_foo!($val))
}
...