Skip to content

Commit 9b0da97

Browse files
committed
Add libc_bitflags convenience macro
We define many bitflags types with values from the libc crate. Currently these look like this: bitflags!{ flags ProtFlags: libc::c_int { const PROT_NONE = libc::PROT_NONE, const PROT_READ = libc::PROT_READ, const PROT_WRITE = libc::PROT_WRITE, const PROT_EXEC = libc::PROT_EXEC, #[cfg(any(target_os = "linux", target_os = "android"))] const PROT_GROWSDOWN = libc::PROT_GROWSDOWN, #[cfg(any(target_os = "linux", target_os = "android"))] const PROT_GROWSUP = libc::PROT_GROWSUP, } } There's some repetition which is tedious. With the new macro, the above can instead be written libc_bitflags!{ flags ProtFlags: libc::c_int { PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC, #[cfg(any(target_os = "linux", target_os = "android"))] PROT_GROWSDOWN, #[cfg(any(target_os = "linux", target_os = "android"))] PROT_GROWSUP, } } Thanks to Daniel Keep for the Little Book of Rust Macros, and for helping with this macro. Refs nix-rust#264
1 parent 97157b4 commit 9b0da97

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ extern crate cfg_if;
1919
#[cfg(test)]
2020
extern crate nix_test as nixtest;
2121

22+
#[macro_use] mod macros;
23+
2224
// In rust 1.8+ this should be `pub extern crate libc` but prior
2325
// to https://github.com/rust-lang/rust/issues/26775 being resolved
2426
// it is necessary to get a little creative.

src/macros.rs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/// The `libc_bitflags!` macro helps with a common use case of defining bitflags with values from
2+
/// the libc crate. It is used the same way as the `bitflags!` macro, except that only the name of
3+
/// the flag value has to be given.
4+
///
5+
/// The `libc` crate must be in scope with the name `libc`.
6+
///
7+
/// # Example
8+
/// ```
9+
/// # #[macro_use] extern crate nix;
10+
/// # #[macro_use] extern crate bitflags;
11+
/// extern crate libc;
12+
/// # fn main() {}
13+
///
14+
/// libc_bitflags!{
15+
/// flags ProtFlags: libc::c_int {
16+
/// PROT_NONE,
17+
/// PROT_READ,
18+
/// PROT_WRITE,
19+
/// PROT_EXEC,
20+
/// #[cfg(any(target_os = "linux", target_os = "android"))]
21+
/// PROT_GROWSDOWN,
22+
/// #[cfg(any(target_os = "linux", target_os = "android"))]
23+
/// PROT_GROWSUP,
24+
/// }
25+
/// }
26+
/// ```
27+
#[macro_export]
28+
macro_rules! libc_bitflags {
29+
// (non-pub) Exit rule.
30+
(@call_bitflags
31+
{
32+
name: $BitFlags:ident,
33+
type: $T:ty,
34+
attrs: [$($attrs:tt)*],
35+
flags: [$($flags:tt)*],
36+
}
37+
) => {
38+
bitflags! {
39+
$($attrs)*
40+
flags $BitFlags: $T {
41+
$($flags)*
42+
}
43+
}
44+
};
45+
46+
// (pub) Exit rule.
47+
(@call_bitflags
48+
{
49+
pub,
50+
name: $BitFlags:ident,
51+
type: $T:ty,
52+
attrs: [$($attrs:tt)*],
53+
flags: [$($flags:tt)*],
54+
}
55+
) => {
56+
bitflags! {
57+
$($attrs)*
58+
pub flags $BitFlags: $T {
59+
$($flags)*
60+
}
61+
}
62+
};
63+
64+
// (non-pub) Done accumulating.
65+
(@accumulate_flags
66+
{
67+
name: $BitFlags:ident,
68+
type: $T:ty,
69+
attrs: $attrs:tt,
70+
},
71+
$flags:tt;
72+
) => {
73+
libc_bitflags! {
74+
@call_bitflags
75+
{
76+
name: $BitFlags,
77+
type: $T,
78+
attrs: $attrs,
79+
flags: $flags,
80+
}
81+
}
82+
};
83+
84+
// (pub) Done accumulating.
85+
(@accumulate_flags
86+
{
87+
pub,
88+
name: $BitFlags:ident,
89+
type: $T:ty,
90+
attrs: $attrs:tt,
91+
},
92+
$flags:tt;
93+
) => {
94+
libc_bitflags! {
95+
@call_bitflags
96+
{
97+
pub,
98+
name: $BitFlags,
99+
type: $T,
100+
attrs: $attrs,
101+
flags: $flags,
102+
}
103+
}
104+
};
105+
106+
// Munch an attr.
107+
(@accumulate_flags
108+
$prefix:tt,
109+
[$($flags:tt)*];
110+
#[$attr:meta] $($tail:tt)*
111+
) => {
112+
libc_bitflags! {
113+
@accumulate_flags
114+
$prefix,
115+
[
116+
$($flags)*
117+
#[$attr]
118+
];
119+
$($tail)*
120+
}
121+
};
122+
123+
// Munch last ident if not followed by a comma.
124+
(@accumulate_flags
125+
$prefix:tt,
126+
[$($flags:tt)*];
127+
$flag:ident
128+
) => {
129+
libc_bitflags! {
130+
@accumulate_flags
131+
$prefix,
132+
[
133+
$($flags)*
134+
const $flag = libc::$flag,
135+
];
136+
}
137+
};
138+
139+
// Munch an ident; covers terminating comma case.
140+
(@accumulate_flags
141+
$prefix:tt,
142+
[$($flags:tt)*];
143+
$flag:ident, $($tail:tt)*
144+
) => {
145+
libc_bitflags! {
146+
@accumulate_flags
147+
$prefix,
148+
[
149+
$($flags)*
150+
const $flag = libc::$flag,
151+
];
152+
$($tail)*
153+
}
154+
};
155+
156+
// (non-pub) Entry rule.
157+
(
158+
$(#[$attr:meta])*
159+
flags $BitFlags:ident: $T:ty {
160+
$($vals:tt)*
161+
}
162+
) => {
163+
libc_bitflags! {
164+
@accumulate_flags
165+
{
166+
name: $BitFlags,
167+
type: $T,
168+
attrs: [$(#[$attr])*],
169+
},
170+
[];
171+
$($vals)*
172+
}
173+
};
174+
175+
// (pub) Entry rule.
176+
(
177+
$(#[$attr:meta])*
178+
pub flags $BitFlags:ident: $T:ty {
179+
$($vals:tt)*
180+
}
181+
) => {
182+
libc_bitflags! {
183+
@accumulate_flags
184+
{
185+
pub,
186+
name: $BitFlags,
187+
type: $T,
188+
attrs: [$(#[$attr])*],
189+
},
190+
[];
191+
$($vals)*
192+
}
193+
};
194+
}

0 commit comments

Comments
 (0)