• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(any(target_os = "linux", target_os = "android"))]
31 ///         PROT_GROWSDOWN;
32 ///         #[cfg(any(target_os = "linux", target_os = "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             $(#[$outer])*
67             pub struct $BitFlags: $T {
68                 $(
69                     $(#[$inner $($args)*])*
70                     const $Flag = libc::$Flag $(as $cast)*;
71                 )+
72             }
73         }
74     };
75 }
76 
77 /// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using
78 /// values from the `libc` crate. This macro supports both `pub` and private `enum`s.
79 ///
80 /// The `libc` crate must be in scope with the name `libc`.
81 ///
82 /// # Example
83 /// ```ignore
84 /// libc_enum!{
85 ///     pub enum ProtFlags {
86 ///         PROT_NONE,
87 ///         PROT_READ,
88 ///         PROT_WRITE,
89 ///         PROT_EXEC,
90 ///         #[cfg(any(target_os = "linux", target_os = "android"))]
91 ///         PROT_GROWSDOWN,
92 ///         #[cfg(any(target_os = "linux", target_os = "android"))]
93 ///         PROT_GROWSUP,
94 ///     }
95 /// }
96 /// ```
97 // Some targets don't use all rules.
98 #[allow(unknown_lints)]
99 #[allow(unused_macro_rules)]
100 macro_rules! libc_enum {
101     // Exit rule.
102     (@make_enum
103         name: $BitFlags:ident,
104         {
105             $v:vis
106             attrs: [$($attrs:tt)*],
107             entries: [$($entries:tt)*],
108         }
109     ) => {
110         $($attrs)*
111         #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
112         $v enum $BitFlags {
113             $($entries)*
114         }
115     };
116 
117     // Exit rule including TryFrom
118     (@make_enum
119         name: $BitFlags:ident,
120         {
121             $v:vis
122             attrs: [$($attrs:tt)*],
123             entries: [$($entries:tt)*],
124             from_type: $repr:path,
125             try_froms: [$($try_froms:tt)*]
126         }
127     ) => {
128         $($attrs)*
129         #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
130         $v enum $BitFlags {
131             $($entries)*
132         }
133         impl ::std::convert::TryFrom<$repr> for $BitFlags {
134             type Error = $crate::Error;
135             #[allow(unused_doc_comments)]
136             fn try_from(x: $repr) -> $crate::Result<Self> {
137                 match x {
138                     $($try_froms)*
139                     _ => Err($crate::Error::EINVAL)
140                 }
141             }
142         }
143     };
144 
145     // Done accumulating.
146     (@accumulate_entries
147         name: $BitFlags:ident,
148         {
149             $v:vis
150             attrs: $attrs:tt,
151         },
152         $entries:tt,
153         $try_froms:tt;
154     ) => {
155         libc_enum! {
156             @make_enum
157             name: $BitFlags,
158             {
159                 $v
160                 attrs: $attrs,
161                 entries: $entries,
162             }
163         }
164     };
165 
166     // Done accumulating and want TryFrom
167     (@accumulate_entries
168         name: $BitFlags:ident,
169         {
170             $v:vis
171             attrs: $attrs:tt,
172             from_type: $repr:path,
173         },
174         $entries:tt,
175         $try_froms:tt;
176     ) => {
177         libc_enum! {
178             @make_enum
179             name: $BitFlags,
180             {
181                 $v
182                 attrs: $attrs,
183                 entries: $entries,
184                 from_type: $repr,
185                 try_froms: $try_froms
186             }
187         }
188     };
189 
190     // Munch an attr.
191     (@accumulate_entries
192         name: $BitFlags:ident,
193         $prefix:tt,
194         [$($entries:tt)*],
195         [$($try_froms:tt)*];
196         #[$attr:meta] $($tail:tt)*
197     ) => {
198         libc_enum! {
199             @accumulate_entries
200             name: $BitFlags,
201             $prefix,
202             [
203                 $($entries)*
204                 #[$attr]
205             ],
206             [
207                 $($try_froms)*
208                 #[$attr]
209             ];
210             $($tail)*
211         }
212     };
213 
214     // Munch last ident if not followed by a comma.
215     (@accumulate_entries
216         name: $BitFlags:ident,
217         $prefix:tt,
218         [$($entries:tt)*],
219         [$($try_froms:tt)*];
220         $entry:ident
221     ) => {
222         libc_enum! {
223             @accumulate_entries
224             name: $BitFlags,
225             $prefix,
226             [
227                 $($entries)*
228                 $entry = libc::$entry,
229             ],
230             [
231                 $($try_froms)*
232                 libc::$entry => Ok($BitFlags::$entry),
233             ];
234         }
235     };
236 
237     // Munch an ident; covers terminating comma case.
238     (@accumulate_entries
239         name: $BitFlags:ident,
240         $prefix:tt,
241         [$($entries:tt)*],
242         [$($try_froms:tt)*];
243         $entry:ident,
244         $($tail:tt)*
245     ) => {
246         libc_enum! {
247             @accumulate_entries
248             name: $BitFlags,
249             $prefix,
250             [
251                 $($entries)*
252                 $entry = libc::$entry,
253             ],
254             [
255                 $($try_froms)*
256                 libc::$entry => Ok($BitFlags::$entry),
257             ];
258             $($tail)*
259         }
260     };
261 
262     // Munch an ident and cast it to the given type; covers terminating comma.
263     (@accumulate_entries
264         name: $BitFlags:ident,
265         $prefix:tt,
266         [$($entries:tt)*],
267         [$($try_froms:tt)*];
268         $entry:ident as $ty:ty,
269         $($tail:tt)*
270     ) => {
271         libc_enum! {
272             @accumulate_entries
273             name: $BitFlags,
274             $prefix,
275             [
276                 $($entries)*
277                 $entry = libc::$entry as $ty,
278             ],
279             [
280                 $($try_froms)*
281                 libc::$entry as $ty => Ok($BitFlags::$entry),
282             ];
283             $($tail)*
284         }
285     };
286 
287     // Entry rule.
288     (
289         $(#[$attr:meta])*
290         $v:vis enum $BitFlags:ident {
291             $($vals:tt)*
292         }
293     ) => {
294         libc_enum! {
295             @accumulate_entries
296             name: $BitFlags,
297             {
298                 $v
299                 attrs: [$(#[$attr])*],
300             },
301             [],
302             [];
303             $($vals)*
304         }
305     };
306 
307     // Entry rule including TryFrom
308     (
309         $(#[$attr:meta])*
310         $v:vis enum $BitFlags:ident {
311             $($vals:tt)*
312         }
313         impl TryFrom<$repr:path>
314     ) => {
315         libc_enum! {
316             @accumulate_entries
317             name: $BitFlags,
318             {
319                 $v
320                 attrs: [$(#[$attr])*],
321                 from_type: $repr,
322             },
323             [],
324             [];
325             $($vals)*
326         }
327     };
328 }
329