I'm writing a program that uses quite a few wierd integer types to hold odd size data.
Below is my current understanding of structs and how much data they take up. There isn't really a u3 or u7 type, just crates that provide structs wrapping the closest primitive but enforcing a lower limit.
struct Shape {
shape: u16,
width: u8,
height: u8,
weight: u8,
} // theoretically 48 bit
struct Shape {
/// Takes up 16 bits because it is just a struct wrapping a u16.
shape: u9,
width: u2,
height: u2,
weight: u3,
} // theoretically still 48 bit
This works, but it kind of sucks though. My understanding is that whilst struct sizes have to be a multiple of a byte, it is theoretically possible to "pack" these fields (that are not multiples of a byte) into two bytes instead of "padding" them into four.
Not a big deal, and I might be misunderstanding this, but it just seems wasteful to me, even on a machine with plenty of ram.
CPU registers can be accessed as byte(U8), word(U16), dword(U32) and U64.
Trying to force "in-between" bit count units would just slow things down and is a waste of effort.
If max value 255 or less use U8, if max value 65,535 or less use U16, etcetera.
(my question) Does Rust STRUCT support bit array.? If so, then you can have your second sample in a U16. Still slows things down a bit by "behind the scenes" code to get the values into a register.
It's not possible while also giving out &muts to them, though.
What this needs is a new feature often called "move-only fields" that would block getting references, thus allowing rust to run code when ever it's read or written, and thereby allowing more freedom for layout optimization.
This is not necessarily true. Yes, bit-packing and unpacking requires extra instructions, but on today’s computers, many instructions can execute in the time it takes to fetch a single piece of data from main memory (a cache miss). Therefore, in some applications, reducing the size of structs, even by explicit bit-packing and unpacking, can be beneficial by allowing more data to fit in cache at once.
There are two other posts pointing to crates commonly used for bit fields -- using those crates is how you do it. The std library doesn't have bit field APIs.
Well, as @jdahlstrom said, you can use a library, and that's what I would recommend if you have multiple structs or are not greatly familiar with bit manipulation.
But for a small case, doing it from scratch is “just” writing getters and setters:
Sure, but we are talking about a type's size. Take OP's struct, for example. All fields combined take up 5 bytes, but Shape has an alignment of 2. 5 is not a multiple of 2, so the compiler adds padding to increase its size to 6 bytes. This is what I wanted to highlight.
I was mostly just making a joke, but I believe the structures the OP was referring to getting rounded up to a byte were the u3 etc types, and those will surely always have equal size and alignment
Also be careful not to assume that the size must be a multiple of the alignment in other languages! I had "fun" with that recently...