#cfg #exclusive #proc-macro #features

macro cfg-exclusive

A procedural macro for defining mutually exclusive cfg attributes

1 unstable release

0.0.1 Jun 20, 2024

#16 in #exclusive

MIT/Apache

8KB
61 lines

cfg-feature

Rust Version crates.io Documentation Dependency Status

A procedural macro for ensuring that only one of a set of features is enabled at a time.

Typically, features should be additive. However, there are times when this is not possible or desired.

For such cases, if the number of features is small, or does not change/evolve frequently some verbose #[cfg] attributes may suffice.

The Problem

For example imagine a fictional crate which should only be build with one of the features feat1 or feat2.

One could create a build script such as the one at build.rs.

fn main() {
    #[cfg(all(feature = "feat1", feature = "feat2"))]
    compile_error!("Only one of the features can be enabled at a time");
}

Now imagine, we add a feat3.

Our build.rs changes to:

fn main() {
    #[cfg(any(
        all(feature = "feat1", any(feature = "feat2", feature = "feat3")),
        all(feature = "feat2", any(feature = "feat1", feature = "feat3")),
        all(feature = "feat3", any(feature = "feat1", feature = "feat2")),
    ))]
    compile_error!("Only one of the features can be enabled at a time");
}

Adding a fourth feat4 jumps to 12 combinations!

fn main() {
    #[cfg(any(
        all(feature = "feat1", any(feature = "feat2", feature = "feat3", feature = "feat4")),
        all(feature = "feat2", any(feature = "feat1", feature = "feat3", feature = "feat4")),
        all(feature = "feat3", any(feature = "feat1", feature = "feat2", feature = "feat4")),
        all(feature = "feat4", any(feature = "feat1", feature = "feat2", feature = "feat3")),
    ))]
    compile_error!("Only one of the features can be enabled at a time");
}

This gets out of hand quickly.

The Solution

Starting of with two features, the cfg-exclusive procedural macro can be used to simplify the build.rs script.

cfg_exclusive::cfg_exclusive! {
    validate_feats,
    ["feat1", "feat2"],
    "Only one of the features can be enabled at a time"
}

fn main() {
    validate_feats();
}

If that changes to three features:

-    ["feat1", "feat2"],
+    ["feat1", "feat2", "feat3"],

Or four:

-    ["feat1", "feat2", "feat3"],
+    ["feat1", "feat2", "feat3", "feat4"],

License

This crate is licensed under either of

at your option.

Contribution

Unless you explicitly note otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~240–690KB
~16K SLoC