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