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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With