match_cfg/
lib.rs

1//! A convenience macro to ergonomically define an item depending on a large
2//! number of `#[cfg]` parameters. Structured like match statement, the first
3//! matching branch is the item that gets emitted.
4
5#![cfg_attr(not(feature = "use_core"), feature(no_core))]
6#![doc(html_root_url = "https://docs.rs/cfg-if")]
7#![cfg_attr(test, deny(warnings))]
8#![cfg_attr(not(feature = "use_core"), no_core)]
9#![cfg_attr(feature = "use_core", no_std)]
10
11/// The macro provided by this crate, `match_cfg`, is similar to the `if/elif` C
12/// preprocessor directives and allows defining a cascade of `#[cfg]` cases,
13/// emitting the implementation which matches first.
14///
15/// This conveniently allows providing a long list `#[cfg]`'d blocks of code
16/// without having to rewrite each `cfg()` clause multiple times.
17///
18/// # Example
19///
20/// ```
21/// #[macro_use(match_cfg)]
22/// extern crate match_cfg;
23///
24/// match_cfg! {
25///     #[cfg(unix)] => {
26///         fn foo() { /* unix specific functionality */ }
27///     }
28///     #[cfg(target_pointer_width = "32")] => {
29///         fn foo() { /* non-unix, 32-bit functionality */ }
30///     }
31///     _ => {
32///         fn foo() { /* fallback implementation */ }
33///     }
34/// }
35/// # fn main() {}
36/// ```
37#[macro_export]
38macro_rules! match_cfg {
39    (#[cfg($cfg:meta)] => { $($i:item)* }) => {
40        $(
41            #[cfg($cfg)] $i
42        )*
43    };
44    (#[cfg($cfg:meta)] @ #[cfg($cfg_not:meta)] => { $($i:item)* }) => {
45        $(
46            #[cfg(not($cfg_not))] #[cfg($cfg)] $i
47        )*
48    };
49    (_ => { $($i:item)* }) => { $( $i )* };
50    (_ @ #[cfg($cfg_not:meta)] => { $($i:item)* }) => {
51        $(
52            #[cfg(not($cfg_not))] $i
53        )*
54    };
55    (
56        #[cfg($cfg0:meta)] => { $($i:item)* }
57        $(#[cfg($cfgs:meta)] => { $($is:item)* })*
58    ) => {
59        match_cfg! {
60            #[cfg($cfg0)] => { $($i)* }
61        }
62        $(
63            match_cfg! {
64                #[cfg($cfgs)] @ #[cfg($cfg0)] => { $($is)* }
65            }
66        )*
67    };
68    (
69        $(#[cfg($cfgs:meta)] => { $($is:item)* })*
70        _ => { $($ni:item)* }
71    ) => {
72        match_cfg! {
73            $( #[cfg($cfgs)] => { $($is)* } )*
74        }
75        match_cfg! {
76            _ @ #[cfg(any($($cfgs),*))] => { $($ni)* }
77        }
78    };
79}
80
81#[cfg(test)]
82mod tests {
83    match_cfg! {
84        #[cfg(target_pointer_width = "64")] => { fn f0_() -> bool { true }}
85    }
86    match_cfg! {
87        #[cfg(unix)] => { fn f1_() -> bool { true }}
88        #[cfg(any(target_os = "macos", target_os = "linux"))] => { fn f1_() -> bool { false }}
89    }
90
91    match_cfg! {
92        #[cfg(target_pointer_width = "64")] => { fn f2_() -> bool { true }}
93        #[cfg(target_pointer_width = "32")] => { fn f2_() -> bool { false }}
94    }
95
96    match_cfg! {
97        #[cfg(target_pointer_width = "8")] => { fn f3_() -> i32 { 0 }}
98        #[cfg(target_pointer_width = "16")] => { fn f3_() -> i32 { 1 }}
99        _ => { fn f3_() -> i32 { 2 }}
100    }
101
102    #[test]
103    fn tests() {
104        #[cfg(target_pointer_width = "64")]
105        {
106            assert!(f0_());
107        }
108        #[cfg(unix)]
109        {
110            assert!(f1_());
111        }
112        assert!(f2_());
113        assert_eq!(f3_(), 2);
114    }
115
116    match_cfg! {
117        #[cfg(test)] => {
118            use core::option::Option as Option2;
119            fn works1() -> Option2<u32> { Some(1) }
120        }
121        _ => {
122            fn works1() -> Option<u32> { None }
123        }
124    }
125
126    match_cfg! {
127        #[cfg(foo)] => {
128            fn works2() -> bool { false }
129        }
130        #[cfg(test)] => {
131            fn works2() -> bool { true }
132        }
133        _ => {
134            fn works2() -> bool { false }
135        }
136    }
137
138    match_cfg! {
139        #[cfg(foo)] => {
140            fn works3() -> bool { false }
141        }
142        _ => {
143            fn works3() -> bool { true }
144        }
145    }
146
147    match_cfg! {
148        #[cfg(test)] => {
149            use core::option::Option as Option3;
150            fn works4() -> Option3<u32> { Some(1) }
151        }
152    }
153
154    match_cfg! {
155        #[cfg(foo)] => {
156            fn works5() -> bool { false }
157        }
158        #[cfg(test)] => {
159            fn works5() -> bool { true }
160        }
161    }
162
163    #[test]
164    fn it_works() {
165        assert!(works1().is_some());
166        assert!(works2());
167        assert!(works3());
168        assert!(works4().is_some());
169        assert!(works5());
170    }
171}