const P0: u32 = 0b11_1111_1111_1111_1111_1111_1111; const P1: u32 = 0b10_1010_1010_1010_1101_0101_1011;
const P2: u32 = 0b11_0011_0011_0011_0110_0110_1101;
const P3: u32 = 0b11_1100_0011_1100_0111_1000_1110;
const P4: u32 = 0b11_1111_1100_0000_0111_1111_0000;
const P5: u32 = 0b11_1111_1111_1111_1000_0000_0000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Header {
len: u32,
}
impl Header {
pub fn new(len: u32) -> Header {
assert!(
len == len & 0x03_FF_FF_FFu32,
"length too big: {} > 2 ^ 26",
len
);
Header { len }
}
pub fn len(&self) -> u32 {
self.len
}
pub fn encode(&self) -> [u8; 4] {
let mut encoded = self.len;
encoded |= ((self.len & P0).count_ones() & 0b1) << 26;
encoded |= ((self.len & P1).count_ones() & 0b1) << 27;
encoded |= ((self.len & P2).count_ones() & 0b1) << 28;
encoded |= ((self.len & P3).count_ones() & 0b1) << 29;
encoded |= ((self.len & P4).count_ones() & 0b1) << 30;
encoded |= ((self.len & P5).count_ones() & 0b1) << 31;
u32::to_be_bytes(encoded)
}
pub fn decode(header: [u8; 4]) -> Header {
let encoded = u32::from_be_bytes(header);
fn xor(a: bool, b: bool) -> bool {
a && b || !a && !b
}
assert!(
xor(
(encoded & P0).count_ones() as u8 & 0b1 != 0,
encoded & (1 << 26) != 0
),
"parity 0 wrong: {:?}",
header
);
assert!(
xor(
(encoded & P1).count_ones() as u8 & 0b1 != 0,
encoded & (1 << 27) != 0
),
"parity 1 wrong: {:?}",
header
);
assert!(
xor(
(encoded & P2).count_ones() as u8 & 0b1 != 0,
encoded & (1 << 28) != 0
),
"parity 2 wrong: {:?}",
header
);
assert!(
xor(
(encoded & P3).count_ones() as u8 & 0b1 != 0,
encoded & (1 << 29) != 0
),
"parity 3 wrong: {:?}",
header
);
assert!(
xor(
(encoded & P4).count_ones() as u8 & 0b1 != 0,
encoded & (1 << 30) != 0
),
"parity 4 wrong: {:?}",
header
);
assert!(
xor(
(encoded & P5).count_ones() as u8 & 0b1 != 0,
encoded & (1 << 31) != 0
),
"parity 5 wrong: {:?}",
header
);
Header::new(encoded & 0x03_FF_FF_FFu32)
}
}
#[cfg(test)]
mod test {
use super::*;
fn lots_of_lengths() -> impl Iterator<Item = Header> {
(0..)
.map(|_| Header::new(rand::random::<u32>() & 0x03_FF_FF_FFu32))
.take(1_000_000)
}
#[test]
fn encode_length_ok() {
let lengths = lots_of_lengths();
for (_i, header) in lengths.enumerate() {
assert_eq!(header, Header::decode(header.encode()));
}
}
#[test]
#[should_panic]
fn encode_gibberish() {
let bad = *b"Asbt";
println!("{:?}", bad);
println!("{:?}", Header::decode(bad));
}
}