use alloc::vec::Vec;
use crate::error::Error;
use crate::traits::{Algorithm, Decoder as DecoderTrait, Encoder as EncoderTrait, Progress};
mod block;
pub const BLOCK_SIZE: usize = 64 * 1024;
#[derive(Debug, Clone, Copy, Default)]
pub struct Lz4;
impl Algorithm for Lz4 {
const NAME: &'static str = "lz4";
type Encoder = Encoder;
type Decoder = Decoder;
fn encoder() -> Encoder {
Encoder::new()
}
fn decoder() -> Decoder {
Decoder::new()
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum EncPhase {
Buffering,
Flushing,
Terminating,
Done,
}
pub struct Encoder {
raw: Vec<u8>,
compressed: Vec<u8>,
compressed_idx: usize,
terminator_idx: u8,
phase: EncPhase,
}
impl Encoder {
pub fn new() -> Self {
Self {
raw: Vec::with_capacity(BLOCK_SIZE),
compressed: Vec::with_capacity(block::compress_bound(BLOCK_SIZE) + 4),
compressed_idx: 0,
terminator_idx: 0,
phase: EncPhase::Buffering,
}
}
fn build_block(&mut self) {
if self.raw.is_empty() {
return;
}
self.compressed.clear();
self.compressed.extend_from_slice(&[0, 0, 0, 0]);
let prefix_len = self.compressed.len();
let mut tmp = Vec::with_capacity(block::compress_bound(self.raw.len()));
block::encode_block(&self.raw, &mut tmp);
debug_assert!(!tmp.is_empty());
let len = tmp.len() as u32;
self.compressed[0..4].copy_from_slice(&len.to_le_bytes());
self.compressed.extend_from_slice(&tmp);
let _ = prefix_len; self.raw.clear();
self.compressed_idx = 0;
self.phase = EncPhase::Flushing;
}
fn drain_compressed(&mut self, output: &mut [u8], written: &mut usize) {
let avail = self.compressed.len() - self.compressed_idx;
let space = output.len() - *written;
let n = avail.min(space);
if n > 0 {
output[*written..*written + n]
.copy_from_slice(&self.compressed[self.compressed_idx..self.compressed_idx + n]);
self.compressed_idx += n;
*written += n;
}
if self.compressed_idx == self.compressed.len() {
self.compressed.clear();
self.compressed_idx = 0;
self.phase = EncPhase::Buffering;
}
}
fn drain_terminator(&mut self, output: &mut [u8], written: &mut usize) {
while self.terminator_idx < 4 && *written < output.len() {
output[*written] = 0;
*written += 1;
self.terminator_idx += 1;
}
if self.terminator_idx == 4 {
self.phase = EncPhase::Done;
}
}
}
impl Default for Encoder {
fn default() -> Self {
Self::new()
}
}
impl EncoderTrait for Encoder {
fn encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
let mut consumed = 0usize;
let mut written = 0usize;
loop {
if self.phase == EncPhase::Flushing {
self.drain_compressed(output, &mut written);
if self.phase == EncPhase::Flushing {
return Ok(Progress {
consumed,
written,
done: false,
});
}
}
if self.phase != EncPhase::Buffering {
return Ok(Progress {
consumed,
written,
done: false,
});
}
if consumed == input.len() {
return Ok(Progress {
consumed,
written,
done: false,
});
}
let room = BLOCK_SIZE - self.raw.len();
let take = (input.len() - consumed).min(room);
self.raw
.extend_from_slice(&input[consumed..consumed + take]);
consumed += take;
if self.raw.len() == BLOCK_SIZE {
self.build_block();
continue;
}
return Ok(Progress {
consumed,
written,
done: false,
});
}
}
fn finish(&mut self, output: &mut [u8]) -> Result<Progress, Error> {
let mut written = 0usize;
loop {
match self.phase {
EncPhase::Buffering => {
if !self.raw.is_empty() {
self.build_block();
} else {
self.phase = EncPhase::Terminating;
}
}
EncPhase::Flushing => {
self.drain_compressed(output, &mut written);
if self.phase == EncPhase::Flushing {
return Ok(Progress {
consumed: 0,
written,
done: false,
});
}
}
EncPhase::Terminating => {
self.drain_terminator(output, &mut written);
if self.phase == EncPhase::Terminating {
return Ok(Progress {
consumed: 0,
written,
done: false,
});
}
}
EncPhase::Done => {
return Ok(Progress {
consumed: 0,
written,
done: true,
});
}
}
}
}
fn reset(&mut self) {
self.raw.clear();
self.compressed.clear();
self.compressed_idx = 0;
self.terminator_idx = 0;
self.phase = EncPhase::Buffering;
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum DecPhase {
Length,
BlockData,
Draining,
Done,
}
pub struct Decoder {
length_buf: [u8; 4],
length_idx: u8,
expected_len: usize,
compressed: Vec<u8>,
decoded: Vec<u8>,
decoded_idx: usize,
phase: DecPhase,
poisoned: bool,
}
impl Decoder {
pub fn new() -> Self {
Self {
length_buf: [0; 4],
length_idx: 0,
expected_len: 0,
compressed: Vec::new(),
decoded: Vec::new(),
decoded_idx: 0,
phase: DecPhase::Length,
poisoned: false,
}
}
fn drain_decoded(&mut self, output: &mut [u8], written: &mut usize) {
let avail = self.decoded.len() - self.decoded_idx;
let space = output.len() - *written;
let n = avail.min(space);
if n > 0 {
output[*written..*written + n]
.copy_from_slice(&self.decoded[self.decoded_idx..self.decoded_idx + n]);
self.decoded_idx += n;
*written += n;
}
if self.decoded_idx == self.decoded.len() {
self.decoded.clear();
self.decoded_idx = 0;
self.phase = DecPhase::Length;
self.length_idx = 0;
}
}
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
impl DecoderTrait for Decoder {
fn decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
if self.poisoned {
return Err(Error::Corrupt);
}
let mut consumed = 0usize;
let mut written = 0usize;
loop {
match self.phase {
DecPhase::Length => {
while self.length_idx < 4 && consumed < input.len() {
self.length_buf[self.length_idx as usize] = input[consumed];
self.length_idx += 1;
consumed += 1;
}
if self.length_idx < 4 {
return Ok(Progress {
consumed,
written,
done: false,
});
}
self.expected_len = u32::from_le_bytes(self.length_buf) as usize;
if self.expected_len == 0 {
self.phase = DecPhase::Done;
return Ok(Progress {
consumed,
written,
done: false,
});
}
self.compressed.clear();
self.compressed.reserve(self.expected_len);
self.phase = DecPhase::BlockData;
}
DecPhase::BlockData => {
let need = self.expected_len - self.compressed.len();
let avail = input.len() - consumed;
let take = need.min(avail);
if take > 0 {
self.compressed
.extend_from_slice(&input[consumed..consumed + take]);
consumed += take;
}
if self.compressed.len() < self.expected_len {
return Ok(Progress {
consumed,
written,
done: false,
});
}
self.decoded.clear();
if let Err(e) = block::decode_block(&self.compressed, &mut self.decoded) {
self.poisoned = true;
return Err(e);
}
self.decoded_idx = 0;
self.phase = DecPhase::Draining;
}
DecPhase::Draining => {
self.drain_decoded(output, &mut written);
if self.phase == DecPhase::Draining {
return Ok(Progress {
consumed,
written,
done: false,
});
}
}
DecPhase::Done => {
return Ok(Progress {
consumed,
written,
done: false,
});
}
}
}
}
fn finish(&mut self, output: &mut [u8]) -> Result<Progress, Error> {
if self.poisoned {
return Err(Error::Corrupt);
}
let mut written = 0usize;
if self.phase == DecPhase::Draining {
self.drain_decoded(output, &mut written);
if self.phase == DecPhase::Draining {
return Ok(Progress {
consumed: 0,
written,
done: false,
});
}
}
match self.phase {
DecPhase::Done => Ok(Progress {
consumed: 0,
written,
done: true,
}),
DecPhase::Length if self.length_idx == 0 => {
Ok(Progress {
consumed: 0,
written,
done: true,
})
}
DecPhase::Length | DecPhase::BlockData => Err(Error::UnexpectedEnd),
DecPhase::Draining => unreachable!(),
}
}
fn reset(&mut self) {
self.length_buf = [0; 4];
self.length_idx = 0;
self.expected_len = 0;
self.compressed.clear();
self.decoded.clear();
self.decoded_idx = 0;
self.phase = DecPhase::Length;
self.poisoned = false;
}
}