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 | |