use super::compression::DecodeError;
use varinteger as varint;
pub fn encode(buf: impl AsRef<[u8]>) -> Vec<u8> {
let (enc, _) = encode_with_offset(&buf, 0);
enc
}
pub fn encode_with_offset(buf: impl AsRef<[u8]>, offset: usize) -> (Vec<u8>, usize) {
let buf = buf.as_ref();
let mut len = 0u64;
let mut contiguous = false;
let mut prev_bits = 0;
let mut noncontiguous_bits = Vec::new();
let mut enc = Vec::with_capacity(encode_len_with_offset(buf, offset));
for (i, byte) in buf[offset..].iter().enumerate() {
if contiguous && *byte == prev_bits {
len += 1;
continue;
} else if contiguous {
write_contiguous(&mut enc, len, prev_bits);
}
if *byte == 0 || *byte == 255 {
if !contiguous && i > offset {
write_noncontiguous(&mut enc, &mut noncontiguous_bits);
}
len = 1;
prev_bits = *byte;
contiguous = true;
} else if !contiguous {
noncontiguous_bits.push(*byte);
} else {
contiguous = false;
noncontiguous_bits.push(*byte);
}
}
if contiguous {
write_contiguous(&mut enc, len, prev_bits);
} else {
write_noncontiguous(&mut enc, &mut noncontiguous_bits);
}
(enc, buf.len() - offset)
}
fn write_contiguous(enc: &mut Vec<u8>, mut len: u64, prev_bits: u8) {
len <<= 2;
len += 1;
if prev_bits == 255 {
len += 2;
}
let mut varint = vec![0u8; varint::length(len)];
varint::encode(len, &mut varint);
enc.append(&mut varint);
}
fn write_noncontiguous(enc: &mut Vec<u8>, noncontiguous_bits: &mut Vec<u8>) {
let mut len = noncontiguous_bits.len() as u64;
len <<= 1;
let mut varint = vec![0u8; varint::length(len)];
varint::encode(len, &mut varint);
enc.append(&mut varint);
enc.append(noncontiguous_bits);
}
pub fn encode_len_with_offset(buf: impl AsRef<[u8]>, offset: usize) -> usize {
let buf = buf.as_ref();
let mut len = 0u64;
let mut partial_len = 0u64;
let mut contiguous = false;
let mut prev_bits = 0;
for (i, byte) in buf[offset..].iter().enumerate() {
if contiguous && *byte == prev_bits {
partial_len += 1;
continue;
} else if contiguous {
len += varint::length(partial_len << 2) as u64;
}
if *byte == 0 || *byte == 255 {
if !contiguous && i > offset {
len += partial_len;
len += varint::length(partial_len << 1) as u64;
}
partial_len = 1;
prev_bits = *byte;
contiguous = true;
} else if !contiguous {
partial_len += 1;
} else {
partial_len = 1;
contiguous = false;
}
}
if contiguous {
len += varint::length(partial_len << 2) as u64;
} else {
len += partial_len;
len += varint::length(partial_len << 1) as u64;
}
len as usize
}
pub fn decode(buf: impl AsRef<[u8]>) -> Result<Vec<u8>, DecodeError> {
let (bitfield, _) = decode_with_offset(&buf, 0)?;
Ok(bitfield)
}
pub fn decode_with_offset(
buf: impl AsRef<[u8]>,
mut offset: usize,
) -> Result<(Vec<u8>, usize), DecodeError> {
let buf = buf.as_ref();
let mut bitfield = vec![0; decode_len_with_offset(buf, offset)?];
let mut next = 0u64;
let mut ptr = 0;
while offset < buf.len() {
offset += varint::decode_with_offset(buf, offset, &mut next);
let repeat = next & 1;
let len = if repeat > 0 {
(next >> 2) as usize
} else {
(next >> 1) as usize
};
if repeat > 0 {
if next & 2 > 0 {
for i in 0..len {
bitfield[ptr + i] = 255;
}
}
} else {
bitfield[ptr..(len + ptr)].clone_from_slice(&buf[offset..(len + offset)]);
offset += len;
}
ptr += len;
}
Ok((bitfield, buf.len() - offset))
}
pub fn decode_len(buf: impl AsRef<[u8]>) -> Result<usize, DecodeError> {
decode_len_with_offset(&buf, 0)
}
pub fn decode_len_with_offset(
buf: impl AsRef<[u8]>,
mut offset: usize,
) -> Result<usize, DecodeError> {
let buf = buf.as_ref();
let mut len = 0;
let mut next = 0u64;
while offset < buf.len() {
offset += varint::decode_with_offset(buf, offset, &mut next);
let repeat = next & 1;
let slice = if repeat > 0 {
(next >> 2) as usize
} else {
(next >> 1) as usize
};
len += slice;
if repeat == 0 {
offset += slice;
}
}
if offset > buf.len() {
return Err(DecodeError::InvalidRLEBitfield {
offset,
len: buf.len(),
});
}
Ok(len)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_should_encode_decode() {
let mut bits: Vec<u8> = vec![0; 16];
bits[8] = 0b00000001;
let enc = encode(&bits);
assert_eq!(enc.len(), 4);
let res = decode(enc).unwrap();
assert_eq!(res[8], 0b00000001);
assert_eq!(res, bits);
}
#[test]
fn test_encode() {
let bitfield = vec![255, 255, 85, 84, 0, 0, 0, 183];
let enc = encode(&bitfield);
let correct = vec![11, 4, 85, 84, 13, 2, 183];
assert_eq!(enc.len(), correct.len());
assert_eq!(enc, correct);
}
#[test]
fn test_decode_len() {
let enc = [11, 4, 85, 84, 13, 2, 183];
assert_eq!(8, decode_len(enc).unwrap());
}
#[test]
fn test_decode() {
let enc = [11, 4, 85, 84, 13, 2, 183];
let res = decode(enc).unwrap();
let correct = vec![255, 255, 85, 84, 0, 0, 0, 183];
assert_eq!(res, correct);
}
#[test]
fn test_not_power_of_two() {
let deflated = encode(vec![255, 255, 255, 240]);
let inflated = decode(deflated).unwrap();
assert_eq!(inflated, vec![255, 255, 255, 240]);
}
#[test]
fn test_encodes_empty_bitfield() {
assert_eq!(decode(encode(vec![])).unwrap(), vec![]);
assert_eq!(decode(vec![]).unwrap(), vec![]);
assert_eq!(decode(vec![0]).unwrap(), vec![]);
assert_eq!(encode(vec![]), vec![0]);
}
#[test]
fn test_does_not_trims_remaining_bytes() {
let mut bitfield = vec![0; 1024];
bitfield[0] = 64;
assert_eq!(encode(&bitfield), vec![2, 64, 253, 31]);
}
}