First off, someone has to ask this: why not a custom derive?
#[derive(BitField)]
#[bitfield(present(unsigned, 0),
page_size(unsigned, 3, 5),
address(unsigned, 16, 46),
other(signed, 60, 63))]
struct MyFlags(u64);
Expands to:
struct MyFlags(u64);
impl MyFlags {
fn present(&self) -> bool /* or u8 */ {
self.0 >> 0 & 0x01 != 0
}
fn set_present(&mut self, bit: bool /* or u8 */) {
self.0 = self.0 & !0x01 | (bit as u64) << 0
}
fn page_size(&self) -> u8 {
self.0 >> 3 & 0x07
}
fn set_page_size(&mut self, bits: u8) {
self.0 = self.0 & !(0x07 << 3) | (bits & 0x7 << 3) // truncation is just an example, more on this later
}
// etc.
}
You canât reasonably take the address of the field anyway, so using a function is not a limitation compared to a direct field access.
If, however, bitfield types are to be added to the language, I think at this point (based on the proposal) they are so fundamentally different from regular structs that they should be a separate kind of type altogether. If field âtypesâ donât really correspond to types anymore, if their address canât be taken, if the syntax is generally just very different from structs, if the bit-typed fields arenât allowed to be mixed with regular fields, then why should we forcibly try to unify the two concepts?
That should probably require a stronger condition (e.g. the existence of all identically-named and identically-typed fields lying on the exact same bit positions). If you just allow casting one to another based purely on the predicate that they have the same size, then people will be free to cast completely unrelated bitfields, which seems like a huge source of errors and doesnât seem to have its place in a strictly-typed language where there are (rightfully) no implicit integer coercions.
For a fallible operation, typically returning Result is the right default choice. Again, second-guessing the user is Badâą, and just truncating the bitfield sounds pretty much like silently second-guessing the user. Perceived (or even real) âergonomicsâ should not take precedence over correctness. Another advantage of the derive-based approach is that the setter is a real function which has no problem of returning a value.
By the way, assigning a dynamically incorrect value would be impossible with the introduction of arbitrary-bit-width integers, but if we donât have them, then I donât really see the value in a special bitfield type because then assigning dynamically incorrect values to its fields is still possible, ie. itâs not an improvement over a getter-and-setter-with-uN-or-iN-based approach.