use rns_core::constants::HEADER_MINSIZE;
const FLAG: u8 = 0x7E;
const ESC: u8 = 0x7D;
const ESC_MASK: u8 = 0x20;
pub fn escape(data: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(data.len());
for &b in data {
match b {
ESC => {
out.push(ESC);
out.push(ESC ^ ESC_MASK);
}
FLAG => {
out.push(ESC);
out.push(FLAG ^ ESC_MASK);
}
_ => out.push(b),
}
}
out
}
pub fn frame(data: &[u8]) -> Vec<u8> {
let escaped = escape(data);
let mut out = Vec::with_capacity(escaped.len() + 2);
out.push(FLAG);
out.extend_from_slice(&escaped);
out.push(FLAG);
out
}
fn unescape(data: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(data.len());
let mut i = 0;
while i < data.len() {
if data[i] == ESC && i + 1 < data.len() {
out.push(data[i + 1] ^ ESC_MASK);
i += 2;
} else {
out.push(data[i]);
i += 1;
}
}
out
}
pub struct Decoder {
buffer: Vec<u8>,
}
impl Decoder {
pub fn new() -> Self {
Decoder { buffer: Vec::new() }
}
pub fn feed(&mut self, chunk: &[u8]) -> Vec<Vec<u8>> {
self.buffer.extend_from_slice(chunk);
let mut frames = Vec::new();
loop {
let start = match self.buffer.iter().position(|&b| b == FLAG) {
Some(pos) => pos,
None => {
self.buffer.clear();
break;
}
};
if start > 0 {
self.buffer.drain(..start);
}
let end = match self.buffer[1..].iter().position(|&b| b == FLAG) {
Some(pos) => pos + 1, None => break, };
let between = &self.buffer[1..end];
let unescaped = unescape(between);
if unescaped.len() >= HEADER_MINSIZE {
frames.push(unescaped);
}
self.buffer.drain(..end);
}
frames
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn escape_passthrough() {
let data = b"hello world";
assert_eq!(escape(data), data.to_vec());
}
#[test]
fn escape_flag() {
assert_eq!(escape(&[FLAG]), vec![ESC, FLAG ^ ESC_MASK]);
assert_eq!(escape(&[0x7E]), vec![0x7D, 0x5E]);
}
#[test]
fn escape_esc() {
assert_eq!(escape(&[ESC]), vec![ESC, ESC ^ ESC_MASK]);
assert_eq!(escape(&[0x7D]), vec![0x7D, 0x5D]);
}
#[test]
fn escape_mixed() {
let data = [0x01, FLAG, 0x02, ESC, 0x03];
let expected = vec![0x01, ESC, FLAG ^ ESC_MASK, 0x02, ESC, ESC ^ ESC_MASK, 0x03];
assert_eq!(escape(&data), expected);
}
#[test]
fn frame_structure() {
let data = b"test";
let framed = frame(data);
assert_eq!(framed[0], FLAG);
assert_eq!(*framed.last().unwrap(), FLAG);
assert_eq!(&framed[1..framed.len() - 1], &escape(data));
}
#[test]
fn roundtrip_all_bytes() {
let data: Vec<u8> = (0..=255).collect();
let framed = frame(&data);
let mut decoder = Decoder::new();
let frames = decoder.feed(&framed);
assert_eq!(frames.len(), 1);
assert_eq!(frames[0], data);
}
#[test]
fn decoder_single_frame() {
let data: Vec<u8> = (0..32).collect();
let framed = frame(&data);
let mut decoder = Decoder::new();
let frames = decoder.feed(&framed);
assert_eq!(frames.len(), 1);
assert_eq!(frames[0], data);
}
#[test]
fn decoder_two_frames_one_chunk() {
let data1: Vec<u8> = (0..24).collect();
let data2: Vec<u8> = (100..130).collect();
let mut combined = frame(&data1);
let framed2 = frame(&data2);
combined.extend_from_slice(&framed2[1..]);
let mut decoder = Decoder::new();
let frames = decoder.feed(&combined);
assert_eq!(frames.len(), 2);
assert_eq!(frames[0], data1);
assert_eq!(frames[1], data2);
}
#[test]
fn decoder_split_frame() {
let data: Vec<u8> = (0..32).collect();
let framed = frame(&data);
let mid = framed.len() / 2;
let mut decoder = Decoder::new();
let frames1 = decoder.feed(&framed[..mid]);
assert_eq!(frames1.len(), 0);
let frames2 = decoder.feed(&framed[mid..]);
assert_eq!(frames2.len(), 1);
assert_eq!(frames2[0], data);
}
#[test]
fn decoder_drops_short() {
let data = vec![0x01, 0x02, 0x03]; let framed = frame(&data);
let mut decoder = Decoder::new();
let frames = decoder.feed(&framed);
assert_eq!(frames.len(), 0); }
}