cfg_if_edc/
lib.rs

1//! A macro for defining `#[cfg]` if-else statements.
2//!
3//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C
4//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases,
5//! emitting the implementation which matches first.
6//!
7//! This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
8//! without having to rewrite each clause multiple times.
9//!
10//! # Example
11//!
12//! ```
13//! cfg_if::cfg_if! {
14//!     if #[cfg(unix)] {
15//!         fn foo() { /* unix specific functionality */ }
16//!     } else if #[cfg(target_pointer_width = "32")] {
17//!         fn foo() { /* non-unix, 32-bit functionality */ }
18//!     } else {
19//!         fn foo() { /* fallback implementation */ }
20//!     }
21//! }
22//!
23//! # fn main() {}
24//! ```
25
26#![no_std]
27#![doc(html_root_url = "https://docs.rs/cfg-if")]
28#![deny(missing_docs)]
29#![cfg_attr(test, deny(warnings))]
30
31/// The main macro provided by this crate. See crate documentation for more
32/// information.
33#[macro_export]
34macro_rules! cfg_if {
35    // match if/else chains with a final `else`
36    (
37        $(
38            if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
39        ) else+
40        else { $( $e_tokens:tt )* }
41    ) => {
42        $crate::cfg_if! {
43            @__items () ;
44            $(
45                (( $i_meta ) ( $( $i_tokens )* )) ,
46            )+
47            (() ( $( $e_tokens )* )) ,
48        }
49    };
50
51    // match if/else chains lacking a final `else`
52    (
53        if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
54        $(
55            else if #[cfg( $e_meta:meta )] { $( $e_tokens:tt )* }
56        )*
57    ) => {
58        $crate::cfg_if! {
59            @__items () ;
60            (( $i_meta ) ( $( $i_tokens )* )) ,
61            $(
62                (( $e_meta ) ( $( $e_tokens )* )) ,
63            )*
64        }
65    };
66
67    // Internal and recursive macro to emit all the items
68    //
69    // Collects all the previous cfgs in a list at the beginning, so they can be
70    // negated. After the semicolon is all the remaining items.
71    (@__items ( $( $_:meta , )* ) ; ) => {};
72    (
73        @__items ( $( $no:meta , )* ) ;
74        (( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
75        $( $rest:tt , )*
76    ) => {
77        // Emit all items within one block, applying an appropriate #[cfg]. The
78        // #[cfg] will require all `$yes` matchers specified and must also negate
79        // all previous matchers.
80        #[cfg(all(
81            $( $yes , )?
82            not(any( $( $no ),* ))
83        ))]
84        $crate::cfg_if! { @__identity $( $tokens )* }
85
86        // Recurse to emit all other items in `$rest`, and when we do so add all
87        // our `$yes` matchers to the list of `$no` matchers as future emissions
88        // will have to negate everything we just matched as well.
89        $crate::cfg_if! {
90            @__items ( $( $no , )* $( $yes , )? ) ;
91            $( $rest , )*
92        }
93    };
94
95    // Internal macro to make __apply work out right for different match types,
96    // because of how macros match/expand stuff.
97    (@__identity $( $tokens:tt )* ) => {
98        $( $tokens )*
99    };
100}
101
102#[cfg(test)]
103mod tests {
104    cfg_if! {
105        if #[cfg(test)] {
106            use core::option::Option as Option2;
107            fn works1() -> Option2<u32> { Some(1) }
108        } else {
109            fn works1() -> Option<u32> { None }
110        }
111    }
112
113    cfg_if! {
114        if #[cfg(foo)] {
115            fn works2() -> bool { false }
116        } else if #[cfg(test)] {
117            fn works2() -> bool { true }
118        } else {
119            fn works2() -> bool { false }
120        }
121    }
122
123    cfg_if! {
124        if #[cfg(foo)] {
125            fn works3() -> bool { false }
126        } else {
127            fn works3() -> bool { true }
128        }
129    }
130
131    cfg_if! {
132        if #[cfg(test)] {
133            use core::option::Option as Option3;
134            fn works4() -> Option3<u32> { Some(1) }
135        }
136    }
137
138    cfg_if! {
139        if #[cfg(foo)] {
140            fn works5() -> bool { false }
141        } else if #[cfg(test)] {
142            fn works5() -> bool { true }
143        }
144    }
145
146    #[test]
147    fn it_works() {
148        assert!(works1().is_some());
149        assert!(works2());
150        assert!(works3());
151        assert!(works4().is_some());
152        assert!(works5());
153    }
154
155    #[test]
156    #[allow(clippy::assertions_on_constants)]
157    fn test_usage_within_a_function() {
158        cfg_if! {if #[cfg(debug_assertions)] {
159            // we want to put more than one thing here to make sure that they
160            // all get configured properly.
161            assert!(cfg!(debug_assertions));
162            assert_eq!(4, 2+2);
163        } else {
164            assert!(works1().is_some());
165            assert_eq!(10, 5+5);
166        }}
167    }
168
169    #[allow(dead_code)]
170    trait Trait {
171        fn blah(&self);
172    }
173
174    #[allow(dead_code)]
175    struct Struct;
176
177    impl Trait for Struct {
178        cfg_if! {
179            if #[cfg(feature = "blah")] {
180                fn blah(&self) {
181                    unimplemented!();
182                }
183            } else {
184                fn blah(&self) {
185                    unimplemented!();
186                }
187            }
188        }
189    }
190}