[go: up one dir, main page]

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}