use alloc::vec::Vec;
use crate::arsenic::pipeline::{self, DecodeOutcome};
use crate::error::Error;
use crate::traits::{RawDecoder, RawProgress};
pub struct Decoder {
input: Vec<u8>,
output: Vec<u8>,
out_pos: usize,
decoded: bool,
next_attempt_len: usize,
finished: bool,
poisoned: bool,
}
impl Decoder {
pub fn new() -> Self {
Self {
input: Vec::new(),
output: Vec::new(),
out_pos: 0,
decoded: false,
next_attempt_len: 1,
finished: false,
poisoned: false,
}
}
fn drain(&mut self, output: &mut [u8]) -> usize {
let avail = self.output.len() - self.out_pos;
let n = avail.min(output.len());
output[..n].copy_from_slice(&self.output[self.out_pos..self.out_pos + n]);
self.out_pos += n;
if self.out_pos == self.output.len() {
self.finished = true;
}
n
}
fn try_decode(&mut self) -> Result<bool, Error> {
match pipeline::decode_stream(&self.input)? {
DecodeOutcome::Complete(out) => {
self.output = out;
self.decoded = true;
Ok(true)
}
DecodeOutcome::NeedMore => {
self.next_attempt_len = (self.input.len() * 2).max(self.input.len() + 1);
Ok(false)
}
}
}
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
impl RawDecoder for Decoder {
fn raw_decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<RawProgress, Error> {
if self.poisoned {
return Err(Error::Corrupt);
}
if self.finished {
return Ok(RawProgress {
consumed: 0,
written: 0,
done: true,
});
}
if self.decoded {
let written = self.drain(output);
return Ok(RawProgress {
consumed: 0,
written,
done: self.finished,
});
}
let consumed = input.len();
if consumed > 0 {
self.input.extend_from_slice(input);
}
if self.input.len() < self.next_attempt_len {
return Ok(RawProgress {
consumed,
written: 0,
done: false,
});
}
match self.try_decode() {
Ok(true) => {
let written = self.drain(output);
Ok(RawProgress {
consumed,
written,
done: self.finished,
})
}
Ok(false) => {
Ok(RawProgress {
consumed,
written: 0,
done: false,
})
}
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error> {
if self.poisoned {
return Err(Error::Corrupt);
}
if self.finished {
return Ok(RawProgress {
consumed: 0,
written: 0,
done: true,
});
}
if !self.decoded {
match self.try_decode() {
Ok(true) => {}
Ok(false) => {
self.poisoned = true;
return Err(Error::UnexpectedEnd);
}
Err(e) => {
self.poisoned = true;
return Err(e);
}
}
}
let written = self.drain(output);
Ok(RawProgress {
consumed: 0,
written,
done: self.finished,
})
}
fn raw_reset(&mut self) {
self.input.clear();
self.output.clear();
self.out_pos = 0;
self.decoded = false;
self.next_attempt_len = 1;
self.finished = false;
self.poisoned = false;
}
}