modular-bitfield
modular-bitfield copied to clipboard
[Question] Polymorphic bitfileds
Thank you for the wonderful library.
I don't know how to name what I'm looking for, so I'm calling them polymorphic bitfields by analogy with a similar concept I've seen in SQL. The idea is that the bitfield has two parts: a type field, and a payload that we interpret differently depending on the type.
As a contrived but simple example, consider a u16
where the first bit is 0
if the remainder should be interpreted as a u15
and a 1
if the remainder should be interpreted as fiveu3
s.
Currently, I manage this behavior as follows:
#[derive(BitfieldSpecifier)]
#[bits = 1]
enum PayloadType {
TypeOne,
TypeTwo,
}
#[bitfield]
struct Data {
type_: PayloadType,
payload: B31,
}
#[bitfield(bits = 31)]
pub struct PackedTypeOne {
...
}
#[bitfield(bits = 31)]
pub struct PackedTypeTwo {
...
}
impl Data {
pub fn unwrap_as_type_one(&self) -> PackedTypeOne {
PackedTypeOne::from_bytes(self.payload().to_be_bytes())
}
pub fn unwrap_as_type_two(&self) -> PackedTypeTwo {
PackedTypeTwo::from_bytes(self.payload().to_be_bytes())
}
}
But this feels clumsy to me, as it seems that the caller can unwrap_as_type_one
even if the payload actually corresponds to TypeTwo
.
I read through the documentation for modular_bitfield
, and while I learned a lot of wonderful things about this library, I'm not sure how to best implement what I describe above. I would be grateful for any help you could provide.
First, this is less clumsy for the caller:
enum PackedType {
One(PackedTypeOne),
Two(PackedTypeTwo)
}
impl Data {
pub fn unwrap(&self) -> PackedType {
if matches!(self.type_(), TypeOne) {
PackedType(PackedTypeOne::from_bytes(self.payload().to_be_bytes()))
} else {
PackedType(PackedTypeTwo::from_bytes(self.payload().to_be_bytes()))
}
}
}
(Also see how this duplicates PayloadType
's variants)
Second, I basically have the same problem, thought about this a bit and I think the nicest semantics would be to use a normal rust enum:
#[bitfield(bits = 32)]
struct Data {
type_: B1, //or bool, or enum with 1 bit, edit: though as this is part of PackedType already, I think it should be private?
#[discriminant = type_]
payload: PackedType,
}
#[..?] //not sure
enum PackedType {
One(PackedTypeOne),
Two(PackedTypeTwo)
}
#[bitfield(bits = 31)]
pub struct PackedTypeOne { ... }
#[bitfield(bits = 31)]
pub struct PackedTypeTwo { ... }
with #[discriminant = ...]
being the field where we want to store the enums discriminant information.
How would this work low-level? I don't know.
PackedType
would then kind of be the "union" part of the tagged union, type_
would be the tag.