From b4c9f5bad14c3ce13edc2f72ef409e3397dc7f10 Mon Sep 17 00:00:00 2001 From: Kamal Marhubi Date: Tue, 15 Mar 2016 14:09:07 -0400 Subject: 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 https://github.com/nix-rust/nix/issues/264 --- src/lib.rs | 2 + src/macros.rs | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 src/macros.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index f3724ec3..fc35aac3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,8 @@ extern crate cfg_if; #[cfg(test)] extern crate nix_test as nixtest; +#[macro_use] mod macros; + // In rust 1.8+ this should be `pub extern crate libc` but prior // to https://github.com/rust-lang/rust/issues/26775 being resolved // it is necessary to get a little creative. diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 00000000..e6d58b10 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,188 @@ +/// The `libc_bitflags!` macro helps with a common use case of defining bitflags with values from +/// the libc crate. It is used the same way as the `bitflags!` macro, except that only the name of +/// the flag value has to be given. +/// +/// The `libc` crate must be in scope with the name `libc`. +/// +/// # Example +/// ``` +/// 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, +/// } +/// } +/// ``` +macro_rules! libc_bitflags { + // (non-pub) Exit rule. + (@call_bitflags + { + name: $BitFlags:ident, + type: $T:ty, + attrs: [$($attrs:tt)*], + flags: [$($flags:tt)*], + } + ) => { + bitflags! { + $($attrs)* + flags $BitFlags: $T { + $($flags)* + } + } + }; + + // (pub) Exit rule. + (@call_bitflags + { + pub, + name: $BitFlags:ident, + type: $T:ty, + attrs: [$($attrs:tt)*], + flags: [$($flags:tt)*], + } + ) => { + bitflags! { + $($attrs)* + pub flags $BitFlags: $T { + $($flags)* + } + } + }; + + // (non-pub) Done accumulating. + (@accumulate_flags + { + name: $BitFlags:ident, + type: $T:ty, + attrs: $attrs:tt, + }, + $flags:tt; + ) => { + libc_bitflags! { + @call_bitflags + { + name: $BitFlags, + type: $T, + attrs: $attrs, + flags: $flags, + } + } + }; + + // (pub) Done accumulating. + (@accumulate_flags + { + pub, + name: $BitFlags:ident, + type: $T:ty, + attrs: $attrs:tt, + }, + $flags:tt; + ) => { + libc_bitflags! { + @call_bitflags + { + pub, + name: $BitFlags, + type: $T, + attrs: $attrs, + flags: $flags, + } + } + }; + + // Munch an attr. + (@accumulate_flags + $prefix:tt, + [$($flags:tt)*]; + #[$attr:meta] $($tail:tt)* + ) => { + libc_bitflags! { + @accumulate_flags + $prefix, + [ + $($flags)* + #[$attr] + ]; + $($tail)* + } + }; + + // Munch last ident if not followed by a comma. + (@accumulate_flags + $prefix:tt, + [$($flags:tt)*]; + $flag:ident + ) => { + libc_bitflags! { + @accumulate_flags + $prefix, + [ + $($flags)* + const $flag = libc::$flag, + ]; + } + }; + + // Munch an ident; covers terminating comma case. + (@accumulate_flags + $prefix:tt, + [$($flags:tt)*]; + $flag:ident, $($tail:tt)* + ) => { + libc_bitflags! { + @accumulate_flags + $prefix, + [ + $($flags)* + const $flag = libc::$flag, + ]; + $($tail)* + } + }; + + // (non-pub) Entry rule. + ( + $(#[$attr:meta])* + flags $BitFlags:ident: $T:ty { + $($vals:tt)* + } + ) => { + libc_bitflags! { + @accumulate_flags + { + name: $BitFlags, + type: $T, + attrs: [$(#[$attr])*], + }, + []; + $($vals)* + } + }; + + // (pub) Entry rule. + ( + $(#[$attr:meta])* + pub flags $BitFlags:ident: $T:ty { + $($vals:tt)* + } + ) => { + libc_bitflags! { + @accumulate_flags + { + pub, + name: $BitFlags, + type: $T, + attrs: [$(#[$attr])*], + }, + []; + $($vals)* + } + }; +} -- cgit v1.2.3