use alloc::vec;
use alloc::vec::Vec;
use crate::error::Error;
use crate::traits::{RawEncoder, RawProgress};
use crate::zstd::encoder_bitwriter::RevBitWriter;
use crate::zstd::encoder_fse::{
DEFAULT_LL_ACCURACY_LOG, DEFAULT_LL_COUNTS, DEFAULT_ML_ACCURACY_LOG, DEFAULT_ML_COUNTS,
DEFAULT_OF_ACCURACY_LOG, DEFAULT_OF_COUNTS, FseEncoder, build_normalised_counts,
encode_fse_table_header,
};
use crate::zstd::encoder_huffman::{
HuffLengths, build_huff_encoder, build_huff_lengths, encode_huff_4streams, encode_huff_stream,
encode_huff_tree_direct, histogram, lengths_to_weights, predicted_bits,
};
use crate::zstd::encoder_seq::{encode_sequence_count, ll_code, ml_code, of_code};
use crate::zstd::matcher::{MIN_MATCH, MatchFinder};
const MAGIC: [u8; 4] = [0x28, 0xB5, 0x2F, 0xFD];
const FHD: u8 = 0x00;
const WD: u8 = 0x70;
const BLOCK_SIZE: usize = 128 * 1024;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncoderConfig {
pub level: u8,
}
impl Default for EncoderConfig {
fn default() -> Self {
Self { level: 3 }
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct LevelParams {
pub max_chain: usize,
pub nice_match: usize,
pub lazy_search: bool,
}
impl LevelParams {
pub(crate) fn from_level(level: u8) -> Self {
let level = level.clamp(1, 22);
let lazy_search = level >= 4;
match level {
1 => Self {
max_chain: 4,
nice_match: 8,
lazy_search,
},
2 => Self {
max_chain: 8,
nice_match: 12,
lazy_search,
},
3 => Self {
max_chain: 16,
nice_match: 16,
lazy_search,
},
4 => Self {
max_chain: 24,
nice_match: 24,
lazy_search,
},
5 => Self {
max_chain: 32,
nice_match: 32,
lazy_search,
},
6 => Self {
max_chain: 48,
nice_match: 48,
lazy_search,
},
7 => Self {
max_chain: 64,
nice_match: 64,
lazy_search,
},
8 => Self {
max_chain: 96,
nice_match: 96,
lazy_search,
},
9 => Self {
max_chain: 128,
nice_match: 128,
lazy_search,
},
10 => Self {
max_chain: 192,
nice_match: 160,
lazy_search,
},
11 => Self {
max_chain: 256,
nice_match: 192,
lazy_search,
},
12 => Self {
max_chain: 384,
nice_match: 224,
lazy_search,
},
13 => Self {
max_chain: 512,
nice_match: 256,
lazy_search,
},
14 => Self {
max_chain: 768,
nice_match: 384,
lazy_search,
},
15 => Self {
max_chain: 1024,
nice_match: 512,
lazy_search,
},
16 => Self {
max_chain: 1536,
nice_match: 768,
lazy_search,
},
17 => Self {
max_chain: 2048,
nice_match: 1024,
lazy_search,
},
18 => Self {
max_chain: 3072,
nice_match: 1536,
lazy_search,
},
19 => Self {
max_chain: 4096,
nice_match: 2048,
lazy_search,
},
20 => Self {
max_chain: 6144,
nice_match: 3072,
lazy_search,
},
21 => Self {
max_chain: 8192,
nice_match: 4096,
lazy_search,
},
_ => Self {
max_chain: 16384,
nice_match: super::matcher::MAX_MATCH,
lazy_search,
},
}
}
}
pub struct Encoder {
state: State,
pending: Vec<u8>,
out_buf: Vec<u8>,
out_idx: usize,
matcher: MatchFinder,
header_written: bool,
prev_offsets: [u32; 3],
prev_huff_lengths: Option<HuffLengths>,
params: LevelParams,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum State {
Accepting,
Draining { last: bool },
Done,
}
impl Encoder {
pub fn new() -> Self {
Self::with_config(EncoderConfig::default())
}
pub fn with_config(config: EncoderConfig) -> Self {
Self {
state: State::Accepting,
pending: Vec::with_capacity(BLOCK_SIZE),
out_buf: Vec::new(),
out_idx: 0,
matcher: MatchFinder::new(BLOCK_SIZE),
header_written: false,
prev_offsets: [1, 4, 8],
prev_huff_lengths: None,
params: LevelParams::from_level(config.level),
}
}
fn write_frame_header(&mut self) {
self.out_buf.extend_from_slice(&MAGIC);
self.out_buf.push(FHD);
self.out_buf.push(WD);
}
fn push_block_header(out: &mut Vec<u8>, body_size: u32, block_type: u32, last: bool) {
debug_assert!(body_size < (1u32 << 21));
debug_assert!(block_type < 4);
let bh: u32 = (if last { 1 } else { 0 }) | (block_type << 1) | (body_size << 3);
out.push((bh & 0xFF) as u8);
out.push(((bh >> 8) & 0xFF) as u8);
out.push(((bh >> 16) & 0xFF) as u8);
}
fn append_raw_block(out: &mut Vec<u8>, body: &[u8], last: bool) {
Self::push_block_header(out, body.len() as u32, 0, last);
out.extend_from_slice(body);
}
fn try_compress_block(&mut self) -> Option<Vec<u8>> {
if self.pending.len() < 16 {
return None;
}
let buffer = self.pending.as_slice();
self.matcher.resize_for(buffer.len());
let mut sequences: Vec<Seq> = Vec::new();
let mut literals: Vec<u8> = Vec::with_capacity(buffer.len());
let mut lit_start: usize = 0;
let mut pos: usize = 0;
let mut block_offsets = self.prev_offsets;
let lazy = self.params.lazy_search;
let buf_len = buffer.len();
let max_chain = self.params.max_chain;
let nice_match = self.params.nice_match;
let mut next_insert: usize = 0;
while pos + MIN_MATCH < buf_len {
while next_insert <= pos {
self.matcher.insert(buffer, next_insert);
next_insert += 1;
}
let (m_dist, m_len, m_is_rep1) = best_at(
&self.matcher,
buffer,
pos,
&block_offsets,
max_chain,
nice_match,
);
if m_len == 0 {
pos += 1;
continue;
}
let (best_pos, best_dist, best_len) =
if lazy && m_len < nice_match && pos + 1 + MIN_MATCH < buf_len {
while next_insert <= pos + 1 {
self.matcher.insert(buffer, next_insert);
next_insert += 1;
}
let (n_dist, n_len, _) = best_at(
&self.matcher,
buffer,
pos + 1,
&block_offsets,
max_chain,
nice_match,
);
let margin = if m_is_rep1 { 2 } else { 1 };
if n_len >= m_len + margin {
(pos + 1, n_dist, n_len)
} else {
(pos, m_dist, m_len)
}
} else {
(pos, m_dist, m_len)
};
let literal_run = best_pos - lit_start;
let offset_value =
assign_offset(best_dist as u32, literal_run as u32, &mut block_offsets);
literals.extend_from_slice(&buffer[lit_start..best_pos]);
sequences.push(Seq {
literal_length: literal_run as u32,
match_length: best_len as u32,
offset_value,
});
let match_end = best_pos + best_len;
while next_insert < match_end {
self.matcher.insert(buffer, next_insert);
next_insert += 1;
}
pos = match_end;
lit_start = pos;
}
if sequences.is_empty() {
return None;
}
let trailing_literals = &buffer[lit_start..];
let mut all_literals: Vec<u8> =
Vec::with_capacity(literals.len() + trailing_literals.len());
all_literals.extend_from_slice(&literals);
all_literals.extend_from_slice(trailing_literals);
let (lit_section, new_lengths) =
build_literals_section(&all_literals, self.prev_huff_lengths.as_ref());
let seq_section = self.build_sequences_section(&sequences);
let total = lit_section.len() + seq_section.len();
let raw_size = buffer.len();
if total >= raw_size {
return None; }
self.prev_offsets = block_offsets;
if let Some(lengths) = new_lengths {
self.prev_huff_lengths = Some(lengths);
}
let mut body = Vec::with_capacity(total);
body.extend_from_slice(&lit_section);
body.extend_from_slice(&seq_section);
Some(body)
}
fn build_sequences_section(&self, sequences: &[Seq]) -> Vec<u8> {
let n = sequences.len() as u32;
let mut ll_codes: Vec<u8> = Vec::with_capacity(sequences.len());
let mut ml_codes: Vec<u8> = Vec::with_capacity(sequences.len());
let mut of_codes: Vec<u8> = Vec::with_capacity(sequences.len());
let mut ll_extras: Vec<(u32, u32)> = Vec::with_capacity(sequences.len());
let mut ml_extras: Vec<(u32, u32)> = Vec::with_capacity(sequences.len());
let mut of_extras: Vec<(u32, u32)> = Vec::with_capacity(sequences.len());
for s in sequences {
let (oc, oe_bits, oe_val) = of_code(s.offset_value);
of_codes.push(oc);
of_extras.push((oe_bits, oe_val));
let (lc, le_bits, le_val) = ll_code(s.literal_length);
ll_codes.push(lc);
ll_extras.push((le_bits, le_val));
let (mc, me_bits, me_val) = ml_code(s.match_length);
ml_codes.push(mc);
ml_extras.push((me_bits, me_val));
}
let (ll_enc, ll_mode, ll_header) = pick_table(
&ll_codes,
&DEFAULT_LL_COUNTS,
DEFAULT_LL_ACCURACY_LOG,
9,
35,
);
let (of_enc, of_mode, of_header) = pick_table(
&of_codes,
&DEFAULT_OF_COUNTS,
DEFAULT_OF_ACCURACY_LOG,
8,
31,
);
let (ml_enc, ml_mode, ml_header) = pick_table(
&ml_codes,
&DEFAULT_ML_COUNTS,
DEFAULT_ML_ACCURACY_LOG,
9,
52,
);
let mut out = encode_sequence_count(n);
let modes: u8 = (ll_mode << 6) | (of_mode << 4) | (ml_mode << 2);
out.push(modes);
out.extend_from_slice(&ll_header);
out.extend_from_slice(&of_header);
out.extend_from_slice(&ml_header);
let mut writer = RevBitWriter::new();
let n_seq = sequences.len();
let mut ll_state = ll_enc.init_state(ll_codes[n_seq - 1] as usize);
let mut of_state = of_enc.init_state(of_codes[n_seq - 1] as usize);
let mut ml_state = ml_enc.init_state(ml_codes[n_seq - 1] as usize);
for i in (0..n_seq).rev() {
if i == n_seq - 1 {
} else {
of_state = of_enc.encode_symbol(of_state, of_codes[i] as usize, &mut writer);
ml_state = ml_enc.encode_symbol(ml_state, ml_codes[i] as usize, &mut writer);
ll_state = ll_enc.encode_symbol(ll_state, ll_codes[i] as usize, &mut writer);
}
writer.write_bits(ll_extras[i].1 as u64, ll_extras[i].0);
writer.write_bits(ml_extras[i].1 as u64, ml_extras[i].0);
writer.write_bits(of_extras[i].1 as u64, of_extras[i].0);
}
ml_enc.write_final_state(ml_state, &mut writer);
of_enc.write_final_state(of_state, &mut writer);
ll_enc.write_final_state(ll_state, &mut writer);
let bitstream = writer.finish();
out.extend_from_slice(&bitstream);
out
}
fn flush_block(&mut self, last: bool) {
if self.pending.len() >= 4 && all_same(&self.pending) {
let body_size = self.pending.len() as u32;
Self::push_block_header(&mut self.out_buf, body_size, 1, last);
self.out_buf.push(self.pending[0]);
self.pending.clear();
return;
}
if let Some(body) = self.try_compress_block() {
Self::push_block_header(&mut self.out_buf, body.len() as u32, 2, last);
self.out_buf.extend_from_slice(&body);
} else {
let pending_snapshot = core::mem::take(&mut self.pending);
Self::append_raw_block(&mut self.out_buf, &pending_snapshot, last);
self.pending = pending_snapshot;
}
self.pending.clear();
}
fn drain_into(&mut self, output: &mut [u8], written: &mut usize) -> bool {
let avail = output.len() - *written;
let remaining = self.out_buf.len() - self.out_idx;
let n = core::cmp::min(avail, remaining);
if n > 0 {
output[*written..*written + n]
.copy_from_slice(&self.out_buf[self.out_idx..self.out_idx + n]);
*written += n;
self.out_idx += n;
}
let drained = self.out_idx == self.out_buf.len();
if drained {
self.out_buf.clear();
self.out_idx = 0;
}
drained
}
}
fn best_at(
matcher: &MatchFinder,
buffer: &[u8],
pos: usize,
block_offsets: &[u32; 3],
max_chain: usize,
nice_match: usize,
) -> (usize, usize, bool) {
let mut best_len: usize = 0;
let mut best_dist: usize = 0;
let mut best_is_rep1: bool = false;
for (i, &d) in block_offsets.iter().enumerate() {
let len = matcher.check_repeat_offset(buffer, pos, d as usize);
if len > best_len {
best_len = len;
best_dist = d as usize;
best_is_rep1 = i == 0;
if best_len >= nice_match {
return (best_dist, best_len, best_is_rep1);
}
}
}
if let Some(m) = matcher.find_match(buffer, pos, buffer.len(), max_chain, nice_match) {
if m.length > best_len {
best_len = m.length;
best_dist = m.distance;
best_is_rep1 = best_dist == block_offsets[0] as usize;
}
}
(best_dist, best_len, best_is_rep1)
}
fn pick_table(
codes: &[u8],
default_counts: &[i16],
default_al: u8,
max_al: u8,
max_symbol: u16,
) -> (FseEncoder, u8, Vec<u8>) {
let alphabet = (max_symbol as usize) + 1;
let mut hist = vec![0u32; alphabet];
for &c in codes {
if (c as usize) < alphabet {
hist[c as usize] += 1;
}
}
let n = codes.len();
let pred_bits_default = predict_fse_bits(default_counts, &hist, default_al);
let mut al = max_al;
while al > 5 && (1u32 << al) > (n as u32) * 4 {
al -= 1;
}
if al < 5 {
al = 5;
}
let custom = build_normalised_counts(&hist, n as u32, al);
if let Some(counts) = custom {
let pred_bits_custom = predict_fse_bits(&counts, &hist, al);
let header = encode_fse_table_header(&counts, al);
let custom_bytes = (pred_bits_custom / 8 + 1) as usize + header.len();
let default_bytes = (pred_bits_default / 8 + 1) as usize;
if custom_bytes + 2 < default_bytes {
let enc = FseEncoder::from_normalized(&counts, al);
return (enc, 0b10, header);
}
}
let predef_enc = FseEncoder::from_normalized(default_counts, default_al);
(predef_enc, 0b00, Vec::new())
}
fn predict_fse_bits(counts: &[i16], hist: &[u32], accuracy_log: u8) -> u64 {
let mut total: u64 = 0;
for s in 0..hist.len().min(counts.len()) {
let n = hist[s] as u64;
if n == 0 {
continue;
}
let c = counts[s];
let bits = if c == -1 || c == 1 {
accuracy_log as u64
} else if c > 1 {
let log2 = 31u32 - (c as u32).leading_zeros();
(accuracy_log as u64).saturating_sub(log2 as u64)
} else {
return u64::MAX;
};
total += n * bits;
}
total
}
fn all_same(s: &[u8]) -> bool {
if s.is_empty() {
return true;
}
let first = s[0];
s.iter().all(|&b| b == first)
}
#[derive(Clone, Copy, Debug)]
struct Seq {
literal_length: u32,
match_length: u32,
offset_value: u32,
}
fn build_raw_literals_section_one(literals: &[u8]) -> Vec<u8> {
let regen = literals.len();
let mut out = Vec::with_capacity(3 + regen);
if regen < 32 {
let hdr = (regen as u8) << 3;
out.push(hdr);
} else if regen < 4096 {
let byte0 = (((regen & 0xF) as u8) << 4) | (0b01 << 2);
let byte1 = (regen >> 4) as u8;
out.push(byte0);
out.push(byte1);
} else {
let byte0 = (((regen & 0xF) as u8) << 4) | (0b11 << 2);
let byte1 = ((regen >> 4) & 0xFF) as u8;
let byte2 = ((regen >> 12) & 0xFF) as u8;
out.push(byte0);
out.push(byte1);
out.push(byte2);
}
out.extend_from_slice(literals);
out
}
fn build_literals_section(
literals: &[u8],
prev_lengths: Option<&HuffLengths>,
) -> (Vec<u8>, Option<HuffLengths>) {
let regen = literals.len();
let mut best: Option<(Vec<u8>, Option<HuffLengths>)> = None;
let raw_len = raw_literals_section_len(regen);
let take_candidate =
|section: Vec<u8>,
lengths: Option<HuffLengths>,
current: &mut Option<(Vec<u8>, Option<HuffLengths>)>| {
if section.len() < raw_len
&& current
.as_ref()
.map(|(b, _)| section.len() < b.len())
.unwrap_or(true)
{
*current = Some((section, lengths));
}
};
if regen >= 32 {
if let Some(prev) = prev_lengths {
let mut compatible = true;
for &b in literals {
if prev[b as usize] == 0 {
compatible = false;
break;
}
}
if compatible
&& let Some(section) = try_build_huffman_literals_section_with(
literals, prev, false,
)
{
take_candidate(section, Some(*prev), &mut best);
}
}
let freq = histogram(literals);
if let Some(lengths) = build_huff_lengths(&freq)
&& let Some(section) = try_build_huffman_literals_section_with(
literals, &lengths, true,
)
{
take_candidate(section, Some(lengths), &mut best);
}
}
if let Some((section, lengths)) = best {
(section, lengths)
} else {
(build_raw_literals_section_one(literals), None)
}
}
fn raw_literals_section_len(regen: usize) -> usize {
let header = if regen < 32 {
1
} else if regen < 4096 {
2
} else {
3
};
header + regen
}
fn try_build_huffman_literals_section_with(
literals: &[u8],
lengths: &HuffLengths,
fresh_tree: bool,
) -> Option<Vec<u8>> {
let regen = literals.len();
if regen == 0 {
return None;
}
if regen > (1 << 18) - 1 {
return None; }
let enc = build_huff_encoder(lengths);
let tree_bytes: Vec<u8> = if fresh_tree {
let (weights, _max_num_bits) = lengths_to_weights(lengths);
if weights.len() > 128 {
return None; }
encode_huff_tree_direct(&weights)
} else {
Vec::new()
};
let mut freq = [0u32; 256];
for &b in literals {
freq[b as usize] += 1;
if !fresh_tree && lengths[b as usize] == 0 {
return None;
}
}
let pred_bits = predicted_bits(lengths, &freq);
let est_payload = pred_bits.div_ceil(8) as usize + tree_bytes.len() + 8;
if est_payload >= regen + 3 {
return None;
}
let (use_4_stream, streams): (bool, Vec<Vec<u8>>) = if regen <= 1023 {
(false, vec![encode_huff_stream(&enc, literals)])
} else {
let (s1, s2, s3, s4) = encode_huff_4streams(&enc, literals);
(true, vec![s1, s2, s3, s4])
};
let stream_total: usize = streams.iter().map(|s| s.len()).sum();
let jump_table_len = if use_4_stream { 6 } else { 0 };
let mut payload = Vec::with_capacity(tree_bytes.len() + jump_table_len + stream_total);
payload.extend_from_slice(&tree_bytes);
if use_4_stream {
let l1 = streams[0].len();
let l2 = streams[1].len();
let l3 = streams[2].len();
if l1 > 0xFFFF || l2 > 0xFFFF || l3 > 0xFFFF {
return None;
}
payload.push((l1 & 0xFF) as u8);
payload.push(((l1 >> 8) & 0xFF) as u8);
payload.push((l2 & 0xFF) as u8);
payload.push(((l2 >> 8) & 0xFF) as u8);
payload.push((l3 & 0xFF) as u8);
payload.push(((l3 >> 8) & 0xFF) as u8);
for s in &streams {
payload.extend_from_slice(s);
}
} else {
payload.extend_from_slice(&streams[0]);
}
let comp_size = payload.len();
let (sf, header_bytes): (u8, usize) = if !use_4_stream {
if regen >= 1024 || comp_size >= 1024 {
return None;
}
(0b00, 3)
} else if regen < 1024 && comp_size < 1024 {
(0b01, 3)
} else if regen < 16384 && comp_size < 16384 {
(0b10, 4)
} else if regen < (1 << 18) && comp_size < (1 << 18) {
(0b11, 5)
} else {
return None;
};
let lit_block_type: u8 = if fresh_tree { 0b10 } else { 0b11 };
let lhd_low_4_bits = lit_block_type | (sf << 2);
let mut out = Vec::with_capacity(header_bytes + comp_size);
match (sf, header_bytes) {
(0b00, 3) | (0b01, 3) => {
let b0 = lhd_low_4_bits | (((regen & 0xF) as u8) << 4);
let b1 = ((regen >> 4) as u8 & 0x3F) | (((comp_size & 0x3) as u8) << 6);
let b2 = (comp_size >> 2) as u8;
out.push(b0);
out.push(b1);
out.push(b2);
}
(0b10, 4) => {
let b0 = lhd_low_4_bits | (((regen & 0xF) as u8) << 4);
let b1 = ((regen >> 4) & 0xFF) as u8;
let b2 = (((regen >> 12) & 0x3) as u8) | (((comp_size & 0x3F) as u8) << 2);
let b3 = (comp_size >> 6) as u8;
out.push(b0);
out.push(b1);
out.push(b2);
out.push(b3);
}
(0b11, 5) => {
let bits: u64 = (lhd_low_4_bits as u64)
| ((regen as u64 & 0x3_FFFF) << 4)
| ((comp_size as u64 & 0x3_FFFF) << 22);
out.push((bits & 0xFF) as u8);
out.push(((bits >> 8) & 0xFF) as u8);
out.push(((bits >> 16) & 0xFF) as u8);
out.push(((bits >> 24) & 0xFF) as u8);
out.push(((bits >> 32) & 0xFF) as u8);
}
_ => unreachable!(),
}
out.extend_from_slice(&payload);
Some(out)
}
fn assign_offset(distance: u32, literal_length: u32, prev: &mut [u32; 3]) -> u32 {
debug_assert!(distance > 0);
if literal_length > 0 {
if distance == prev[0] {
return 1;
}
if distance == prev[1] {
prev.swap(0, 1);
return 2;
}
if distance == prev[2] {
let tmp = prev[2];
prev[2] = prev[1];
prev[1] = prev[0];
prev[0] = tmp;
return 3;
}
} else {
if distance == prev[1] {
prev.swap(0, 1);
return 1;
}
if distance == prev[2] {
let tmp = prev[2];
prev[2] = prev[1];
prev[1] = prev[0];
prev[0] = tmp;
return 2;
}
if prev[0] > 1 && distance == prev[0] - 1 {
prev[2] = prev[1];
prev[1] = prev[0];
prev[0] = distance;
return 3;
}
}
prev[2] = prev[1];
prev[1] = prev[0];
prev[0] = distance;
distance + 3
}
impl Default for Encoder {
fn default() -> Self {
Self::new()
}
}
impl RawEncoder for Encoder {
fn raw_encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<RawProgress, Error> {
let mut consumed = 0usize;
let mut written = 0usize;
loop {
match self.state {
State::Accepting => {
if !self.header_written {
self.write_frame_header();
self.header_written = true;
}
let space = BLOCK_SIZE - self.pending.len();
let take = core::cmp::min(space, input.len() - consumed);
if take > 0 {
self.pending
.extend_from_slice(&input[consumed..consumed + take]);
consumed += take;
}
if self.pending.len() == BLOCK_SIZE {
self.flush_block(false);
self.state = State::Draining { last: false };
} else if !self.out_buf.is_empty() {
self.state = State::Draining { last: false };
} else {
return Ok(RawProgress {
consumed,
written,
done: false,
});
}
}
State::Draining { last } => {
let drained = self.drain_into(output, &mut written);
if !drained {
return Ok(RawProgress {
consumed,
written,
done: false,
});
}
if last {
self.state = State::Done;
} else {
self.state = State::Accepting;
}
}
State::Done => {
return Ok(RawProgress {
consumed,
written,
done: false,
});
}
}
}
}
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error> {
let mut written = 0usize;
loop {
match self.state {
State::Accepting => {
if !self.header_written {
self.write_frame_header();
self.header_written = true;
}
if self.pending.is_empty() {
Self::push_block_header(&mut self.out_buf, 0, 0, true);
} else {
self.flush_block(true);
}
self.state = State::Draining { last: true };
}
State::Draining { last } => {
let drained = self.drain_into(output, &mut written);
if !drained {
return Ok(RawProgress {
consumed: 0,
written,
done: false,
});
}
if last {
self.state = State::Done;
} else {
self.state = State::Accepting;
}
}
State::Done => {
return Ok(RawProgress {
consumed: 0,
written,
done: true,
});
}
}
}
}
fn raw_reset(&mut self) {
self.state = State::Accepting;
self.pending.clear();
self.out_buf.clear();
self.out_idx = 0;
self.matcher = MatchFinder::new(BLOCK_SIZE);
self.header_written = false;
self.prev_offsets = [1, 4, 8];
self.prev_huff_lengths = None;
}
}