1// Thanks to Tokio for this macro
2macro_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/// ```
55macro_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)]
100macro_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