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] 38 macro_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)] 82 mod 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] tests()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] it_works()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 } 172