From b4c9f5bad14c3ce13edc2f72ef409e3397dc7f10 Mon Sep 17 00:00:00 2001
From: Kamal Marhubi <kamal@marhubi.com>
Date: Tue, 15 Mar 2016 14:09:07 -0400
Subject: [PATCH 1/2] 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
---
 CONVENTIONS.md |  26 ++++++-
 src/lib.rs     |   2 +
 src/macros.rs  | 188 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+), 3 deletions(-)
 create mode 100644 src/macros.rs

diff --git a/CONVENTIONS.md b/CONVENTIONS.md
index 068f1e458e..ba179a44a1 100644
--- a/CONVENTIONS.md
+++ b/CONVENTIONS.md
@@ -34,12 +34,32 @@ When creating newtypes, we use Rust's `CamelCase` type naming convention.
 
 ## Bitflags
 
-We represent sets of constants that are intended to be combined using bitwise
-operations as parameters to functions by types defined using the `bitflags!`
-macro from the [bitflags crate][bitflags].
+Many C functions have flags parameters that are combined from constants using
+bitwise operations. We represent the types of these parameters by types defined
+using our `libc_bitflags!` macro, which is a convenience wrapper around the
+`bitflags!` macro from the [bitflags crate][bitflags] that brings in the
+constant value from `libc`.
+
 We name the type for a set of constants whose element's names start with `FOO_`
 `FooFlags`.
 
+For example,
+
+```rust
+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,
+    }
+}
+```
+
 
 ## Enumerations
 
diff --git a/src/lib.rs b/src/lib.rs
index f3724ec3ed..fc35aac311 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 0000000000..e6d58b10d2
--- /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)*
+        }
+    };
+}

From 7038da088ae828d892ce46f778bf62f6aeb1f424 Mon Sep 17 00:00:00 2001
From: Kamal Marhubi <kamal@marhubi.com>
Date: Tue, 15 Mar 2016 14:14:39 -0400
Subject: [PATCH 2/2] mman: Use libc_bitflags macro for ProtFlags

This serves as an example use of the libc_bitflags macro.
---
 src/sys/mman.rs | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/sys/mman.rs b/src/sys/mman.rs
index a23526d622..5bc1c82d60 100644
--- a/src/sys/mman.rs
+++ b/src/sys/mman.rs
@@ -6,16 +6,16 @@ use std::os::unix::io::RawFd;
 
 pub use self::consts::*;
 
-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,
+libc_bitflags!{
+    flags ProtFlags: libc::c_int {
+        PROT_NONE,
+        PROT_READ,
+        PROT_WRITE,
+        PROT_EXEC,
         #[cfg(any(target_os = "linux", target_os = "android"))]
-        const PROT_GROWSDOWN = libc::PROT_GROWSDOWN,
+        PROT_GROWSDOWN,
         #[cfg(any(target_os = "linux", target_os = "android"))]
-        const PROT_GROWSUP   = libc::PROT_GROWSUP,
+        PROT_GROWSUP,
     }
 }