pub const START1: u8 = 0x94;
pub const START2: u8 = 0xc3;
pub const MAX_PAYLOAD: usize = 512;
pub fn encode(payload: &[u8]) -> Vec<u8> {
assert!(payload.len() <= MAX_PAYLOAD, "payload exceeds MAX_PAYLOAD");
let mut out = Vec::with_capacity(4 + payload.len());
out.push(START1);
out.push(START2);
out.extend_from_slice(&(payload.len() as u16).to_be_bytes());
out.extend_from_slice(payload);
out
}
pub struct Deframer {
buf: Vec<u8>,
}
impl Deframer {
pub fn new() -> Self {
Deframer { buf: Vec::new() }
}
pub fn push(&mut self, bytes: &[u8], out: &mut Vec<Vec<u8>>) {
self.buf.extend_from_slice(bytes);
loop {
let Some(start) = find_magic(&self.buf) else {
if self.buf.last() == Some(&START1) {
let last = self.buf.len() - 1;
self.buf.drain(..last);
} else {
self.buf.clear();
}
return;
};
if start > 0 {
self.buf.drain(..start);
}
if self.buf.len() < 4 {
return;
}
let len = u16::from_be_bytes([self.buf[2], self.buf[3]]) as usize;
if len > MAX_PAYLOAD {
self.buf.drain(..2);
continue;
}
if self.buf.len() < 4 + len {
return; }
out.push(self.buf[4..4 + len].to_vec());
self.buf.drain(..4 + len);
}
}
}
impl Default for Deframer {
fn default() -> Self {
Self::new()
}
}
fn find_magic(buf: &[u8]) -> Option<usize> {
buf.windows(2).position(|w| w == [START1, START2])
}
#[cfg(test)]
mod tests {
use super::*;
fn deframe_all(d: &mut Deframer, bytes: &[u8]) -> Vec<Vec<u8>> {
let mut out = Vec::new();
d.push(bytes, &mut out);
out
}
#[test]
fn round_trips_one_frame() {
let payload = b"\x08\x01\x12\x03abc";
let wire = encode(payload);
assert_eq!(&wire[..2], &[START1, START2]);
assert_eq!(&wire[2..4], &(payload.len() as u16).to_be_bytes());
let mut d = Deframer::new();
assert_eq!(deframe_all(&mut d, &wire), vec![payload.to_vec()]);
}
#[test]
fn skips_leading_debug_text_before_a_frame() {
let mut wire = b"INFO some log line\r\n".to_vec();
wire.extend_from_slice(&encode(b"payload here"));
let mut d = Deframer::new();
assert_eq!(deframe_all(&mut d, &wire), vec![b"payload here".to_vec()]);
}
#[test]
fn reassembles_across_chunked_reads() {
let wire = encode(&vec![0xAB; 300]);
let mut d = Deframer::new();
let mut out = Vec::new();
for chunk in wire.chunks(17) {
d.push(chunk, &mut out);
}
assert_eq!(out, vec![vec![0xAB; 300]]);
}
#[test]
fn back_to_back_frames() {
let mut wire = encode(b"one");
wire.extend_from_slice(&encode(b"two"));
let mut d = Deframer::new();
assert_eq!(
deframe_all(&mut d, &wire),
vec![b"one".to_vec(), b"two".to_vec()]
);
}
#[test]
fn a_false_magic_with_huge_length_is_resynced_past() {
let mut wire = vec![START1, START2, 0xFF, 0xFF, 0x00];
wire.extend_from_slice(&encode(b"real"));
let mut d = Deframer::new();
assert_eq!(deframe_all(&mut d, &wire), vec![b"real".to_vec()]);
}
#[test]
fn a_split_magic_at_the_buffer_end_is_held() {
let mut d = Deframer::new();
assert!(deframe_all(&mut d, &[0x00, START1]).is_empty());
let mut out = Vec::new();
d.push(&[START2, 0x00, 0x02, b'h', b'i'], &mut out);
assert_eq!(out, vec![b"hi".to_vec()]);
}
}