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