nix/
macros.rs

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(linux_android)]
31///         PROT_GROWSDOWN;
32///         #[cfg(linux_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(linux_android)]
93///         PROT_GROWSDOWN,
94///         #[cfg(linux_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}