Steve Lau
Steve Lau

Reputation: 1023

Strange struct definition from crate nix

I just encountered this weird struct definition, it is in fcntl.rs from the crate nix.

pub struct OFlag: c_int {
    /// Mask for the access mode of the file.
    O_ACCMODE; 

    // other fields are omitted.
}

A normal struct in my perspective will be something like this:

struct Person{
    name: String,
    age: u8,
}

So, here are my doubts:

  1. what is OFlag: c_int?

    c_int is an type alias of i32. pub type c_int = i32;

  2. Why don't its fields have any type annotation?

My surmise is that OFlag is of type c_int, and the fields are something similar to enum's fields.(compliant to the open syscall function signature int open(const char *pathname, int flags, mode_t mode) ) But this is just my guesswork, an explanation citing rust official doc would be appreciated.

Upvotes: 1

Views: 152

Answers (2)

Akida
Akida

Reputation: 1116

If you look at the file you can see that the code inside the macro libc_bitflags!. The definition of the macro is here. There you can see that the macro ::bitflags::bitflags! is called and that libc_bitflags almost redirects the full input to bitflags. You can read more about that crate here.

Now to your questions:

  • OFlag will be after macro expansion a struct with a single attribute which is of type c_int:
pub struct OFlag {
    bits: c_int,
}
  • The fields don't need a type because they won't exist anymore in the expanded code (after the macro was run). The bits are of the "type of the struct" so in your case c_int. The fields will be converted to associated constants:
impl OFlag {
    pub const O_ACCMODE = Self { bits: libc::O_ACCMODE };
}

You can create an expansion of an example in the playground (Tools -> Expand macros)

Upvotes: 1

Sven Marnach
Sven Marnach

Reputation: 602115

The code you quoted is not valid Rust code on its own. It's code that gets passed to an internal macro of the nix crate called libc_bitflags!(). This macro takes the quoted code as input and transforms it into valid Rust code.

The libc_bitflags!() macro is a simple wrapper around the bitflags!() macro from the bitflags crate. The wrapper simplifies creating bitflags structs that take all their values from constants defined in the libc crate. For example this invocation

libc_bitflags!{
    pub struct ProtFlags: libc::c_int {
        PROT_NONE;
        PROT_READ;
        PROT_WRITE;
        PROT_EXEC;
    }
}

gets expanded to

bitflags!{
    pub struct 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;
    }
}

which in turn will be expanded to Rust code by the bitflags!() macro. The libc::c_int type is used as the type of the bits field of the resulting struct. The constants inside will become associated constants of the resulting struct. See the documentation of the bitflags crate for further details.

Upvotes: 3

Related Questions