nix/macros.rs
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/// ```ignore
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/// ```ignore
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/// ```
41macro_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/// ```ignore
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// Some targets don't use all rules.
84#[allow(unknown_lints)]
85#[allow(unused_macro_rules)]
86macro_rules! libc_enum {
87 // Exit rule.
88 (@make_enum
89 name: $BitFlags:ident,
90 {
91 $v:vis
92 attrs: [$($attrs:tt)*],
93 entries: [$($entries:tt)*],
94 }
95 ) => {
96 $($attrs)*
97 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
98 $v enum $BitFlags {
99 $($entries)*
100 }
101 };
102
103 // Exit rule including TryFrom
104 (@make_enum
105 name: $BitFlags:ident,
106 {
107 $v:vis
108 attrs: [$($attrs:tt)*],
109 entries: [$($entries:tt)*],
110 from_type: $repr:path,
111 try_froms: [$($try_froms:tt)*]
112 }
113 ) => {
114 $($attrs)*
115 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
116 $v enum $BitFlags {
117 $($entries)*
118 }
119 impl ::std::convert::TryFrom<$repr> for $BitFlags {
120 type Error = $crate::Error;
121 #[allow(unused_doc_comments)]
122 fn try_from(x: $repr) -> $crate::Result<Self> {
123 match x {
124 $($try_froms)*
125 _ => Err($crate::Error::EINVAL)
126 }
127 }
128 }
129 };
130
131 // Done accumulating.
132 (@accumulate_entries
133 name: $BitFlags:ident,
134 {
135 $v:vis
136 attrs: $attrs:tt,
137 },
138 $entries:tt,
139 $try_froms:tt;
140 ) => {
141 libc_enum! {
142 @make_enum
143 name: $BitFlags,
144 {
145 $v
146 attrs: $attrs,
147 entries: $entries,
148 }
149 }
150 };
151
152 // Done accumulating and want TryFrom
153 (@accumulate_entries
154 name: $BitFlags:ident,
155 {
156 $v:vis
157 attrs: $attrs:tt,
158 from_type: $repr:path,
159 },
160 $entries:tt,
161 $try_froms:tt;
162 ) => {
163 libc_enum! {
164 @make_enum
165 name: $BitFlags,
166 {
167 $v
168 attrs: $attrs,
169 entries: $entries,
170 from_type: $repr,
171 try_froms: $try_froms
172 }
173 }
174 };
175
176 // Munch an attr.
177 (@accumulate_entries
178 name: $BitFlags:ident,
179 $prefix:tt,
180 [$($entries:tt)*],
181 [$($try_froms:tt)*];
182 #[$attr:meta] $($tail:tt)*
183 ) => {
184 libc_enum! {
185 @accumulate_entries
186 name: $BitFlags,
187 $prefix,
188 [
189 $($entries)*
190 #[$attr]
191 ],
192 [
193 $($try_froms)*
194 #[$attr]
195 ];
196 $($tail)*
197 }
198 };
199
200 // Munch last ident if not followed by a comma.
201 (@accumulate_entries
202 name: $BitFlags:ident,
203 $prefix:tt,
204 [$($entries:tt)*],
205 [$($try_froms:tt)*];
206 $entry:ident
207 ) => {
208 libc_enum! {
209 @accumulate_entries
210 name: $BitFlags,
211 $prefix,
212 [
213 $($entries)*
214 $entry = libc::$entry,
215 ],
216 [
217 $($try_froms)*
218 libc::$entry => Ok($BitFlags::$entry),
219 ];
220 }
221 };
222
223 // Munch an ident; covers terminating comma case.
224 (@accumulate_entries
225 name: $BitFlags:ident,
226 $prefix:tt,
227 [$($entries:tt)*],
228 [$($try_froms:tt)*];
229 $entry:ident,
230 $($tail:tt)*
231 ) => {
232 libc_enum! {
233 @accumulate_entries
234 name: $BitFlags,
235 $prefix,
236 [
237 $($entries)*
238 $entry = libc::$entry,
239 ],
240 [
241 $($try_froms)*
242 libc::$entry => Ok($BitFlags::$entry),
243 ];
244 $($tail)*
245 }
246 };
247
248 // Munch an ident and cast it to the given type; covers terminating comma.
249 (@accumulate_entries
250 name: $BitFlags:ident,
251 $prefix:tt,
252 [$($entries:tt)*],
253 [$($try_froms:tt)*];
254 $entry:ident as $ty:ty,
255 $($tail:tt)*
256 ) => {
257 libc_enum! {
258 @accumulate_entries
259 name: $BitFlags,
260 $prefix,
261 [
262 $($entries)*
263 $entry = libc::$entry as $ty,
264 ],
265 [
266 $($try_froms)*
267 libc::$entry as $ty => Ok($BitFlags::$entry),
268 ];
269 $($tail)*
270 }
271 };
272
273 // Entry rule.
274 (
275 $(#[$attr:meta])*
276 $v:vis enum $BitFlags:ident {
277 $($vals:tt)*
278 }
279 ) => {
280 libc_enum! {
281 @accumulate_entries
282 name: $BitFlags,
283 {
284 $v
285 attrs: [$(#[$attr])*],
286 },
287 [],
288 [];
289 $($vals)*
290 }
291 };
292
293 // Entry rule including TryFrom
294 (
295 $(#[$attr:meta])*
296 $v:vis enum $BitFlags:ident {
297 $($vals:tt)*
298 }
299 impl TryFrom<$repr:path>
300 ) => {
301 libc_enum! {
302 @accumulate_entries
303 name: $BitFlags,
304 {
305 $v
306 attrs: [$(#[$attr])*],
307 from_type: $repr,
308 },
309 [],
310 [];
311 $($vals)*
312 }
313 };
314}