use crate::{Decoder, Error, Progress, Status};
pub struct LimitedDecoder<D: Decoder> {
inner: D,
limit: u64,
written: u64,
}
impl<D: Decoder> LimitedDecoder<D> {
pub fn new(inner: D, max_output_bytes: u64) -> Self {
Self {
inner,
limit: max_output_bytes,
written: 0,
}
}
pub fn bytes_written(&self) -> u64 {
self.written
}
pub fn remaining(&self) -> u64 {
self.limit.saturating_sub(self.written)
}
pub fn get_ref(&self) -> &D {
&self.inner
}
pub fn get_mut(&mut self) -> &mut D {
&mut self.inner
}
pub fn into_inner(self) -> D {
self.inner
}
}
impl<D: Decoder> Decoder for LimitedDecoder<D> {
fn decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<(Progress, Status), Error> {
let remaining = self.remaining();
let cap = core::cmp::min(remaining as usize, output.len());
let (p, status) = self.inner.decode(input, &mut output[..cap])?;
self.written = self.written.saturating_add(p.written as u64);
if remaining == 0 && matches!(status, Status::OutputFull) {
return Err(Error::OutputLimitExceeded);
}
Ok((p, status))
}
fn finish(&mut self, output: &mut [u8]) -> Result<(Progress, Status), Error> {
let remaining = self.remaining();
let cap = core::cmp::min(remaining as usize, output.len());
let (p, status) = self.inner.finish(&mut output[..cap])?;
self.written = self.written.saturating_add(p.written as u64);
if remaining == 0 && matches!(status, Status::OutputFull) {
return Err(Error::OutputLimitExceeded);
}
Ok((p, status))
}
fn reset(&mut self) {
self.inner.reset();
self.written = 0;
}
fn discard_output(&mut self, input: &[u8], n: usize) -> Result<(Progress, Status), Error> {
self.inner.discard_output(input, n)
}
}