4 ms·
About this section: > Unfortunately, as the ??? shows, the different output arrays have different lengths – a u16 would be 2 bytes and a u64 8 bytes – and so t
by ekimekim 5y ago
About this section:
> Unfortunately, as the ??? shows, the different output arrays have different lengths – a u16 would be 2 bytes and a u64 8 bytes – and so the Rust trait system at the time of this writing is (to my knowledge) not powerful enough to represent this trait as is.
It seems to me that this is possible using const generics.
If you define your EndianBytes like this:
trait EndianBytes<const N: usize> {
fn be_bytes(self) -> [u8; N];
fn le_bytes(self) -> [u8; N];
}
Then provide a concrete length with each impl:
impl EndianBytes<4> for u32 {
fn be_bytes(self) -> [u8; 4] {
self.to_be_bytes()
}
fn le_bytes(self) -> [u8; 4] {
self.to_le_bytes()
}
}
(I've renamed their methods to avoid conflicting with u32::to_be_bytes to make it easier to read)
Then that allows you to use the EndianBytes type as long as you remain generic over both the value type and its length:
fn write<T: EndianBytes<N>, const N: usize>(val: T) {
println!("{:?}", val.be_bytes());
}
fn main() {
write(0x1234u16);
write(0x12345678u32);
}
This code (plus an impl for EndianBytes<2> for u16) works for me on 1.51 stable.
EDIT: I thought about doing this with an associated constant, ie:
trait EndianBytes {
const LENGTH: usize;
fn be_bytes(self) -> [u8; Self::LENGTH];
fn le_bytes(self) -> [u8; Self::LENGTH];
}
However it turns out that this kind of usage is not quite supported yet: https://github.com/rust-lang/rust/issues/60551 https://github.com/rust-lang/rust/issues/60551