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 #[cfg(feature = "extra_traits")] 164 impl ::core::fmt::Debug for $i { 165 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 166 f.debug_struct(::core::stringify!($i)).finish_non_exhaustive() 167 } 168 } 169 ); 170 171 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( 172 __item! { 173 #[repr(C)] 174 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)] 175 $(#[$attr])* 176 pub struct $i { $($field)* } 177 } 178 ); 179 } 180 181 /// Specify that an enum should have no traits that aren't specified in the macro 182 /// invocation, i.e. no `Clone` or `Copy`. 183 macro_rules! missing { 184 ($( 185 $(#[$attr:meta])* 186 pub enum $i:ident {} 187 )*) => ($( 188 $(#[$attr])* 189 #[allow(missing_copy_implementations)] 190 pub enum $i { } 191 )*); 192 } 193 194 /// Implement `Clone` and `Copy` for an enum, as well as `Debug`, `Eq`, `Hash`, and 195 /// `PartialEq` if the `extra_traits` feature is enabled. 196 // FIXME(#4419): Replace all uses of `e!` with `c_enum!` 197 macro_rules! e { 198 ($( 199 $(#[$attr:meta])* 200 pub enum $i:ident { $($field:tt)* } 201 )*) => ($( 202 __item! { 203 #[cfg_attr( 204 feature = "extra_traits", 205 ::core::prelude::v1::derive(Debug, Eq, Hash, PartialEq) 206 )] 207 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)] 208 $(#[$attr])* 209 pub enum $i { $($field)* } 210 } 211 )*); 212 } 213 214 /// Represent a C enum as Rust constants and a type. 215 /// 216 /// C enums can't soundly be mapped to Rust enums since C enums are allowed to have duplicates or 217 /// unlisted values, but this is UB in Rust. This enum doesn't implement any traits, its main 218 /// purpose is to calculate the correct enum values. 219 /// 220 /// See <https://github.com/rust-lang/libc/issues/4419> for more. 221 macro_rules! c_enum { 222 ( 223 $(#[repr($repr:ty)])? 224 $ty_name:ident { 225 $($variant:ident $(= $value:literal)?,)+ 226 } 227 ) => { 228 pub type $ty_name = c_enum!(@ty $($repr)?); 229 c_enum!(@one; $ty_name; 0; $($variant $(= $value)?,)+); 230 }; 231 232 // Matcher for a single variant 233 (@one; $_ty_name:ident; $_idx:expr;) => {}; 234 ( 235 @one; $ty_name:ident; $default_val:expr; 236 $variant:ident $(= $value:literal)?, 237 $($tail:tt)* 238 ) => { 239 pub const $variant: $ty_name = { 240 #[allow(unused_variables)] 241 let r = $default_val; 242 $(let r = $value;)? 243 r 244 }; 245 246 // The next value is always one more than the previous value, unless 247 // set explicitly. 248 c_enum!(@one; $ty_name; $variant + 1; $($tail)*); 249 }; 250 251 // Use a specific type if provided, otherwise default to `c_uint` 252 (@ty $repr:ty) => { $repr }; 253 (@ty) => { $crate::c_uint }; 254 } 255 256 // This is a pretty horrible hack to allow us to conditionally mark some functions as 'const', 257 // without requiring users of this macro to care "libc_const_extern_fn". 258 // 259 // When 'libc_const_extern_fn' is enabled, we emit the captured 'const' keyword in the expanded 260 // function. 261 // 262 // When 'libc_const_extern_fn' is disabled, we always emit a plain 'pub unsafe extern fn'. 263 // Note that the expression matched by the macro is exactly the same - this allows 264 // users of this macro to work whether or not 'libc_const_extern_fn' is enabled 265 // 266 // Unfortunately, we need to duplicate most of this macro between the 'cfg_if' blocks. 267 // This is because 'const unsafe extern fn' won't even parse on older compilers, 268 // so we need to avoid emitting it at all of 'libc_const_extern_fn'. 269 // 270 // Specifically, moving the 'cfg_if' into the macro body will *not* work. Doing so would cause the 271 // '#[cfg(libc_const_extern_fn)]' to be emitted into user code. The 'cfg' gate will not stop Rust 272 // from trying to parse the 'pub const unsafe extern fn', so users would get a compiler error even 273 // when the 'libc_const_extern_fn' feature is disabled. 274 275 // FIXME(ctest): ctest can't handle `const extern` functions, we should be able to remove this 276 // cfg completely. 277 // FIXME(ctest): ctest can't handle `$(,)?` so we use `$(,)*` which isn't quite correct. 278 cfg_if! { 279 if #[cfg(libc_const_extern_fn)] { 280 /// Define an `unsafe` function that is const as long as `libc_const_extern_fn` is enabled. 281 macro_rules! f { 282 ($( 283 $(#[$attr:meta])* 284 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 285 $body:block 286 )*) => ($( 287 #[inline] 288 $(#[$attr])* 289 pub $($constness)* unsafe extern "C" fn $i($($arg: $argty),*) -> $ret 290 $body 291 )*) 292 } 293 294 /// Define a safe function that is const as long as `libc_const_extern_fn` is enabled. 295 macro_rules! safe_f { 296 ($( 297 $(#[$attr:meta])* 298 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 299 $body:block 300 )*) => ($( 301 #[inline] 302 $(#[$attr])* 303 pub $($constness)* extern "C" fn $i($($arg: $argty),*) -> $ret 304 $body 305 )*) 306 } 307 308 /// A nonpublic function that is const as long as `libc_const_extern_fn` is enabled. 309 macro_rules! const_fn { 310 ($( 311 $(#[$attr:meta])* 312 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 313 $body:block 314 )*) => ($( 315 #[inline] 316 $(#[$attr])* 317 $($constness)* fn $i($($arg: $argty),*) -> $ret 318 $body 319 )*) 320 } 321 } else { 322 /// Define an `unsafe` function that is const as long as `libc_const_extern_fn` is enabled. 323 macro_rules! f { 324 ($( 325 $(#[$attr:meta])* 326 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 327 $body:block 328 )*) => ($( 329 #[inline] 330 $(#[$attr])* 331 pub unsafe extern "C" fn $i($($arg: $argty),*) -> $ret 332 $body 333 )*) 334 } 335 336 /// Define a safe function that is const as long as `libc_const_extern_fn` is enabled. 337 macro_rules! safe_f { 338 ($( 339 $(#[$attr:meta])* 340 pub $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 341 $body:block 342 )*) => ($( 343 #[inline] 344 $(#[$attr])* 345 pub extern "C" fn $i($($arg: $argty),*) -> $ret 346 $body 347 )*) 348 } 349 350 /// A nonpublic function that is const as long as `libc_const_extern_fn` is enabled. 351 macro_rules! const_fn { 352 ($( 353 $(#[$attr:meta])* 354 $({$constness:ident})* fn $i:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty 355 $body:block 356 )*) => ($( 357 #[inline] 358 $(#[$attr])* 359 fn $i($($arg: $argty),*) -> $ret 360 $body 361 )*) 362 } 363 } 364 } 365 366 macro_rules! __item { 367 ($i:item) => { 368 $i 369 }; 370 } 371 372 // This macro is used to deprecate items that should be accessed via the mach2 crate 373 macro_rules! deprecated_mach { 374 (pub const $id:ident: $ty:ty = $expr:expr;) => { 375 #[deprecated( 376 since = "0.2.55", 377 note = "Use the `mach2` crate instead", 378 )] 379 #[allow(deprecated)] 380 pub const $id: $ty = $expr; 381 }; 382 ($(pub const $id:ident: $ty:ty = $expr:expr;)*) => { 383 $( 384 deprecated_mach!( 385 pub const $id: $ty = $expr; 386 ); 387 )* 388 }; 389 (pub type $id:ident = $ty:ty;) => { 390 #[deprecated( 391 since = "0.2.55", 392 note = "Use the `mach2` crate instead", 393 )] 394 #[allow(deprecated)] 395 pub type $id = $ty; 396 }; 397 ($(pub type $id:ident = $ty:ty;)*) => { 398 $( 399 deprecated_mach!( 400 pub type $id = $ty; 401 ); 402 )* 403 } 404 } 405 406 #[cfg(test)] 407 mod tests { 408 #[test] 409 fn c_enumbasic() { 410 // By default, variants get sequential values. 411 c_enum! { 412 e { 413 VAR0, 414 VAR1, 415 VAR2, 416 } 417 } 418 419 assert_eq!(VAR0, 0_u32); 420 assert_eq!(VAR1, 1_u32); 421 assert_eq!(VAR2, 2_u32); 422 } 423 424 #[test] 425 fn c_enumrepr() { 426 // By default, variants get sequential values. 427 c_enum! { 428 #[repr(u16)] 429 e { 430 VAR0, 431 } 432 } 433 434 assert_eq!(VAR0, 0_u16); 435 } 436 437 #[test] 438 fn c_enumset_value() { 439 // Setting an explicit value resets the count. 440 c_enum! { 441 e { 442 VAR2 = 2, 443 VAR3, 444 VAR4, 445 } 446 } 447 448 assert_eq!(VAR2, 2_u32); 449 assert_eq!(VAR3, 3_u32); 450 assert_eq!(VAR4, 4_u32); 451 } 452 453 #[test] 454 fn c_enummultiple_set_value() { 455 // C enums always take one more than the previous value, unless set to a specific 456 // value. Duplicates are allowed. 457 c_enum! { 458 e { 459 VAR0, 460 VAR2_0 = 2, 461 VAR3_0, 462 VAR4_0, 463 VAR2_1 = 2, 464 VAR3_1, 465 VAR4_1, 466 } 467 } 468 469 assert_eq!(VAR0, 0_u32); 470 assert_eq!(VAR2_0, 2_u32); 471 assert_eq!(VAR3_0, 3_u32); 472 assert_eq!(VAR4_0, 4_u32); 473 assert_eq!(VAR2_1, 2_u32); 474 assert_eq!(VAR3_1, 3_u32); 475 assert_eq!(VAR4_1, 4_u32); 476 } 477 } 478