libc/
macros.rs

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}