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