Is there a one-bit value type in Rust?

I would like to know if there is a single bit structure in Rust. Not byte (8 bits), but a single bit (either 0, or 1). If yes, how can I use it?

The closest I've ever seen (whether in C or in Rust) is bitwise manipulations e.g. >>, &, | etc.
But even those operate on the bits of a value that's at least 1 byte wide i.e. at least a u8 or i8.
(update: as @mbrubeck points out below, the bool type is very likely what you'll want to use if it's about a single bit, and otherwise use the crates listed in his post).

At this point I'm not certain that current CPUs would even support manipulating loose bits in their load and store instruction equivalents.

2 Likes

There's no primitive one-bit type. The closest thing is bool, which conceptually represents a single bit, but physically it is represented as one byte in memory.

When you want to pack multiple one-bit values efficiently in memory (without using a full byte for each of them), you can use libraries like bitvec, bitflags, and packed_struct.

12 Likes

LLVM lets you define arbitrary-width integers so in theory Rust could have a single-bit value, but the smallest unit of memory modern processors can work with is the byte so in practice your single-bit value would take up 8 bits in memory.

C has a concept called the bitfield, but this is just syntactic sugar for bitwise manipulations.

It’s probably worth noting that, unlike some other languages with bool types, Rust guarantees that a boolean value is either 0x01 or 0x00, i.e. only the least-significant-bit is used, which potentially makes pretending that bool is a single bit much safer in some expressions.

https://doc.rust-lang.org/reference/types/boolean.html

3 Likes

However, Rust does not guarantee that the other bits in the underlying u8 are unused, thus providing a 7-bit niche for rustc's use. bool and option(bool) both encode in one byte, implying that the compiler is using those apparently-unused seven bits for other purposes.

3 Likes

Good point!

The compiler only uses those niche values when it is not actually a bool though. So for Option<bool>, you may see raw values for Some(false) = 0, Some(true) = 1, or None = 2 (not an exact guarantee). But if you're looking at a bool alone, or say dereferencing &bool, the whole byte will be only 0x00 or 0x01.

4 Likes

Here there is some post about bitfields required for feature Rust as it is a system programming language: Rust Roadmap 2021: Allowing for arbitrary size integer primitives | The subconscious mumblings of therealprof

It looks true especially for embedded programming where most MCU mode & I/O registers are bit-splitted, so embedded Rust requires at least C-like packed structures.

Also, we have also the ux crate but starts from two bits integers.

For the specific case of memory-mapped registers, using b3 or such types is probably never going to work, because you cannot have a "&VolatileCell" in Rust. The very concept is fundamentally broken and doesn't work. Use voladdress instead.

After you read or before you write the MMIO, though, yeah.

For regular memory, bitvec is wonderful. There's IIUC still a missing space for a "bitstruct" based off of bitvec and its techniques which, while not as integrated as a language addition would be, can still imho feel more integrated than other existing solutions.