Course contentsShow
← Rust
Lesson 1702 of 1,91015. Performance and Architectural EngineeringFree lesson

Compact Representation with Bitfields

Use bitwise manipulation to pack multiple boolean flags into a single byte.

In this lesson, you will learn how to optimize memory usage by packing multiple boolean flags into a single byte using bitwise manipulation.

The Cost of Booleans

In Rust, a bool occupies one full byte of memory to ensure that every addressable value has a unique memory location. If you have a struct containing eight distinct flags—like is_active, is_admin, is_readonly, and so on—Rust will allocate 8 bytes. For high-performance systems or massive collections, this overhead adds up quickly.

Bitwise Packing

Instead of using eight bytes, we can use a single u8 (an unsigned 8-bit integer) and treat each individual bit as a flag. By using the bitwise OR (|) operator to set a flag and the bitwise AND (&) combined with the NOT (!) operator to clear it, we gain granular control over the data.

Consider this implementation:

struct Permissions(u8);

impl Permissions {
    const READ: u8 = 1 << 0;  // 00000001
    const WRITE: u8 = 1 << 1; // 00000010
    const EXEC: u8 = 1 << 2;  // 00000100

    fn set_read(&mut self) { self.0 |= Self::READ; }
    fn is_read(&self) -> bool { (self.0 & Self::READ) != 0 }
    fn clear_read(&mut self) { self.0 &= !Self::READ; }
}

How It Works

  • The Bit Mask: We define constants using the bit-shift operator (1 << n). This creates a value where only the n-th bit is set to 1.
  • Setting: The |= operator forces a specific bit to 1 without affecting other bits.
  • Checking: The & operator masks the byte. If the result is non-zero, the flag is set.
  • Clearing: The !Self::READ creates a mask where every bit except the one we want to clear is 1. Applying & ensures the target bit becomes 0 while preserving the state of all other flags.

By using this technique, we reduce the memory footprint by 8x for boolean collections, significantly improving cache locality when processing thousands of instances. This is a common pattern in low-level drivers, protocol parsers, and game engines where every byte saved increases the system's overall throughput.

Key Takeaway: Bitwise manipulation allows you to trade a small amount of CPU overhead for a significant reduction in memory footprint by treating individual bits as boolean storage.