Endian-Aware Binary Reader
Parse and build big-endian length-prefixed frames with a version byte, flags, checksum, and explicit truncation errors.
Code
#[derive(Debug, PartialEq)]
struct Frame {
version: u8,
flags: u16,
length: u32,
payload: Vec<u8>,
}
const HEADER_LEN: usize = 8;
fn simple_sum(payload: &[u8]) -> u8 {
payload
.iter()
.fold(0u8, |accumulator, byte| accumulator.wrapping_add(*byte))
}
fn parse_frame(bytes: &[u8]) -> Result<Frame, String> {
if bytes.len() < HEADER_LEN {
return Err(format!(
"need {HEADER_LEN} header bytes, got {}",
bytes.len()
));
}
let version = bytes[0];
let flags = u16::from_be_bytes([bytes[1], bytes[2]]);
let length = u32::from_be_bytes([bytes[3], bytes[4], bytes[5], bytes[6]]);
let checksum = bytes[7];
if version != 1 {
return Err(format!("unsupported version {version}"));
}
let end = HEADER_LEN + length as usize;
if bytes.len() < end {
return Err(format!("truncated payload: need {end} bytes"));
}
let payload = bytes[HEADER_LEN..end].to_vec();
if simple_sum(&payload) != checksum {
return Err("checksum mismatch".to_string());
}
Ok(Frame {
version,
flags,
length,
payload,
})
}
fn encode_frame(frame: &Frame) -> Vec<u8> {
let mut bytes = Vec::with_capacity(HEADER_LEN + frame.payload.len());
bytes.push(frame.version);
bytes.extend_from_slice(&frame.flags.to_be_bytes());
bytes.extend_from_slice(&frame.length.to_be_bytes());
bytes.push(simple_sum(&frame.payload));
bytes.extend_from_slice(&frame.payload);
bytes
}
fn main() {
let frame = Frame {
version: 1,
flags: 0b1010,
length: 5,
payload: b"hello".to_vec(),
};
let encoded = encode_frame(&frame);
println!("encoded: {:?}", encoded);
println!("decoded: {:?}", parse_frame(&encoded));
println!(
"truncated: {}",
parse_frame(&encoded[..encoded.len() - 2]).is_err()
);
let mut corrupted = encoded.clone();
corrupted[HEADER_LEN] ^= 0xff;
println!("checksum error: {:?}", parse_frame(&corrupted).unwrap_err());
}Report a problem with this exampleOpens a pre-filled issue on GitHub.