use crate::base::MagicBytes;
use crate::error::Error;
use crate::fse::FseCore;
use crate::ops::{Len, Pos};
use crate::raw::RawBlock;
use crate::ring::{RingBlock, RingLzWriter, RingSize};
use crate::types::{ByteReader, Idx};
use crate::vn::VnCore;
use super::constants::*;
use std::convert::TryInto;
use std::io::{self, Read, Sink};
#[derive(Debug, PartialEq, Eq)]
enum State {
None,
Fse,
Vn,
Raw,
Eos,
Err,
}
pub struct ReaderCore<'a, I: for<'b> ByteReader<'b>> {
ring: RingLzWriter<'a, Sink, Output>,
inner: I,
fse_core: &'a mut FseCore,
vn_core: VnCore,
raw_block: RawBlock,
state: State,
idx: Idx,
}
impl<'a, I: for<'b> ByteReader<'b>> ReaderCore<'a, I> {
#[allow(clippy::assertions_on_constants)]
pub fn new(ring: RingLzWriter<'a, Sink, Output>, inner: I, fse_core: &'a mut FseCore) -> Self {
assert!(Output::RING_BLK_SIZE <= Output::RING_SIZE / 4);
Self {
ring,
inner,
fse_core,
vn_core: VnCore::default(),
raw_block: RawBlock::default(),
state: State::None,
idx: Idx::default(),
}
}
pub fn into_inner(self) -> I {
self.inner
}
}
impl<'a, I: for<'b> ByteReader<'b>> ReaderCore<'a, I> {
#[cold]
#[rustfmt::skip]
fn fill(&mut self) -> crate::Result<bool> {
debug_assert_eq!(self.idx, self.ring.pos());
self.inner.fill()?;
match self.state {
State::None => self.init()?,
State::Fse => self.fill_fse()?,
State::Vn => self.fill_vn()?,
State::Raw => self.fill_raw()?,
State::Eos => return Ok(false),
State::Err => return Err(Error::BadReaderState),
};
assert!(self.ring.pos() - self.idx < Output::RING_SIZE as i32 / 2);
Ok(true)
}
fn fill_fse(&mut self) -> crate::Result<()> {
debug_assert_eq!(self.idx, self.ring.pos());
let len = Output::RING_BLK_SIZE;
if !self.fse_core.decode_n(&mut self.ring, len)? {
self.state = State::None;
}
Ok(())
}
fn fill_vn(&mut self) -> crate::Result<()> {
debug_assert_eq!(self.idx, self.ring.pos());
let len = Output::RING_BLK_SIZE;
if !self.vn_core.decode_n(&mut self.ring, &mut self.inner, len)? {
self.state = State::None;
}
Ok(())
}
fn fill_raw(&mut self) -> crate::Result<()> {
debug_assert_eq!(self.idx, self.ring.pos());
let len = Output::RING_BLK_SIZE;
if !self.raw_block.decode_n(&mut self.ring, &mut self.inner, len)? {
self.state = State::None;
}
Ok(())
}
fn init(&mut self) -> crate::Result<()> {
debug_assert_eq!(self.state, State::None);
self.inner.fill()?;
if self.inner.len() < 4 {
return Err(crate::Error::PayloadUnderflow);
}
let magic_bytes: MagicBytes = self.inner.peek_u32().try_into()?;
match magic_bytes {
MagicBytes::Vx1 => self.init_vx1(),
MagicBytes::Vx2 => self.init_vx2(),
MagicBytes::Vxn => self.init_vxn(),
MagicBytes::Raw => self.init_raw(),
MagicBytes::Eos => self.init_eos(),
}
}
fn init_vx1(&mut self) -> crate::Result<()> {
let view = self.inner.view();
let n = self.fse_core.load_v1(view)?;
self.inner.skip(n as usize);
self.init_vx1_vx2_cont()
}
fn init_vx2(&mut self) -> crate::Result<()> {
let view = self.inner.view();
let n = self.fse_core.load_v2(view)?;
self.inner.skip(n as usize);
self.init_vx1_vx2_cont()
}
fn init_vx1_vx2_cont(&mut self) -> crate::Result<()> {
let view = self.inner.view();
let n = self.fse_core.load_literals(view)?;
self.inner.skip(n as usize);
let view = self.inner.view();
let n = self.fse_core.load_lmds(view)?;
self.inner.skip(n as usize);
self.fse_core.decode_n_init(&self.ring);
self.state = State::Fse;
Ok(())
}
fn init_vxn(&mut self) -> crate::Result<()> {
let view = self.inner.view();
let n = self.vn_core.load_short(view)?;
self.inner.skip(n as usize);
self.state = State::Vn;
Ok(())
}
fn init_raw(&mut self) -> crate::Result<()> {
let view = self.inner.view();
let n = self.raw_block.load_short(view)?;
self.inner.skip(n as usize);
self.state = State::Raw;
Ok(())
}
fn init_eos(&mut self) -> crate::Result<()> {
if self.inner.len() != 4 || !self.inner.is_eof() {
self.state = State::Err;
Err(crate::Error::PayloadOverflow)
} else {
self.state = State::Eos;
Ok(())
}
}
}
impl<'a, I: for<'b> ByteReader<'b>> Read for ReaderCore<'a, I> {
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
let mark = self.idx;
loop {
debug_assert!(self.idx <= self.ring.pos());
let limit = ((self.ring.pos() - self.idx) as usize).min(buf.len());
self.ring.copy(unsafe { buf.get_unchecked_mut(..limit) }, self.idx);
self.idx += limit as u32;
buf = unsafe { buf.get_unchecked_mut(limit..) };
if buf.is_empty() {
break;
}
if !self.fill()? {
break;
}
}
Ok((self.idx - mark) as usize)
}
}