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.
9macro_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.
65macro_rules! prelude {
66 () => {
67 mod types;
68
69 /// Frequently-used types that are available on all platforms
70 ///
71 /// We need to reexport the core types so this works with `rust-dep-of-std`.
72 mod prelude {
73 // Exports from `core`
74 #[allow(unused_imports)]
75 pub(crate) use core::clone::Clone;
76 #[allow(unused_imports)]
77 pub(crate) use core::default::Default;
78 #[allow(unused_imports)]
79 pub(crate) use core::marker::{Copy, Send, Sync};
80 #[allow(unused_imports)]
81 pub(crate) use core::option::Option;
82 #[allow(unused_imports)]
83 pub(crate) use core::prelude::v1::derive;
84 #[allow(unused_imports)]
85 pub(crate) use core::{fmt, hash, iter, mem, ptr};
86
87 #[allow(unused_imports)]
88 pub(crate) use fmt::Debug;
89 #[allow(unused_imports)]
90 pub(crate) use mem::{align_of, align_of_val, size_of, size_of_val};
91
92 #[allow(unused_imports)]
93 pub(crate) use crate::types::{CEnumRepr, Padding};
94 // Commonly used types defined in this crate
95 #[allow(unused_imports)]
96 pub(crate) use crate::{
97 c_char, c_double, c_float, c_int, c_long, c_longlong, c_short, c_uchar, c_uint,
98 c_ulong, c_ulonglong, c_ushort, c_void, intptr_t, size_t, ssize_t, uintptr_t,
99 };
100 }
101 };
102}
103
104/// Implement `Clone` and `Copy` for a struct, as well as `Debug`, `Eq`, `Hash`, and
105/// `PartialEq` if the `extra_traits` feature is enabled.
106///
107/// Use [`s_no_extra_traits`] for structs where the `extra_traits` feature does not
108/// make sense, and for unions.
109macro_rules! s {
110 ($(
111 $(#[$attr:meta])*
112 pub $t:ident $i:ident { $($field:tt)* }
113 )*) => ($(
114 s!(it: $(#[$attr])* pub $t $i { $($field)* });
115 )*);
116
117 (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => (
118 compile_error!("unions cannot derive extra traits, use s_no_extra_traits instead");
119 );
120
121 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => (
122 __item! {
123 #[repr(C)]
124 #[cfg_attr(
125 feature = "extra_traits",
126 ::core::prelude::v1::derive(Eq, Hash, PartialEq)
127 )]
128 #[::core::prelude::v1::derive(
129 ::core::clone::Clone,
130 ::core::marker::Copy,
131 ::core::fmt::Debug,
132 )]
133 #[allow(deprecated)]
134 $(#[$attr])*
135 pub struct $i { $($field)* }
136 }
137 );
138}
139
140/// Implement `Clone` and `Copy` for a tuple struct, as well as `Debug`, `Eq`, `Hash`,
141/// and `PartialEq` if the `extra_traits` feature is enabled.
142///
143/// This is the same as [`s`] but works for tuple structs.
144macro_rules! s_paren {
145 ($(
146 $(#[$attr:meta])*
147 pub struct $i:ident ( $($field:tt)* );
148 )*) => ($(
149 __item! {
150 #[cfg_attr(
151 feature = "extra_traits",
152 ::core::prelude::v1::derive(Eq, Hash, PartialEq)
153 )]
154 #[::core::prelude::v1::derive(
155 ::core::clone::Clone,
156 ::core::marker::Copy,
157 ::core::fmt::Debug,
158 )]
159 $(#[$attr])*
160 pub struct $i ( $($field)* );
161 }
162 )*);
163}
164
165/// Implement `Clone`, `Copy`, and `Debug` since those can be derived, but exclude `PartialEq`,
166/// `Eq`, and `Hash`.
167///
168/// Most items will prefer to use [`s`].
169macro_rules! s_no_extra_traits {
170 ($(
171 $(#[$attr:meta])*
172 pub $t:ident $i:ident { $($field:tt)* }
173 )*) => ($(
174 s_no_extra_traits!(it: $(#[$attr])* pub $t $i { $($field)* });
175 )*);
176
177 (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => (
178 __item! {
179 #[repr(C)]
180 #[::core::prelude::v1::derive(::core::clone::Clone, ::core::marker::Copy)]
181 $(#[$attr])*
182 pub union $i { $($field)* }
183 }
184
185 impl ::core::fmt::Debug for $i {
186 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
187 f.debug_struct(::core::stringify!($i)).finish_non_exhaustive()
188 }
189 }
190 );
191
192 (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => (
193 __item! {
194 #[repr(C)]
195 #[::core::prelude::v1::derive(
196 ::core::clone::Clone,
197 ::core::marker::Copy,
198 ::core::fmt::Debug,
199 )]
200 $(#[$attr])*
201 pub struct $i { $($field)* }
202 }
203 );
204}
205
206/// Specify that an enum should have no traits that aren't specified in the macro
207/// invocation, i.e. no `Clone` or `Copy`.
208macro_rules! missing {
209 ($(
210 $(#[$attr:meta])*
211 pub enum $i:ident {}
212 )*) => ($(
213 $(#[$attr])*
214 #[allow(missing_copy_implementations)]
215 pub enum $i { }
216 )*);
217}
218
219/// Implement `Clone` and `Copy` for an enum, as well as `Debug`, `Eq`, `Hash`, and
220/// `PartialEq` if the `extra_traits` feature is enabled.
221// FIXME(#4419): Replace all uses of `e!` with `c_enum!`
222macro_rules! e {
223 ($(
224 $(#[$attr:meta])*
225 pub enum $i:ident { $($field:tt)* }
226 )*) => ($(
227 __item! {
228 #[cfg_attr(
229 feature = "extra_traits",
230 ::core::prelude::v1::derive(Eq, Hash, PartialEq)
231 )]
232 #[::core::prelude::v1::derive(
233 ::core::clone::Clone,
234 ::core::marker::Copy,
235 ::core::fmt::Debug,
236 )]
237 $(#[$attr])*
238 pub enum $i { $($field)* }
239 }
240 )*);
241}
242
243/// Represent a C enum as Rust constants and a type.
244///
245/// C enums can't soundly be mapped to Rust enums since C enums are allowed to have duplicates or
246/// unlisted values, but this is UB in Rust. This enum doesn't implement any traits, its main
247/// purpose is to calculate the correct enum values.
248///
249/// See <https://github.com/rust-lang/libc/issues/4419> for more.
250macro_rules! c_enum {
251 ($(
252 $(#[repr($repr:ty)])?
253 pub enum $ty_name:ident {
254 $($variant:ident $(= $value:expr)?,)+
255 }
256 )+) => {
257 $(c_enum!(@expand;
258 $(#[repr($repr)])?
259 pub enum $ty_name {
260 $($variant $(= $value)?,)+
261 }
262 );)+
263 };
264
265 (@expand;
266 $(#[repr($repr:ty)])?
267 pub enum $ty_name:ident {
268 $($variant:ident $(= $value:expr)?,)+
269 }
270 ) => {
271 pub type $ty_name = c_enum!(@ty $($repr)?);
272 c_enum!(@one; $ty_name; 0; $($variant $(= $value)?,)+);
273 };
274
275 // Matcher for a single variant
276 (@one; $_ty_name:ident; $_idx:expr;) => {};
277 (
278 @one; $ty_name:ident; $default_val:expr;
279 $variant:ident $(= $value:expr)?,
280 $($tail:tt)*
281 ) => {
282 pub const $variant: $ty_name = {
283 #[allow(unused_variables)]
284 let r = $default_val;
285 $(let r = $value;)?
286 r
287 };
288
289 // The next value is always one more than the previous value, unless
290 // set explicitly.
291 c_enum!(@one; $ty_name; $variant + 1; $($tail)*);
292 };
293
294 // Use a specific type if provided, otherwise default to `CEnumRepr`
295 (@ty $repr:ty) => { $repr };
296 (@ty) => { $crate::prelude::CEnumRepr };
297}
298
299/// Define a `unsafe` function.
300macro_rules! f {
301 ($(
302 $(#[$attr:meta])*
303 // Less than ideal hack to match either `fn` or `const fn`.
304 pub $(fn $i:ident)? $(const fn $const_i:ident)?
305 ($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty
306 $body:block
307 )+) => {$(
308 #[inline]
309 $(#[$attr])*
310 pub $(unsafe extern "C" fn $i)? $(const unsafe extern "C" fn $const_i)?
311 ($($arg: $argty),*) -> $ret
312 $body
313 )+};
314}
315
316/// Define a safe function.
317macro_rules! safe_f {
318 ($(
319 $(#[$attr:meta])*
320 // Less than ideal hack to match either `fn` or `const fn`.
321 pub $(fn $i:ident)? $(const fn $const_i:ident)?
322 ($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty
323 $body:block
324 )+) => {$(
325 #[inline]
326 $(#[$attr])*
327 pub $(extern "C" fn $i)? $(const extern "C" fn $const_i)?
328 ($($arg: $argty),*) -> $ret
329 $body
330 )+};
331}
332
333macro_rules! __item {
334 ($i:item) => {
335 $i
336 };
337}
338
339// This macro is used to deprecate items that should be accessed via the mach2 crate
340macro_rules! deprecated_mach {
341 (pub const $id:ident: $ty:ty = $expr:expr;) => {
342 #[deprecated(
343 since = "0.2.55",
344 note = "Use the `mach2` crate instead",
345 )]
346 #[allow(deprecated)]
347 pub const $id: $ty = $expr;
348 };
349 ($(pub const $id:ident: $ty:ty = $expr:expr;)*) => {
350 $(
351 deprecated_mach!(
352 pub const $id: $ty = $expr;
353 );
354 )*
355 };
356 (pub type $id:ident = $ty:ty;) => {
357 #[deprecated(
358 since = "0.2.55",
359 note = "Use the `mach2` crate instead",
360 )]
361 #[allow(deprecated)]
362 pub type $id = $ty;
363 };
364 ($(pub type $id:ident = $ty:ty;)*) => {
365 $(
366 deprecated_mach!(
367 pub type $id = $ty;
368 );
369 )*
370 }
371}
372
373#[cfg(test)]
374mod tests {
375 use crate::types::CEnumRepr;
376
377 #[test]
378 fn c_enumbasic() {
379 // By default, variants get sequential values.
380 c_enum! {
381 pub enum e {
382 VAR0,
383 VAR1,
384 VAR2,
385 }
386 }
387
388 assert_eq!(VAR0, 0 as CEnumRepr);
389 assert_eq!(VAR1, 1 as CEnumRepr);
390 assert_eq!(VAR2, 2 as CEnumRepr);
391 }
392
393 #[test]
394 fn c_enumrepr() {
395 // By default, variants get sequential values.
396 c_enum! {
397 #[repr(u16)]
398 pub enum e {
399 VAR0,
400 }
401 }
402
403 assert_eq!(VAR0, 0_u16);
404 }
405
406 #[test]
407 fn c_enumset_value() {
408 // Setting an explicit value resets the count.
409 c_enum! {
410 pub enum e {
411 VAR2 = 2,
412 VAR3,
413 VAR4,
414 }
415 }
416
417 assert_eq!(VAR2, 2 as CEnumRepr);
418 assert_eq!(VAR3, 3 as CEnumRepr);
419 assert_eq!(VAR4, 4 as CEnumRepr);
420 }
421
422 #[test]
423 fn c_enummultiple_set_value() {
424 // C enums always take one more than the previous value, unless set to a specific
425 // value. Duplicates are allowed.
426 c_enum! {
427 pub enum e {
428 VAR0,
429 VAR2_0 = 2,
430 VAR3_0,
431 VAR4_0,
432 VAR2_1 = 2,
433 VAR3_1,
434 VAR4_1,
435 }
436 }
437
438 assert_eq!(VAR0, 0 as CEnumRepr);
439 assert_eq!(VAR2_0, 2 as CEnumRepr);
440 assert_eq!(VAR3_0, 3 as CEnumRepr);
441 assert_eq!(VAR4_0, 4 as CEnumRepr);
442 assert_eq!(VAR2_1, 2 as CEnumRepr);
443 assert_eq!(VAR3_1, 3 as CEnumRepr);
444 assert_eq!(VAR4_1, 4 as CEnumRepr);
445 }
446}
447