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