wasefire_one_of/
lib.rs

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Provides macros to check mutually exclusive features.
16
17#![no_std]
18
19/// Makes sure exactly one of the provided feature is enabled.
20///
21/// For example, `exactly_one_of!["a", "b", "c"]` will expand to:
22///
23/// ```ignore
24/// #[cfg(any(
25///     not(any(feature = "a", feature = "b", feature = "c")),
26///     all(feature = "a", feature = "b"),
27///     all(feature = "a", feature = "c"),
28///     all(feature = "b", feature = "c"),
29/// ))]
30/// compile_error!("Exactly one of feature \"a\", \"b\", or \"c\" can be enabled.");
31/// ```
32#[macro_export]
33macro_rules! exactly_one_of {
34    ($f:literal, $($fs:literal),+$(,)?) => {
35        $crate::internal_one_of!(0 [$f $($fs)*] "Exactly");
36    };
37}
38
39/// Makes sure at most one of the provided feature is enabled.
40///
41/// For example, `at_most_one_of!["a", "b", "c"]` will expand to:
42///
43/// ```ignore
44/// #[cfg(any(
45///     all(feature = "a", feature = "b"),
46///     all(feature = "a", feature = "c"),
47///     all(feature = "b", feature = "c"),
48/// ))]
49/// compile_error!("At most one of feature \"a\", \"b\", or \"c\" can be enabled.");
50/// ```
51#[macro_export]
52macro_rules! at_most_one_of {
53    ($f:literal, $($fs:literal),+$(,)?) => {
54        $crate::internal_one_of!(1 [$f $($fs)*] () ["At most";]);
55    };
56}
57
58#[doc(hidden)]
59#[macro_export]
60macro_rules! internal_one_of {
61    (0 [$($f:literal)*] $p:literal) => {
62        $crate::internal_one_of!(1 [$($f)*] (not(any($(feature = $f),*)),) [$p;]);
63    };
64
65    (1 [$f:literal $($fs:literal)*] $r:tt [$($ds:literal)*; $($d:literal)?]) => {
66        $crate::internal_one_of!(2 [$($fs)*] $f [$($fs)*] $r [$($ds)* $($d)?; $f]);
67    };
68    (1 [] $r:tt $ds:tt) => {
69        #[cfg(any $r)]
70        $crate::internal_one_of!(3 $ds);
71    };
72
73    (2 $s:tt $g:literal [$f:literal $($fs:literal)*] ($($r:tt)*) $d:tt) => {
74        $crate::internal_one_of!(2 $s $g [$($fs)*] ($($r)* all(feature = $g, feature = $f),) $d);
75    };
76    (2 $s:tt $g:literal [] $r:tt $d:tt) => {
77        $crate::internal_one_of!(1 $s $r $d);
78    };
79
80    (3 [$p:literal $a:literal; $b:literal]) => {
81        compile_error!(concat!($p, " one of feature ", stringify!($a), " or ", stringify!($b),
82          " can be enabled."));
83    };
84    (3 [$p:literal $($as:literal)*; $b:literal]) => {
85        compile_error!(concat!($p, " one of feature ",$(stringify!($as), ", ",)* "or ",
86          stringify!($b), " can be enabled."));
87    };
88}