1 // Thanks to Tokio for this macro
2 macro_rules! feature {
3     (
4         #![$meta:meta]
5         $($item:item)*
6     ) => {
7         $(
8             #[cfg($meta)]
9             #[cfg_attr(docsrs, doc(cfg($meta)))]
10             $item
11         )*
12     }
13 }
14 
15 /// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type
16 /// with values from the libc crate. It is used the same way as the `bitflags!` macro, except
17 /// that only the name of the flag value has to be given.
18 ///
19 /// The `libc` crate must be in scope with the name `libc`.
20 ///
21 /// # Example
22 /// ```ignore
23 /// libc_bitflags!{
24 ///     pub struct ProtFlags: libc::c_int {
25 ///         PROT_NONE;
26 ///         PROT_READ;
27 ///         /// PROT_WRITE enables write protect
28 ///         PROT_WRITE;
29 ///         PROT_EXEC;
30 ///         #[cfg(linux_android)]
31 ///         PROT_GROWSDOWN;
32 ///         #[cfg(linux_android)]
33 ///         PROT_GROWSUP;
34 ///     }
35 /// }
36 /// ```
37 ///
38 /// Example with casting, due to a mistake in libc. In this example, the
39 /// various flags have different types, so we cast the broken ones to the right
40 /// type.
41 ///
42 /// ```ignore
43 /// libc_bitflags!{
44 ///     pub struct SaFlags: libc::c_ulong {
45 ///         SA_NOCLDSTOP as libc::c_ulong;
46 ///         SA_NOCLDWAIT;
47 ///         SA_NODEFER as libc::c_ulong;
48 ///         SA_ONSTACK;
49 ///         SA_RESETHAND as libc::c_ulong;
50 ///         SA_RESTART as libc::c_ulong;
51 ///         SA_SIGINFO;
52 ///     }
53 /// }
54 /// ```
55 macro_rules! libc_bitflags {
56     (
57         $(#[$outer:meta])*
58         pub struct $BitFlags:ident: $T:ty {
59             $(
60                 $(#[$inner:ident $($args:tt)*])*
61                 $Flag:ident $(as $cast:ty)*;
62             )+
63         }
64     ) => {
65         ::bitflags::bitflags! {
66             #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
67             #[repr(transparent)]
68             $(#[$outer])*
69             pub struct $BitFlags: $T {
70                 $(
71                     $(#[$inner $($args)*])*
72                     const $Flag = libc::$Flag $(as $cast)*;
73                 )+
74             }
75         }
76     };
77 }
78 
79 /// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using
80 /// values from the `libc` crate. This macro supports both `pub` and private `enum`s.
81 ///
82 /// The `libc` crate must be in scope with the name `libc`.
83 ///
84 /// # Example
85 /// ```ignore
86 /// libc_enum!{
87 ///     pub enum ProtFlags {
88 ///         PROT_NONE,
89 ///         PROT_READ,
90 ///         PROT_WRITE,
91 ///         PROT_EXEC,
92 ///         #[cfg(linux_android)]
93 ///         PROT_GROWSDOWN,
94 ///         #[cfg(linux_android)]
95 ///         PROT_GROWSUP,
96 ///     }
97 /// }
98 /// ```
99 // Some targets don't use all rules.
100 #[allow(unused_macro_rules)]
101 macro_rules! libc_enum {
102     // Exit rule.
103     (@make_enum
104         name: $BitFlags:ident,
105         {
106             $v:vis
107             attrs: [$($attrs:tt)*],
108             entries: [$($entries:tt)*],
109         }
110     ) => {
111         $($attrs)*
112         #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
113         $v enum $BitFlags {
114             $($entries)*
115         }
116     };
117 
118     // Exit rule including TryFrom
119     (@make_enum
120         name: $BitFlags:ident,
121         {
122             $v:vis
123             attrs: [$($attrs:tt)*],
124             entries: [$($entries:tt)*],
125             from_type: $repr:path,
126             try_froms: [$($try_froms:tt)*]
127         }
128     ) => {
129         $($attrs)*
130         #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
131         $v enum $BitFlags {
132             $($entries)*
133         }
134         impl ::std::convert::TryFrom<$repr> for $BitFlags {
135             type Error = $crate::Error;
136             #[allow(unused_doc_comments)]
137             #[allow(deprecated)]
138             #[allow(unused_attributes)]
139             fn try_from(x: $repr) -> $crate::Result<Self> {
140                 match x {
141                     $($try_froms)*
142                     _ => Err($crate::Error::EINVAL)
143                 }
144             }
145         }
146     };
147 
148     // Done accumulating.
149     (@accumulate_entries
150         name: $BitFlags:ident,
151         {
152             $v:vis
153             attrs: $attrs:tt,
154         },
155         $entries:tt,
156         $try_froms:tt;
157     ) => {
158         libc_enum! {
159             @make_enum
160             name: $BitFlags,
161             {
162                 $v
163                 attrs: $attrs,
164                 entries: $entries,
165             }
166         }
167     };
168 
169     // Done accumulating and want TryFrom
170     (@accumulate_entries
171         name: $BitFlags:ident,
172         {
173             $v:vis
174             attrs: $attrs:tt,
175             from_type: $repr:path,
176         },
177         $entries:tt,
178         $try_froms:tt;
179     ) => {
180         libc_enum! {
181             @make_enum
182             name: $BitFlags,
183             {
184                 $v
185                 attrs: $attrs,
186                 entries: $entries,
187                 from_type: $repr,
188                 try_froms: $try_froms
189             }
190         }
191     };
192 
193     // Munch an attr.
194     (@accumulate_entries
195         name: $BitFlags:ident,
196         $prefix:tt,
197         [$($entries:tt)*],
198         [$($try_froms:tt)*];
199         #[$attr:meta] $($tail:tt)*
200     ) => {
201         libc_enum! {
202             @accumulate_entries
203             name: $BitFlags,
204             $prefix,
205             [
206                 $($entries)*
207                 #[$attr]
208             ],
209             [
210                 $($try_froms)*
211                 #[$attr]
212             ];
213             $($tail)*
214         }
215     };
216 
217     // Munch last ident if not followed by a comma.
218     (@accumulate_entries
219         name: $BitFlags:ident,
220         $prefix:tt,
221         [$($entries:tt)*],
222         [$($try_froms:tt)*];
223         $entry:ident
224     ) => {
225         libc_enum! {
226             @accumulate_entries
227             name: $BitFlags,
228             $prefix,
229             [
230                 $($entries)*
231                 $entry = libc::$entry,
232             ],
233             [
234                 $($try_froms)*
235                 libc::$entry => Ok($BitFlags::$entry),
236             ];
237         }
238     };
239 
240     // Munch an ident; covers terminating comma case.
241     (@accumulate_entries
242         name: $BitFlags:ident,
243         $prefix:tt,
244         [$($entries:tt)*],
245         [$($try_froms:tt)*];
246         $entry:ident,
247         $($tail:tt)*
248     ) => {
249         libc_enum! {
250             @accumulate_entries
251             name: $BitFlags,
252             $prefix,
253             [
254                 $($entries)*
255                 $entry = libc::$entry,
256             ],
257             [
258                 $($try_froms)*
259                 libc::$entry => Ok($BitFlags::$entry),
260             ];
261             $($tail)*
262         }
263     };
264 
265     // Munch an ident and cast it to the given type; covers terminating comma.
266     (@accumulate_entries
267         name: $BitFlags:ident,
268         $prefix:tt,
269         [$($entries:tt)*],
270         [$($try_froms:tt)*];
271         $entry:ident as $ty:ty,
272         $($tail:tt)*
273     ) => {
274         libc_enum! {
275             @accumulate_entries
276             name: $BitFlags,
277             $prefix,
278             [
279                 $($entries)*
280                 $entry = libc::$entry as $ty,
281             ],
282             [
283                 $($try_froms)*
284                 libc::$entry as $ty => Ok($BitFlags::$entry),
285             ];
286             $($tail)*
287         }
288     };
289 
290     // Entry rule.
291     (
292         $(#[$attr:meta])*
293         $v:vis enum $BitFlags:ident {
294             $($vals:tt)*
295         }
296     ) => {
297         libc_enum! {
298             @accumulate_entries
299             name: $BitFlags,
300             {
301                 $v
302                 attrs: [$(#[$attr])*],
303             },
304             [],
305             [];
306             $($vals)*
307         }
308     };
309 
310     // Entry rule including TryFrom
311     (
312         $(#[$attr:meta])*
313         $v:vis enum $BitFlags:ident {
314             $($vals:tt)*
315         }
316         impl TryFrom<$repr:path>
317     ) => {
318         libc_enum! {
319             @accumulate_entries
320             name: $BitFlags,
321             {
322                 $v
323                 attrs: [$(#[$attr])*],
324                 from_type: $repr,
325             },
326             [],
327             [];
328             $($vals)*
329         }
330     };
331 }
332