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 #[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)]
101macro_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