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 | #[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(any(target_os = "linux" , target_os = "android" ))] |
93 | /// PROT_GROWSDOWN, |
94 | /// #[cfg(any(target_os = "linux" , target_os = "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 | |