use crate::{Bitstream, DecodeFailed, MAX_CHUNK_SIZE};
#[repr(u32)]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum WindowSize {
KB32 = 0x0000_8000,
KB64 = 0x0001_0000,
KB128 = 0x0002_0000,
KB256 = 0x0004_0000,
KB512 = 0x0008_0000,
MB1 = 0x0010_0000,
MB2 = 0x0020_0000,
MB4 = 0x0040_0000,
MB8 = 0x0080_0000,
MB16 = 0x0100_0000,
MB32 = 0x0200_0000,
}
pub struct Window {
pos: usize,
buffer: Box<[u8]>,
}
impl WindowSize {
pub(crate) fn position_slots(&self) -> usize {
use WindowSize::*;
match self {
KB32 => 30,
KB64 => 32,
KB128 => 34,
KB256 => 36,
KB512 => 38,
MB1 => 42,
MB2 => 50,
MB4 => 66,
MB8 => 98,
MB16 => 162,
MB32 => 290,
}
}
fn value(&self) -> usize {
*self as usize
}
pub(crate) fn create_buffer(&self) -> Window {
assert!(self.value() >= MAX_CHUNK_SIZE);
assert!(self.value().is_power_of_two());
Window {
pos: 0,
buffer: vec![0; self.value()].into_boxed_slice(),
}
}
}
impl Window {
fn advance(&mut self, delta: usize) {
self.pos += delta;
if self.pos >= self.buffer.len() {
self.pos -= self.buffer.len();
}
}
pub fn push(&mut self, value: u8) {
self.buffer[self.pos] = value;
self.advance(1);
}
pub fn copy_from_self(&mut self, offset: usize, length: usize) {
if offset <= self.pos && length <= offset && self.pos + length < self.buffer.len() {
let start = self.pos - offset;
self.buffer.copy_within(start..start + length, self.pos);
} else {
let mask = self.buffer.len() - 1;
for i in 0..length {
let dst = (self.pos + i) & mask;
let src = (self.buffer.len() + self.pos + i - offset) & mask;
self.buffer[dst] = self.buffer[src];
}
}
self.advance(length);
}
pub fn copy_from_bitstream(
&mut self,
bitstream: &mut Bitstream,
len: usize,
) -> Result<(), DecodeFailed> {
if len > self.buffer.len() {
return Err(DecodeFailed::WindowTooSmall);
}
if self.pos + len > self.buffer.len() {
let shift = self.pos + len - self.buffer.len();
self.pos -= shift;
self.buffer.copy_within(shift.., 0);
}
bitstream.read_raw(&mut self.buffer[self.pos..self.pos + len])?;
self.advance(len);
Ok(())
}
pub fn past_view(&mut self, len: usize) -> Result<&mut [u8], DecodeFailed> {
if len > MAX_CHUNK_SIZE {
return Err(DecodeFailed::ChunkTooLong);
}
if self.pos != 0 && len > self.pos {
let shift = len - self.pos;
self.advance(shift);
let tmp = self.buffer[self.buffer.len() - shift..].to_vec();
self.buffer.copy_within(0..self.buffer.len() - shift, shift);
self.buffer[..shift].copy_from_slice(&tmp);
}
let pos = if self.pos == 0 {
self.buffer.len()
} else {
self.pos
};
Ok(&mut self.buffer[pos - len..pos])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_push() {
let mut window = WindowSize::KB32.create_buffer();
window.push(1);
window.push(2);
window.push(3);
assert_eq!(window.pos, 3);
assert_eq!(&window.buffer[..3], &[1, 2, 3]);
assert!(window.buffer[3..].iter().all(|&x| x == 0));
}
#[test]
fn check_push_before_boundary() {
let mut window = WindowSize::KB32.create_buffer();
window.pos = window.buffer.len() - 1;
window.push(1);
assert_eq!(window.pos, 0);
}
#[test]
fn check_push_at_boundary() {
let mut window = WindowSize::KB32.create_buffer();
for _ in 0..((1 << 15) - 2) {
window.push(0);
}
window.push(1);
window.push(2);
window.push(3);
window.push(4);
assert_eq!(window.pos, 2);
assert_eq!(&window.buffer[window.buffer.len() - 2..], &[1, 2]);
assert_eq!(&window.buffer[..2], &[3, 4]);
assert!(window.buffer[2..window.buffer.len() - 2]
.iter()
.all(|&x| x == 0));
}
#[test]
fn check_copy_from_self() {
let mut window = WindowSize::KB32.create_buffer();
window.buffer[0] = 1;
window.buffer[1] = 2;
window.buffer[2] = 3;
window.pos = 3;
window.copy_from_self(3, 2);
assert_eq!(window.pos, 5);
assert_eq!(&window.buffer[..5], &[1, 2, 3, 1, 2]);
assert!(window.buffer[5..].iter().all(|&x| x == 0));
}
#[test]
fn check_copy_from_self_overlap() {
let mut window = WindowSize::KB32.create_buffer();
window.buffer[0] = 1;
window.buffer[1] = 2;
window.buffer[2] = 3;
window.pos = 3;
window.copy_from_self(2, 3);
assert_eq!(window.pos, 6);
assert_eq!(&window.buffer[..6], &[1, 2, 3, 2, 3, 2]);
assert!(window.buffer[6..].iter().all(|&x| x == 0));
}
#[test]
fn check_copy_at_boundary_from_self() {
let mut window = WindowSize::KB32.create_buffer();
window.buffer[window.buffer.len() - 3] = 1;
window.buffer[window.buffer.len() - 2] = 2;
window.pos = window.buffer.len() - 1;
window.copy_from_self(2, 2);
assert_eq!(window.pos, 1);
assert_eq!(window.buffer[0], 2);
assert_eq!(&window.buffer[window.buffer.len() - 3..], &[1, 2, 1]);
assert!(window.buffer[1..window.buffer.len() - 3]
.iter()
.all(|&x| x == 0));
}
#[test]
fn check_copy_from_self_before_boundary() {
let mut window = WindowSize::KB32.create_buffer();
window.buffer[window.buffer.len() - 4] = 1;
window.buffer[window.buffer.len() - 3] = 2;
window.pos = window.buffer.len() - 2;
window.copy_from_self(2, 2);
assert_eq!(window.pos, 0);
}
#[test]
fn check_copy_from_self_at_boundary() {
let mut window = WindowSize::KB32.create_buffer();
window.buffer[window.buffer.len() - 2] = 1;
window.buffer[window.buffer.len() - 1] = 2;
window.buffer[0] = 3;
window.buffer[1] = 4;
window.pos = 2;
window.copy_from_self(4, 3);
assert_eq!(window.pos, 5);
assert_eq!(&window.buffer[..5], &[3, 4, 1, 2, 3]);
assert_eq!(&window.buffer[window.buffer.len() - 2..], &[1, 2]);
assert!(window.buffer[5..window.buffer.len() - 2]
.iter()
.all(|&x| x == 0));
}
#[test]
fn check_bitstream() {
let buffer = [1, 2, 3, 4];
let mut bitstream = Bitstream::new(&buffer);
let mut window = WindowSize::KB32.create_buffer();
window.copy_from_bitstream(&mut bitstream, 4).unwrap();
assert_eq!(window.pos, 4);
assert_eq!(&window.buffer[..4], &[1, 2, 3, 4]);
assert!(window.buffer[4..].iter().all(|&x| x == 0));
}
#[test]
fn check_bitstream_before_boundary() {
let buffer = [1, 2, 3, 4];
let mut bitstream = Bitstream::new(&buffer);
let mut window = WindowSize::KB32.create_buffer();
window.pos = window.buffer.len() - 4;
window.copy_from_bitstream(&mut bitstream, 4).unwrap();
assert_eq!(window.pos, 0);
}
#[test]
fn check_bitstream_at_boundary() {
let buffer = [1, 2, 3, 4];
let mut bitstream = Bitstream::new(&buffer);
let mut window = WindowSize::KB32.create_buffer();
window.pos = window.buffer.len() - 2;
window.copy_from_bitstream(&mut bitstream, 4).unwrap();
assert_eq!(window.pos, 0);
assert_eq!(&window.buffer[window.buffer.len() - 4..], &[1, 2, 3, 4]);
assert!(window.buffer[..window.buffer.len() - 4]
.iter()
.all(|&x| x == 0));
}
#[test]
fn check_past_view() {
let mut window = WindowSize::KB32.create_buffer();
window.buffer[0] = 1;
window.buffer[1] = 2;
window.buffer[2] = 3;
window.pos = 3;
assert_eq!(window.past_view(2).unwrap(), &[2, 3]);
assert_eq!(window.past_view(3).unwrap(), &[1, 2, 3]);
}
#[test]
fn check_past_view_at_boundary() {
let mut window = WindowSize::KB32.create_buffer();
window.buffer[window.buffer.len() - 2] = 1;
window.buffer[window.buffer.len() - 1] = 2;
window.buffer[0] = 3;
window.buffer[1] = 4;
window.pos = 2;
assert_eq!(window.past_view(4).unwrap(), &[1, 2, 3, 4]);
}
#[test]
fn check_past_view_too_long() {
let mut window = WindowSize::KB32.create_buffer();
assert_eq!(
window.past_view(1 << 15 + 1),
Err(DecodeFailed::ChunkTooLong)
);
}
#[test]
fn check_past_view_new_max_size() {
let mut window = WindowSize::KB32.create_buffer();
assert!(window.past_view(1 << 15).is_ok());
}
#[test]
fn check_past_view_shifted_max_size() {
let mut window = WindowSize::KB32.create_buffer();
window.pos = 123;
assert!(window.past_view(1 << 15).is_ok());
}
}