use crate::error::Error;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Progress {
pub consumed: usize,
pub written: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Status {
InputEmpty,
OutputFull,
StreamEnd,
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct RawProgress {
pub consumed: usize,
pub written: usize,
pub done: bool,
}
#[doc(hidden)]
pub trait RawEncoder {
fn raw_encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<RawProgress, Error>;
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error>;
fn raw_reset(&mut self);
}
#[doc(hidden)]
pub trait RawDecoder {
fn raw_decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<RawProgress, Error>;
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error>;
fn raw_reset(&mut self);
fn raw_skip(&mut self, input: &[u8], n: usize) -> Result<RawProgress, Error> {
let mut scratch = [0u8; 1024];
let mut consumed = 0usize;
let mut written = 0usize;
while written < n {
let want = (n - written).min(scratch.len());
let p = self.raw_decode(&input[consumed..], &mut scratch[..want])?;
consumed += p.consumed;
written += p.written;
if p.consumed == 0 && p.written == 0 {
break;
}
}
Ok(RawProgress {
consumed,
written,
done: false,
})
}
}
pub trait Encoder {
fn encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<(Progress, Status), Error>;
fn finish(&mut self, output: &mut [u8]) -> Result<(Progress, Status), Error>;
fn reset(&mut self);
}
pub trait Decoder {
fn decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<(Progress, Status), Error>;
fn finish(&mut self, output: &mut [u8]) -> Result<(Progress, Status), Error>;
fn reset(&mut self);
fn discard_output(&mut self, input: &[u8], n: usize) -> Result<(Progress, Status), Error>;
}
impl<T: RawEncoder> Encoder for T {
fn encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<(Progress, Status), Error> {
let p = self.raw_encode(input, output)?;
let status = if p.consumed >= input.len() {
Status::InputEmpty
} else {
Status::OutputFull
};
Ok((
Progress {
consumed: p.consumed,
written: p.written,
},
status,
))
}
fn finish(&mut self, output: &mut [u8]) -> Result<(Progress, Status), Error> {
let p = self.raw_finish(output)?;
let status = if p.done {
Status::StreamEnd
} else {
Status::OutputFull
};
Ok((
Progress {
consumed: 0,
written: p.written,
},
status,
))
}
fn reset(&mut self) {
self.raw_reset()
}
}
impl<T: RawDecoder> Decoder for T {
fn decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<(Progress, Status), Error> {
let p = self.raw_decode(input, output)?;
let status = if p.done {
Status::StreamEnd
} else if p.consumed >= input.len() {
Status::InputEmpty
} else {
Status::OutputFull
};
Ok((
Progress {
consumed: p.consumed,
written: p.written,
},
status,
))
}
fn finish(&mut self, output: &mut [u8]) -> Result<(Progress, Status), Error> {
let p = self.raw_finish(output)?;
let status = if p.done {
Status::StreamEnd
} else {
Status::OutputFull
};
Ok((
Progress {
consumed: 0,
written: p.written,
},
status,
))
}
fn reset(&mut self) {
self.raw_reset()
}
fn discard_output(&mut self, input: &[u8], n: usize) -> Result<(Progress, Status), Error> {
let p = self.raw_skip(input, n)?;
let status = if p.done {
Status::StreamEnd
} else if p.written >= n {
Status::OutputFull
} else if p.consumed >= input.len() {
Status::InputEmpty
} else {
Status::OutputFull
};
Ok((
Progress {
consumed: p.consumed,
written: p.written,
},
status,
))
}
}
pub trait Algorithm {
const NAME: &'static str;
type Encoder: Encoder;
type Decoder: Decoder;
type EncoderConfig: Clone + Default;
type DecoderConfig: Clone + Default;
fn encoder() -> Self::Encoder {
Self::encoder_with(Self::EncoderConfig::default())
}
fn encoder_with(config: Self::EncoderConfig) -> Self::Encoder;
fn decoder() -> Self::Decoder {
Self::decoder_with(Self::DecoderConfig::default())
}
fn decoder_with(config: Self::DecoderConfig) -> Self::Decoder;
}