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 /// Create an internal crate prelude with `core` reexports and common types. 65 macro_rules! prelude { 66 () => { 67 /// Frequently-used types that are available on all platforms 68 /// 69 /// We need to reexport the core types so this works with `rust-dep-of-std`. 70 mod prelude { 71 // Exports from `core` 72 #[allow(unused_imports)] 73 pub(crate) use ::core::clone::Clone; 74 #[allow(unused_imports)] 75 pub(crate) use ::core::marker::{Copy, Send, Sync}; 76 #[allow(unused_imports)] 77 pub(crate) use ::core::option::Option; 78 #[allow(unused_imports)] 79 pub(crate) use ::core::{fmt, hash, iter, mem}; 80 81 // Commonly used types defined in this crate 82 #[allow(unused_imports)] 83 pub(crate) use crate::{ 84 c_char, c_double, c_float, c_int, c_long, c_longlong, c_short, c_uchar, c_uint, 85 c_ulong, c_ulonglong, c_ushort, c_void, intptr_t, size_t, ssize_t, uintptr_t, 86 }; 87 } 88 }; 89 } 90 91 /// Implement `Clone` and `Copy` for a struct, as well as `Debug`, `Eq`, `Hash`, and 92 /// `PartialEq` if the `extra_traits` feature is enabled. 93 /// 94 /// Use [`s_no_extra_traits`] for structs where the `extra_traits` feature does not 95 /// make sense, and for unions. 96 macro_rules! s { 97 ($( 98 $(#[$attr:meta])* 99 pub $t:ident $i:ident { $($field:tt)* } 100 )*) => ($( 101 s!(it: $(#[$attr])* pub $t $i { $($field)* }); 102 )*); 103 104 (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => ( 105 compile_error!("unions cannot derive extra traits, use s_no_extra_traits instead"); 106 ); 107 108 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( 109 __item! { 110 #[repr(C)] 111 #[cfg_attr( 112 feature = "extra_traits", 113 ::core::prelude::v1::derive(Debug, Eq, Hash, PartialEq) 114 )] 115 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)] 116 #[allow(deprecated)] 117 $(#[$attr])* 118 pub struct $i { $($field)* } 119 } 120 ); 121 } 122 123 /// Implement `Clone` and `Copy` for a tuple struct, as well as `Debug`, `Eq`, `Hash`, 124 /// and `PartialEq` if the `extra_traits` feature is enabled. 125 /// 126 /// This is the same as [`s`] but works for tuple structs. 127 macro_rules! s_paren { 128 ($( 129 $(#[$attr:meta])* 130 pub struct $i:ident ( $($field:tt)* ); 131 )*) => ($( 132 __item! { 133 #[cfg_attr( 134 feature = "extra_traits", 135 ::core::prelude::v1::derive(Debug, Eq, Hash, PartialEq) 136 )] 137 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)] 138 $(#[$attr])* 139 pub struct $i ( $($field)* ); 140 } 141 )*); 142 } 143 144 /// Implement `Clone` and `Copy` for a struct with no `extra_traits` feature. 145 /// 146 /// Most items will prefer to use [`s`]. 147 macro_rules! s_no_extra_traits { 148 ($( 149 $(#[$attr:meta])* 150 pub $t:ident $i:ident { $($field:tt)* } 151 )*) => ($( 152 s_no_extra_traits!(it: $(#[$attr])* pub $t $i { $($field)* }); 153 )*); 154 155 (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => ( 156 __item! { 157 #[repr(C)] 158 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)] 159 $(#[$attr])* 160 pub union $i { $($field)* } 161 } 162 ); 163 164 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( 165 __item! { 166 #[repr(C)] 167 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)] 168 $(#[$attr])* 169 pub struct $i { $($field)* } 170 } 171 ); 172 } 173 174 /// Specify that an enum should have no traits that aren't specified in the macro 175 /// invocation, i.e. no `Clone` or `Copy`. 176 macro_rules! missing { 177 ($( 178 $(#[$attr:meta])* 179 pub enum $i:ident {} 180 )*) => ($( 181 $(#[$attr])* 182 #[allow(missing_copy_implementations)] 183 pub enum $i { } 184 )*); 185 } 186 187 /// Implement `Clone` and `Copy` for an enum, as well as `Debug`, `Eq`, `Hash`, and 188 /// `PartialEq` if the `extra_traits` feature is enabled. 189 macro_rules! e { 190 ($( 191 $(#[$attr:meta])* 192 pub enum $i:ident { $($field:tt)* } 193 )*) => ($( 194 __item! { 195 #[cfg_attr( 196 feature = "extra_traits", 197 ::core::prelude::v1::derive(Debug, Eq, Hash, PartialEq) 198 )] 199 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)] 200 $(#[$attr])* 201 pub enum $i { $($field)* } 202 } 203 )*); 204 } 205 206 // This is a pretty horrible hack to allow us to conditionally mark some functions as 'const', 207 // without requiring users of this macro to care "libc_const_extern_fn". 208 // 209 // When 'libc_const_extern_fn' is enabled, we emit the captured 'const' keyword in the expanded 210 // function. 211 // 212 // When 'libc_const_extern_fn' is disabled, we always emit a plain 'pub unsafe extern fn'. 213 // Note that the expression matched by the macro is exactly the same - this allows 214 // users of this macro to work whether or not 'libc_const_extern_fn' is enabled 215 // 216 // Unfortunately, we need to duplicate most of this macro between the 'cfg_if' blocks. 217 // This is because 'const unsafe extern fn' won't even parse on older compilers, 218 // so we need to avoid emitting it at all of 'libc_const_extern_fn'. 219 // 220 // Specifically, moving the 'cfg_if' into the macro body will *not* work. Doing so would cause the 221 // '#[cfg(libc_const_extern_fn)]' to be emitted into user code. The 'cfg' gate will not stop Rust 222 // from trying to parse the 'pub const unsafe extern fn', so users would get a compiler error even 223 // when the 'libc_const_extern_fn' feature is disabled. 224 225 // FIXME(ctest): ctest can't handle `const extern` functions, we should be able to remove this 226 // cfg completely. 227 // FIXME(ctest): ctest can't handle `$(,)?` so we use `$(,)*` which isn't quite correct. 228 cfg_if! { 229 if #[cfg(libc_const_extern_fn)] { 230 /// Define an `unsafe` function that is const as long as `libc_const_extern_fn` is enabled. 231 macro_rules! f { 232 ($( 233 $(#[$attr:meta])* 234 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 235 $body:block 236 )*) => ($( 237 #[inline] 238 $(#[$attr])* 239 pub $($constness)* unsafe extern fn $i($($arg: $argty),*) -> $ret 240 $body 241 )*) 242 } 243 244 /// Define a safe function that is const as long as `libc_const_extern_fn` is enabled. 245 macro_rules! safe_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 $($constness)* extern fn $i($($arg: $argty),*) -> $ret 254 $body 255 )*) 256 } 257 258 /// A nonpublic function that is const as long as `libc_const_extern_fn` is enabled. 259 macro_rules! const_fn { 260 ($( 261 $(#[$attr:meta])* 262 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 263 $body:block 264 )*) => ($( 265 #[inline] 266 $(#[$attr])* 267 $($constness)* fn $i($($arg: $argty),*) -> $ret 268 $body 269 )*) 270 } 271 } else { 272 /// Define an `unsafe` function that is const as long as `libc_const_extern_fn` is enabled. 273 macro_rules! f { 274 ($( 275 $(#[$attr:meta])* 276 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 277 $body:block 278 )*) => ($( 279 #[inline] 280 $(#[$attr])* 281 pub unsafe extern fn $i($($arg: $argty),*) -> $ret 282 $body 283 )*) 284 } 285 286 /// Define a safe function that is const as long as `libc_const_extern_fn` is enabled. 287 macro_rules! safe_f { 288 ($( 289 $(#[$attr:meta])* 290 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 291 $body:block 292 )*) => ($( 293 #[inline] 294 $(#[$attr])* 295 pub extern fn $i($($arg: $argty),*) -> $ret 296 $body 297 )*) 298 } 299 300 /// A nonpublic function that is const as long as `libc_const_extern_fn` is enabled. 301 macro_rules! const_fn { 302 ($( 303 $(#[$attr:meta])* 304 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 305 $body:block 306 )*) => ($( 307 #[inline] 308 $(#[$attr])* 309 fn $i($($arg: $argty),*) -> $ret 310 $body 311 )*) 312 } 313 } 314 } 315 316 macro_rules! __item { 317 ($i:item) => { 318 $i 319 }; 320 } 321 322 // This macro is used to deprecate items that should be accessed via the mach2 crate 323 macro_rules! deprecated_mach { 324 (pub const $id:ident: $ty:ty = $expr:expr;) => { 325 #[deprecated( 326 since = "0.2.55", 327 note = "Use the `mach2` crate instead", 328 )] 329 #[allow(deprecated)] 330 pub const $id: $ty = $expr; 331 }; 332 ($(pub const $id:ident: $ty:ty = $expr:expr;)*) => { 333 $( 334 deprecated_mach!( 335 pub const $id: $ty = $expr; 336 ); 337 )* 338 }; 339 (pub type $id:ident = $ty:ty;) => { 340 #[deprecated( 341 since = "0.2.55", 342 note = "Use the `mach2` crate instead", 343 )] 344 #[allow(deprecated)] 345 pub type $id = $ty; 346 }; 347 ($(pub type $id:ident = $ty:ty;)*) => { 348 $( 349 deprecated_mach!( 350 pub type $id = $ty; 351 ); 352 )* 353 } 354 } 355