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 #[allow(deprecated)] 86 $(#[$attr])* 87 pub struct $i { $($field)* } 88 } 89 #[allow(deprecated)] 90 impl ::Copy for $i {} 91 #[allow(deprecated)] 92 impl ::Clone for $i { 93 fn clone(&self) -> $i { *self } 94 } 95 ); 96 } 97 98 /// Implement `Clone` and `Copy` for a tuple struct, as well as `Debug`, `Eq`, `Hash`, 99 /// and `PartialEq` if the `extra_traits` feature is enabled. 100 /// 101 /// This is the same as [`s`] but works for tuple structs. 102 macro_rules! s_paren { 103 ($( 104 $(#[$attr:meta])* 105 pub struct $i:ident ( $($field:tt)* ); 106 )* ) => ($( 107 __item! { 108 #[cfg_attr(feature = "extra_traits", derive(Debug, Eq, Hash, PartialEq))] 109 $(#[$attr])* 110 pub struct $i ( $($field)* ); 111 } 112 impl ::Copy for $i {} 113 impl ::Clone for $i { 114 fn clone(&self) -> $i { *self } 115 } 116 )*); 117 } 118 119 /// Implement `Clone` and `Copy` for a struct with no `extra_traits` feature. 120 /// 121 /// Most items will prefer to use [`s`]. 122 macro_rules! s_no_extra_traits { 123 ($( 124 $(#[$attr:meta])* 125 pub $t:ident $i:ident { $($field:tt)* } 126 )*) => ($( 127 s_no_extra_traits!(it: $(#[$attr])* pub $t $i { $($field)* }); 128 )*); 129 130 (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => ( 131 __item! { 132 #[repr(C)] 133 $(#[$attr])* 134 pub union $i { $($field)* } 135 } 136 137 impl ::Copy for $i {} 138 impl ::Clone for $i { 139 fn clone(&self) -> $i { *self } 140 } 141 ); 142 143 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( 144 __item! { 145 #[repr(C)] 146 $(#[$attr])* 147 pub struct $i { $($field)* } 148 } 149 #[allow(deprecated)] 150 impl ::Copy for $i {} 151 #[allow(deprecated)] 152 impl ::Clone for $i { 153 fn clone(&self) -> $i { *self } 154 } 155 ); 156 } 157 158 /// Specify that an enum should have no traits that aren't specified in the macro 159 /// invocation, i.e. no `Clone` or `Copy`. 160 macro_rules! missing { 161 ($( 162 $(#[$attr:meta])* 163 pub enum $i:ident {} 164 )*) => ($( 165 $(#[$attr])* 166 #[allow(missing_copy_implementations)] 167 pub enum $i { } 168 )*); 169 } 170 171 /// Implement `Clone` and `Copy` for an enum, as well as `Debug`, `Eq`, `Hash`, and 172 /// `PartialEq` if the `extra_traits` feature is enabled. 173 macro_rules! e { 174 ($( 175 $(#[$attr:meta])* 176 pub enum $i:ident { $($field:tt)* } 177 )*) => ($( 178 __item! { 179 #[cfg_attr(feature = "extra_traits", derive(Debug, Eq, Hash, PartialEq))] 180 $(#[$attr])* 181 pub enum $i { $($field)* } 182 } 183 impl ::Copy for $i {} 184 impl ::Clone for $i { 185 fn clone(&self) -> $i { *self } 186 } 187 )*); 188 } 189 190 // This is a pretty horrible hack to allow us to conditionally mark 191 // some functions as 'const', without requiring users of this macro 192 // to care about the "const-extern-fn" feature. 193 // 194 // When 'const-extern-fn' is enabled, we emit the captured 'const' keyword 195 // in the expanded function. 196 // 197 // When 'const-extern-fn' is disabled, we always emit a plain 'pub unsafe extern fn'. 198 // Note that the expression matched by the macro is exactly the same - this allows 199 // users of this macro to work whether or not 'const-extern-fn' is enabled 200 // 201 // Unfortunately, we need to duplicate most of this macro between the 'cfg_if' blocks. 202 // This is because 'const unsafe extern fn' won't even parse on older compilers, 203 // so we need to avoid emitting it at all of 'const-extern-fn'. 204 // 205 // Specifically, moving the 'cfg_if' into the macro body will *not* work. 206 // Doing so would cause the '#[cfg(feature = "const-extern-fn")]' to be emitted 207 // into user code. The 'cfg' gate will not stop Rust from trying to parse the 208 // 'pub const unsafe extern fn', so users would get a compiler error even when 209 // the 'const-extern-fn' feature is disabled 210 // 211 // Note that users of this macro need to place 'const' in a weird position 212 // (after the closing ')' for the arguments, but before the return type). 213 // This was the only way I could satisfy the following two requirements: 214 // 1. Avoid ambiguity errors from 'macro_rules!' (which happen when writing '$foo:ident fn' 215 // 2. Allow users of this macro to mix 'pub fn foo' and 'pub const fn bar' within the same 216 // 'f!' block 217 cfg_if! { 218 if #[cfg(libc_const_extern_fn)] { 219 /// Define an `unsafe` function that is const as long as `const-extern-fn` is enabled. 220 macro_rules! f { 221 ($( 222 $(#[$attr:meta])* 223 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty { 224 $($body:stmt);* 225 } 226 )*) => ($( 227 #[inline] 228 $(#[$attr])* 229 pub $($constness)* unsafe extern fn $i($($arg: $argty),*) -> $ret { 230 $($body);* 231 } 232 )*) 233 } 234 235 /// Define a safe function that is const as long as `const-extern-fn` is enabled. 236 macro_rules! safe_f { 237 ($( 238 $(#[$attr:meta])* 239 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty { 240 $($body:stmt);* 241 } 242 )*) => ($( 243 #[inline] 244 $(#[$attr])* 245 pub $($constness)* extern fn $i($($arg: $argty),*) -> $ret { 246 $($body);* 247 } 248 )*) 249 } 250 251 /// A nonpublic function that is const as long as `const-extern-fn` is enabled. 252 macro_rules! const_fn { 253 ($( 254 $(#[$attr:meta])* 255 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty { 256 $($body:stmt);* 257 } 258 )*) => ($( 259 #[inline] 260 $(#[$attr])* 261 $($constness)* fn $i($($arg: $argty),*) -> $ret { 262 $($body);* 263 } 264 )*) 265 } 266 } else { 267 /// Define an `unsafe` function that is const as long as `const-extern-fn` is enabled. 268 macro_rules! f { 269 ($( 270 $(#[$attr:meta])* 271 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty { 272 $($body:stmt);* 273 } 274 )*) => ($( 275 #[inline] 276 $(#[$attr])* 277 pub unsafe extern fn $i($($arg: $argty),*) -> $ret { 278 $($body);* 279 } 280 )*) 281 } 282 283 /// Define a safe function that is const as long as `const-extern-fn` is enabled. 284 macro_rules! safe_f { 285 ($( 286 $(#[$attr:meta])* 287 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty { 288 $($body:stmt);* 289 } 290 )*) => ($( 291 #[inline] 292 $(#[$attr])* 293 pub extern fn $i($($arg: $argty),*) -> $ret { 294 $($body);* 295 } 296 )*) 297 } 298 299 /// A nonpublic function that is const as long as `const-extern-fn` is enabled. 300 macro_rules! const_fn { 301 ($( 302 $(#[$attr:meta])* 303 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty { 304 $($body:stmt);* 305 } 306 )*) => ($( 307 #[inline] 308 $(#[$attr])* 309 fn $i($($arg: $argty),*) -> $ret { 310 $($body);* 311 } 312 )*) 313 } 314 } 315 } 316 317 macro_rules! __item { 318 ($i:item) => { 319 $i 320 }; 321 } 322 323 // This macro is used to deprecate items that should be accessed via the mach2 crate 324 macro_rules! deprecated_mach { 325 (pub const $id:ident: $ty:ty = $expr:expr;) => { 326 #[deprecated( 327 since = "0.2.55", 328 note = "Use the `mach2` crate instead", 329 )] 330 #[allow(deprecated)] 331 pub const $id: $ty = $expr; 332 }; 333 ($(pub const $id:ident: $ty:ty = $expr:expr;)*) => { 334 $( 335 deprecated_mach!( 336 pub const $id: $ty = $expr; 337 ); 338 )* 339 }; 340 (pub type $id:ident = $ty:ty;) => { 341 #[deprecated( 342 since = "0.2.55", 343 note = "Use the `mach2` crate instead", 344 )] 345 #[allow(deprecated)] 346 pub type $id = $ty; 347 }; 348 ($(pub type $id:ident = $ty:ty;)*) => { 349 $( 350 deprecated_mach!( 351 pub type $id = $ty; 352 ); 353 )* 354 } 355 } 356