Reputation: 5411
My library has several features, say F1
, F2
, F3
, F4
,.. and only one of them can be active at a time. These features are further classified as types A
, B
, C
, so for example, features F1
and F2
are of type A
, F3
, F4
are of type B
and so on.
I have several occurrences of such code (in the library)
#[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(... ) {
Is there a way to write the above cfg
predicates concisely so that I don't have to mention each feature in the #[cfg(any(..
every time I have that condition? Verbosity is not the only issue. Every time I introduce a new feature, say F5
which is of type, say, A
, I have to update the occurrences of line #[cfg(any(feature = "F1", feature = "F2"))]
to #[cfg(any(feature = "F1", feature = "F2", feature = "F5"))]
.
My first thought was to create an attribute based on the feature and then use the attribute as below but seems I can't do that.
#[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(... ) {
Declaring a new feature for types A
, B
, C
is my last resort.
Upvotes: 3
Views: 1293
Reputation: 4239
You could use the cfg_aliases
crate, although it requires adding a build script.
// 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(... ) {
Alternatively you can define macros like Tokio does.
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() {
...
}
}
Note that the macro-based approach can cause trouble for any of users of the library using the CLion IDE. When using that IDE, you have to enable
Settings > Languages & Frameworks > Rust > Expand declarative macros: Use experimental engine
to get type completion for things defined behind macros such as above.
Upvotes: 4