@@ -119,3 +119,84 @@ macro_rules! impl_fn_for_zst {
119119 ) +
120120 }
121121}
122+
123+ /// A macro for defining `#[cfg]` if-else statements.
124+ ///
125+ /// The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C
126+ /// preprocessor macro by allowing definition of a cascade of `#[cfg]` cases,
127+ /// emitting the implementation which matches first.
128+ ///
129+ /// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
130+ /// without having to rewrite each clause multiple times.
131+ ///
132+ /// # Example
133+ ///
134+ /// ```
135+ /// #[macro_use]
136+ /// extern crate cfg_if;
137+ ///
138+ /// cfg_if! {
139+ /// if #[cfg(unix)] {
140+ /// fn foo() { /* unix specific functionality */ }
141+ /// } else if #[cfg(target_pointer_width = "32")] {
142+ /// fn foo() { /* non-unix, 32-bit functionality */ }
143+ /// } else {
144+ /// fn foo() { /* fallback implementation */ }
145+ /// }
146+ /// }
147+ ///
148+ /// # fn main() {}
149+ /// ```
150+ macro_rules! cfg_if {
151+ // match if/else chains with a final `else`
152+ ( $(
153+ if #[ cfg( $( $meta: meta) ,* ) ] { $( $it: item) * }
154+ ) else * else {
155+ $( $it2: item) *
156+ } ) => {
157+ cfg_if! {
158+ @__items
159+ ( ) ;
160+ $( ( ( $( $meta) ,* ) ( $( $it) * ) ) , ) *
161+ ( ( ) ( $( $it2) * ) ) ,
162+ }
163+ } ;
164+
165+ // match if/else chains lacking a final `else`
166+ (
167+ if #[ cfg( $( $i_met: meta) ,* ) ] { $( $i_it: item) * }
168+ $(
169+ else if #[ cfg( $( $e_met: meta) ,* ) ] { $( $e_it: item) * }
170+ ) *
171+ ) => {
172+ cfg_if! {
173+ @__items
174+ ( ) ;
175+ ( ( $( $i_met) ,* ) ( $( $i_it) * ) ) ,
176+ $( ( ( $( $e_met) ,* ) ( $( $e_it) * ) ) , ) *
177+ ( ( ) ( ) ) ,
178+ }
179+ } ;
180+
181+ // Internal and recursive macro to emit all the items
182+ //
183+ // Collects all the negated cfgs in a list at the beginning and after the
184+ // semicolon is all the remaining items
185+ ( @__items ( $( $not: meta, ) * ) ; ) => { } ;
186+ ( @__items ( $( $not: meta, ) * ) ; ( ( $( $m: meta) ,* ) ( $( $it: item) * ) ) , $( $rest: tt) * ) => {
187+ // Emit all items within one block, applying an approprate #[cfg]. The
188+ // #[cfg] will require all `$m` matchers specified and must also negate
189+ // all previous matchers.
190+ cfg_if! { @__apply cfg( all( $( $m, ) * not( any( $( $not) ,* ) ) ) ) , $( $it) * }
191+
192+ // Recurse to emit all other items in `$rest`, and when we do so add all
193+ // our `$m` matchers to the list of `$not` matchers as future emissions
194+ // will have to negate everything we just matched as well.
195+ cfg_if! { @__items ( $( $not, ) * $( $m, ) * ) ; $( $rest) * }
196+ } ;
197+
198+ // Internal macro to Apply a cfg attribute to a list of items
199+ ( @__apply $m: meta, $( $it: item) * ) => {
200+ $( #[ $m] $it) *
201+ } ;
202+ }
0 commit comments