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}