1 /// A macro for defining #[cfg] if-else statements. 2 /// 3 /// This is similar to the `if/elif` C preprocessor macro by allowing definition 4 /// of a cascade of `#[cfg]` cases, emitting the implementation which matches 5 /// 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 macro_rules! cfg_if { 10 // match if/else chains with a final `else` 11 ($( 12 if #[cfg($($meta:meta),*)] { $($it:item)* } 13 ) else * else { 14 $($it2:item)* 15 }) => { 16 cfg_if! { 17 @__items 18 () ; 19 $( ( ($($meta),*) ($($it)*) ), )* 20 ( () ($($it2)*) ), 21 } 22 }; 23 24 // match if/else chains lacking a final `else` 25 ( 26 if #[cfg($($i_met:meta),*)] { $($i_it:item)* } 27 $( 28 else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } 29 )* 30 ) => { 31 cfg_if! { 32 @__items 33 () ; 34 ( ($($i_met),*) ($($i_it)*) ), 35 $( ( ($($e_met),*) ($($e_it)*) ), )* 36 ( () () ), 37 } 38 }; 39 40 // Internal and recursive macro to emit all the items 41 // 42 // Collects all the negated `cfg`s in a list at the beginning and after the 43 // semicolon is all the remaining items 44 (@__items ($($not:meta,)*) ; ) => {}; 45 (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), 46 $($rest:tt)*) => { 47 // Emit all items within one block, applying an appropriate #[cfg]. The 48 // #[cfg] will require all `$m` matchers specified and must also negate 49 // all previous matchers. 50 cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } 51 52 // Recurse to emit all other items in `$rest`, and when we do so add all 53 // our `$m` matchers to the list of `$not` matchers as future emissions 54 // will have to negate everything we just matched as well. 55 cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } 56 }; 57 58 // Internal macro to Apply a cfg attribute to a list of items 59 (@__apply $m:meta, $($it:item)*) => { 60 $(#[$m] $it)* 61 }; 62 } 63 64 /// Implement `Clone` and `Copy` for a struct, as well as `Debug`, `Eq`, `Hash`, and 65 /// `PartialEq` if the `extra_traits` feature is enabled. 66 /// 67 /// Use [`s_no_extra_traits`] for structs where the `extra_traits` feature does not 68 /// make sense, and for unions. 69 macro_rules! s { 70 ($( 71 $(#[$attr:meta])* 72 pub $t:ident $i:ident { $($field:tt)* } 73 )*) => ($( 74 s!(it: $(#[$attr])* pub $t $i { $($field)* }); 75 )*); 76 77 (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => ( 78 compile_error!("unions cannot derive extra traits, use s_no_extra_traits instead"); 79 ); 80 81 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( 82 __item! { 83 #[repr(C)] 84 #[cfg_attr(feature = "extra_traits", derive(Debug, Eq, Hash, PartialEq))] 85 #[derive(Copy, Clone)] 86 #[allow(deprecated)] 87 $(#[$attr])* 88 pub struct $i { $($field)* } 89 } 90 ); 91 } 92 93 /// Implement `Clone` and `Copy` for a tuple struct, as well as `Debug`, `Eq`, `Hash`, 94 /// and `PartialEq` if the `extra_traits` feature is enabled. 95 /// 96 /// This is the same as [`s`] but works for tuple structs. 97 macro_rules! s_paren { 98 ($( 99 $(#[$attr:meta])* 100 pub struct $i:ident ( $($field:tt)* ); 101 )*) => ($( 102 __item! { 103 #[cfg_attr(feature = "extra_traits", derive(Debug, Eq, Hash, PartialEq))] 104 #[derive(Copy, Clone)] 105 $(#[$attr])* 106 pub struct $i ( $($field)* ); 107 } 108 )*); 109 } 110 111 /// Implement `Clone` and `Copy` for a struct with no `extra_traits` feature. 112 /// 113 /// Most items will prefer to use [`s`]. 114 macro_rules! s_no_extra_traits { 115 ($( 116 $(#[$attr:meta])* 117 pub $t:ident $i:ident { $($field:tt)* } 118 )*) => ($( 119 s_no_extra_traits!(it: $(#[$attr])* pub $t $i { $($field)* }); 120 )*); 121 122 (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => ( 123 __item! { 124 #[repr(C)] 125 #[derive(Copy, Clone)] 126 $(#[$attr])* 127 pub union $i { $($field)* } 128 } 129 ); 130 131 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( 132 __item! { 133 #[repr(C)] 134 #[derive(Copy, Clone)] 135 $(#[$attr])* 136 pub struct $i { $($field)* } 137 } 138 ); 139 } 140 141 /// Specify that an enum should have no traits that aren't specified in the macro 142 /// invocation, i.e. no `Clone` or `Copy`. 143 macro_rules! missing { 144 ($( 145 $(#[$attr:meta])* 146 pub enum $i:ident {} 147 )*) => ($( 148 $(#[$attr])* 149 #[allow(missing_copy_implementations)] 150 pub enum $i { } 151 )*); 152 } 153 154 /// Implement `Clone` and `Copy` for an enum, as well as `Debug`, `Eq`, `Hash`, and 155 /// `PartialEq` if the `extra_traits` feature is enabled. 156 macro_rules! e { 157 ($( 158 $(#[$attr:meta])* 159 pub enum $i:ident { $($field:tt)* } 160 )*) => ($( 161 __item! { 162 #[cfg_attr(feature = "extra_traits", derive(Debug, Eq, Hash, PartialEq))] 163 #[derive(Copy, Clone)] 164 $(#[$attr])* 165 pub enum $i { $($field)* } 166 } 167 )*); 168 } 169 170 // This is a pretty horrible hack to allow us to conditionally mark 171 // some functions as 'const', without requiring users of this macro 172 // to care about the "const-extern-fn" feature. 173 // 174 // When 'const-extern-fn' is enabled, we emit the captured 'const' keyword 175 // in the expanded function. 176 // 177 // When 'const-extern-fn' is disabled, we always emit a plain 'pub unsafe extern fn'. 178 // Note that the expression matched by the macro is exactly the same - this allows 179 // users of this macro to work whether or not 'const-extern-fn' is enabled 180 // 181 // Unfortunately, we need to duplicate most of this macro between the 'cfg_if' blocks. 182 // This is because 'const unsafe extern fn' won't even parse on older compilers, 183 // so we need to avoid emitting it at all of 'const-extern-fn'. 184 // 185 // Specifically, moving the 'cfg_if' into the macro body will *not* work. 186 // Doing so would cause the '#[cfg(feature = "const-extern-fn")]' to be emitted 187 // into user code. The 'cfg' gate will not stop Rust from trying to parse the 188 // 'pub const unsafe extern fn', so users would get a compiler error even when 189 // the 'const-extern-fn' feature is disabled 190 // 191 // Note that users of this macro need to place 'const' in a weird position 192 // (after the closing ')' for the arguments, but before the return type). 193 // This was the only way I could satisfy the following two requirements: 194 // 1. Avoid ambiguity errors from 'macro_rules!' (which happen when writing '$foo:ident fn' 195 // 2. Allow users of this macro to mix 'pub fn foo' and 'pub const fn bar' within the same 196 // 'f!' block 197 198 // FIXME(ctest): ctest can't handle `const extern` functions, we should be able to remove this 199 // cfg completely. 200 cfg_if! { 201 if #[cfg(feature = "const-extern-fn")] { 202 /// Define an `unsafe` function that is const as long as `const-extern-fn` is enabled. 203 macro_rules! f { 204 ($( 205 $(#[$attr:meta])* 206 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty 207 $body:block 208 )*) => ($( 209 #[inline] 210 $(#[$attr])* 211 pub $($constness)* unsafe extern fn $i($($arg: $argty),*) -> $ret 212 $body 213 )*) 214 } 215 216 /// Define a safe function that is const as long as `const-extern-fn` is enabled. 217 macro_rules! safe_f { 218 ($( 219 $(#[$attr:meta])* 220 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty 221 $body:block 222 )*) => ($( 223 #[inline] 224 $(#[$attr])* 225 pub $($constness)* extern fn $i($($arg: $argty),*) -> $ret 226 $body 227 )*) 228 } 229 230 /// A nonpublic function that is const as long as `const-extern-fn` is enabled. 231 macro_rules! const_fn { 232 ($( 233 $(#[$attr:meta])* 234 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty 235 $body:block 236 )*) => ($( 237 #[inline] 238 $(#[$attr])* 239 $($constness)* fn $i($($arg: $argty),*) -> $ret 240 $body 241 )*) 242 } 243 } else { 244 /// Define an `unsafe` function that is const as long as `const-extern-fn` is enabled. 245 macro_rules! f { 246 ($( 247 $(#[$attr:meta])* 248 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty 249 $body:block 250 )*) => ($( 251 #[inline] 252 $(#[$attr])* 253 pub unsafe extern fn $i($($arg: $argty),*) -> $ret 254 $body 255 )*) 256 } 257 258 /// Define a safe function that is const as long as `const-extern-fn` is enabled. 259 macro_rules! safe_f { 260 ($( 261 $(#[$attr:meta])* 262 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty 263 $body:block 264 )*) => ($( 265 #[inline] 266 $(#[$attr])* 267 pub extern fn $i($($arg: $argty),*) -> $ret 268 $body 269 )*) 270 } 271 272 /// A nonpublic function that is const as long as `const-extern-fn` is enabled. 273 macro_rules! const_fn { 274 ($( 275 $(#[$attr:meta])* 276 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty 277 $body:block 278 )*) => ($( 279 #[inline] 280 $(#[$attr])* 281 fn $i($($arg: $argty),*) -> $ret 282 $body 283 )*) 284 } 285 } 286 } 287 288 macro_rules! __item { 289 ($i:item) => { 290 $i 291 }; 292 } 293 294 // This macro is used to deprecate items that should be accessed via the mach2 crate 295 macro_rules! deprecated_mach { 296 (pub const $id:ident: $ty:ty = $expr:expr;) => { 297 #[deprecated( 298 since = "0.2.55", 299 note = "Use the `mach2` crate instead", 300 )] 301 #[allow(deprecated)] 302 pub const $id: $ty = $expr; 303 }; 304 ($(pub const $id:ident: $ty:ty = $expr:expr;)*) => { 305 $( 306 deprecated_mach!( 307 pub const $id: $ty = $expr; 308 ); 309 )* 310 }; 311 (pub type $id:ident = $ty:ty;) => { 312 #[deprecated( 313 since = "0.2.55", 314 note = "Use the `mach2` crate instead", 315 )] 316 #[allow(deprecated)] 317 pub type $id = $ty; 318 }; 319 ($(pub type $id:ident = $ty:ty;)*) => { 320 $( 321 deprecated_mach!( 322 pub type $id = $ty; 323 ); 324 )* 325 } 326 } 327