osi/cfg.rs
1//! # Configuration Flag Utilities
2//!
3//! This module provides utilities to help dealing with configuration flags as
4//! usually used in `#[cfg()]` or [`core::cfg!()`].
5
6#[doc(hidden)]
7#[macro_export]
8macro_rules! crate_cfg_cond {
9 // Helper to expand the argument in the current context.
10 (@expand(
11 $($v:tt)*
12 )) => { $($v)* };
13
14 // Termination of the recursive macro.
15 (@internal(
16 ($(($acc:meta),)*),
17 )) => {};
18
19 // Recursive macro that expands each block prefixed with a cfg-condition
20 // plus a negated condition of all preceding items. It recurses by adding
21 // the condition to the accumulator and proceeding with the next item.
22 (@internal(
23 ($(($acc:meta),)*),
24 (($($cond:meta)?), ($($v:tt)*)),
25 $($rem:tt,)*
26 )) => {
27 #[cfg(all(
28 $($cond,)?
29 not(any($($acc,)*)),
30 ))]
31 $crate::crate_cfg_cond! { @expand($($v)*) }
32
33 $crate::crate_cfg_cond! {
34 @internal(
35 ($(($acc),)* $(($cond),)?),
36 $($rem,)*
37 )
38 }
39 };
40
41 // Take a list of condition+block, plus optionally a terminating
42 // block and produce the related cfg-conditions.
43 (
44 $(
45 ($cond:meta) { $($v:tt)* },
46 )+
47 $(
48 { $($else:tt)* },
49 )?
50 ) => {
51 $crate::crate_cfg_cond! {
52 @internal(
53 (),
54 $(
55 (($cond), ($($v)*)),
56 )+
57 $(
58 ((), ($($else)*)),
59 )?
60 )
61 }
62 };
63}
64
65/// Turn a list of cascading conditions with associated blocks into a list of
66/// blocks with corresponding `#[cfg(...)]` conditions.
67///
68/// This macro allows writing statements similar in style to
69/// `if-{}-else-if-{}-[...]-else-{}` statements with `cfg(...)` conditions,
70/// and then turning them into the correct coalesced `#[cfg(...)]` blocks.
71///
72/// Note that this macro cannot produce expressions, and is not valid in
73/// expression context. Use [`core::cfg!()`] from the standard library for that
74/// purpose.
75pub use crate_cfg_cond as cond;
76
77#[cfg(test)]
78mod test {
79 use super::*;
80
81 cond! {
82 (test) {
83 const V0: bool = true;
84 },
85 }
86
87 cond! {
88 (test) {
89 const V1: bool = true;
90 },
91 {
92 const V1: bool = false;
93 },
94 }
95
96 cond! {
97 (not(test)) {
98 const V2: bool = false;
99 },
100 {
101 const V2: bool = true;
102 },
103 }
104
105 cond! {
106 (not(test)) {
107 const V3: bool = false;
108 },
109 (test) {
110 const V3: bool = true;
111 },
112 (any(not(test), not(test))) {
113 const V3: bool = false;
114 },
115 }
116
117 cond! {
118 (not(test)) {
119 const V4: bool = false;
120 },
121 (any(not(test), not(test))) {
122 const V4: bool = false;
123 },
124 (any(test, not(test))) {
125 const V4: bool = true;
126 },
127 }
128
129 cond! {
130 (not(test)) {
131 const V5: bool = false;
132 },
133 (any(test, not(test))) {
134 const V5: bool = true;
135 },
136 (not(test)) {
137 const V5: bool = false;
138 },
139 {
140 const V5: bool = false;
141 },
142 }
143
144 cond! {
145 (not(test)) {
146 const V6: bool = false;
147 },
148 (any(not(test), not(test))) {
149 const V6: bool = false;
150 },
151 (any(not(test))) {
152 const V6: bool = false;
153 },
154 {
155 const V6: bool = true;
156 },
157 }
158
159 #[test]
160 fn basic_cond() {
161 assert!(V0);
162 assert!(V1);
163 assert!(V2);
164 assert!(V3);
165 assert!(V4);
166 assert!(V5);
167 assert!(V6);
168 }
169}