nix/CONVENTIONS.md
Kamal Marhubi b4c9f5bad1 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
2016-03-16 11:59:03 -04:00

2.6 KiB

Conventions

In order to achieve our goal of wrapping libc code in idiomatic rust constructs with minimal performance overhead, we follow the following conventions.

Note that, thus far, not all the code follows these conventions and not all conventions we try to follow have been documented here. If you find an instance of either, feel free to remedy the flaw by opening a pull request with appropriate changes or additions.

libc constants, functions and structs

We do not define integer constants ourselves, but use or reexport them from the libc crate.

We use the functions exported from libc instead of writing our own extern declarations.

We use the struct definitions from libc internally instead of writing our own. If we want to add methods to a libc type, we use the newtype pattern. For example,

pub struct SigSet(libc::sigset_t);

impl SigSet {
    ...
}

When creating newtypes, we use Rust's CamelCase type naming convention.

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 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,

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

We represent sets of constants that are intended as mutually exclusive arguments to parameters of functions by enumerations.

Structures Initialized by libc Functions

Whenever we need to use a libc function to properly initialize a variable and said function allows us to use uninitialized memory, we use std::mem::uninitialized (or core::mem::uninitialized) when defining the variable. This allows us to avoid the overhead incurred by zeroing or otherwise initializing the variable.