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