use crate::encode::Backend;
use crate::fse::{Buffer, Encoder, Weights};
use crate::lmd::MatchDistance;
use crate::types::{ShortBuffer, ShortWriter};
use super::constants::*;
use super::object::Fse;
use std::io;
#[derive(Default)]
pub struct FseBackend {
buffer: Buffer,
weights: Weights,
encoder: Encoder,
}
impl FseBackend {
#[allow(dead_code)]
#[cold]
fn emit_block_v1<O: ShortWriter>(&mut self, dst: &mut O, flush: bool) -> io::Result<()> {
let mark = dst.pos();
dst.write_short_bytes(&[0u8; V1_HEADER_SIZE as usize])?;
self.buffer.pad();
self.buffer.init_weights(&mut self.weights);
self.weights.store_v1_short(dst)?;
self.encoder.init(&self.weights);
let block = self.buffer.store(dst, &self.encoder)?;
let bytes = dst.patch_into(mark, V1_HEADER_SIZE as usize);
block.store_v1(bytes);
self.buffer.reset();
if flush {
dst.flush(false)?;
}
Ok(())
}
#[cold]
fn emit_block_v2<O: ShortWriter>(&mut self, dst: &mut O, flush: bool) -> io::Result<()> {
let mark = dst.pos();
dst.write_short_bytes(&[0u8; V2_HEADER_SIZE as usize])?;
self.buffer.pad();
self.buffer.init_weights(&mut self.weights);
let n_weight_payload_bytes = self.weights.store_v2_short(dst)?;
self.encoder.init(&self.weights);
let block = self.buffer.store(dst, &self.encoder)?;
let bytes = dst.patch_into(mark, V2_HEADER_SIZE as usize);
block.store_v2(bytes, n_weight_payload_bytes);
self.buffer.reset();
if flush {
dst.flush(false)?;
}
Ok(())
}
}
impl Backend for FseBackend {
type Type = Fse;
#[inline(always)]
fn init<O: ShortWriter>(&mut self, _: &mut O, _: Option<usize>) -> io::Result<()> {
self.buffer.reset();
Ok(())
}
#[inline(always)]
fn push_literals<I: ShortBuffer, O: ShortWriter>(
&mut self,
dst: &mut O,
literals: I,
) -> io::Result<()> {
self.push_match(dst, literals, 0, unsafe { MatchDistance::new_unchecked(1) })
}
#[inline(always)]
fn push_match<I: ShortBuffer, O: ShortWriter>(
&mut self,
dst: &mut O,
mut literals: I,
mut match_len: u32,
match_distance: MatchDistance<Fse>,
) -> io::Result<()> {
loop {
if self.buffer.push(&mut literals, &mut match_len, match_distance) {
break;
}
self.emit_block_v2(dst, true)?;
}
Ok(())
}
fn finalize<O: ShortWriter>(&mut self, dst: &mut O) -> io::Result<()> {
self.emit_block_v2(dst, false)?;
Ok(())
}
}