DRY для условной компиляции Rust с функциями - PullRequest
2 голосов
/ 12 июля 2020

В моей библиотеке есть несколько функций, например, F1, F2, F3, F4, .. и только одна из них может быть активной одновременно. Эти функции далее классифицируются как типы A, B, C, поэтому, например, функции F1 и F2 относятся к типу A, F3, F4 относятся к типу * 1013. * и т. д.

У меня есть несколько вхождений такого кода (в библиотеке)

#[cfg(any(feature = "F1", feature = "F2"))]
fn do_onething_for_type_A(... ) {
// repeating same cfg predicate as above
#[cfg(any(feature = "F1", feature = "F2"))]
fn do_another_thing_for_type_A(... ) {
#[cfg(any(feature = "F3", feature = "F4"))]
fn do_onething_for_type_B(... ) {

Есть ли способ записать указанные выше cfg предикаты кратко, чтобы мне не приходилось упоминать каждую функцию в #[cfg(any(.. каждый раз, когда у меня возникает это условие? Многословие - не единственная проблема. Каждый раз, когда я представляю новую функцию, скажем F5, которая имеет тип, скажем, A, мне приходится обновлять вхождения строки #[cfg(any(feature = "F1", feature = "F2"))] на #[cfg(any(feature = "F1", feature = "F2", feature = "F5"))].

Моя первая мысль была создайте атрибут на основе функции, а затем используйте атрибут, как показано ниже, но, похоже, я не могу этого сделать.

#[cfg(any(feature = "F1", feature = "F2"), typeA)]
#[cfg(any(feature = "F3", feature = "F4"), typeB)]

#[typeA]
fn do_onething_for_type_A(... ) {...}

#[typeA]
fn do_another_thing_for_type_A(... ) {

#[typeB]
fn do_onething_for_type_B(... ) {

Объявление новой функции для типов A, B, C - мое последнее средство.

1 Ответ

2 голосов
/ 19 июля 2020

Вы можете использовать ящик cfg_aliases, хотя для этого потребуется добавить скрипт сборки.

// Cargo.toml
[build-dependencies]
cfg_aliases = "0.1.0"
// build.rs
use cfg_aliases::cfg_aliases;

fn main() {
    // Setup cfg aliases
    cfg_aliases! {
        type_a: { any(feature = "F1", feature = "F2") },
        type_b: { any(feature = "F3", feature = "F4") },
        type_c: { feature = "F5" },
    }
}
#[cfg(type_a)]
fn do_onething_for_type_A(... ) {...}

#[cfg(type_a)]
fn do_another_thing_for_type_A(... ) {

#[cfg(type_b)]
fn do_onething_for_type_B(... ) {

В качестве альтернативы вы можете определить макросы как Tokio делает .

macro_rules! cfg_type_a {
    ($($item:item)*) => {
        $(
            #[cfg(any(feature = "F1", feature = "F2"))]
            $item
        )*
    }
}
cfg_type_a! {
    fn do_onething_for_type_A() {
        ...
    }
}
cfg_type_b! {
    fn do_onething_for_type_B() {
        ...
    }
}

Обратите внимание, что подход, основанный на макросах, может вызвать проблемы для любого из пользователей библиотеки, использующих CLion IDE. При использовании этой IDE необходимо включить

Настройки> Языки и рамки> Rust> Расширить декларативные макросы: используйте экспериментальный движок

, чтобы получить завершение типов для вещей, определенных за макросы, такие как выше.

...