pub mod decoders;
#[cfg(feature = "std")]
use crate::ReadError;
use crate::{DecodeError, UnconsumedError};
pub trait Decode {
type Decoder: Decoder<Output = Self> + Default;
fn decoder() -> Self::Decoder { Self::Decoder::default() }
}
pub trait Decoder: Sized {
type Output;
type Error;
#[must_use = "must check result to avoid panics on subsequent calls"]
#[track_caller]
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error>;
#[must_use = "must check result to avoid panics on subsequent calls"]
#[track_caller]
fn end(self) -> Result<Self::Output, Self::Error>;
fn read_limit(&self) -> usize;
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DecoderStatus {
NeedsMore,
Ready,
}
impl DecoderStatus {
pub fn needs_more(&self) -> bool { matches!(self, Self::NeedsMore) }
pub fn is_ready(&self) -> bool { matches!(self, Self::Ready) }
}
pub fn decode_from_slice<T: Decode>(
bytes: &[u8],
) -> Result<T, DecodeError<<T::Decoder as Decoder>::Error>> {
let mut remaining = bytes;
let data = decode_from_slice_unbounded::<T>(&mut remaining).map_err(DecodeError::Parse)?;
if remaining.is_empty() {
Ok(data)
} else {
Err(DecodeError::Unconsumed(UnconsumedError()))
}
}
pub fn decode_from_slice_unbounded<T>(
bytes: &mut &[u8],
) -> Result<T, <T::Decoder as Decoder>::Error>
where
T: Decode,
{
let mut decoder = T::decoder();
while !bytes.is_empty() {
if decoder.push_bytes(bytes)?.is_ready() {
break;
}
}
decoder.end()
}
#[cfg(feature = "std")]
pub fn decode_from_read<T, R>(mut reader: R) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
where
T: Decode,
R: std::io::BufRead,
{
let mut decoder = T::decoder();
loop {
let mut buffer = match reader.fill_buf() {
Ok(buffer) => buffer,
Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue,
Err(error) => return Err(ReadError::Io(error)),
};
if buffer.is_empty() {
return decoder.end().map_err(ReadError::Decode);
}
let original_len = buffer.len();
let status = decoder.push_bytes(&mut buffer).map_err(ReadError::Decode)?;
let consumed = original_len - buffer.len();
reader.consume(consumed);
if status.is_ready() {
return decoder.end().map_err(ReadError::Decode);
}
}
}
#[cfg(feature = "std")]
pub fn decode_from_read_unbuffered<T, R>(
reader: R,
) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
where
T: Decode,
R: std::io::Read,
{
decode_from_read_unbuffered_with::<T, R, 4096>(reader)
}
#[cfg(feature = "std")]
pub fn decode_from_read_unbuffered_with<T, R, const BUFFER_SIZE: usize>(
mut reader: R,
) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
where
T: Decode,
R: std::io::Read,
{
let mut decoder = T::decoder();
let mut buffer = [0u8; BUFFER_SIZE];
while decoder.read_limit() > 0 {
let clamped_buffer = &mut buffer[..decoder.read_limit().min(BUFFER_SIZE)];
match reader.read(clamped_buffer) {
Ok(0) => {
return decoder.end().map_err(ReadError::Decode);
}
Ok(bytes_read) => {
if decoder
.push_bytes(&mut &clamped_buffer[..bytes_read])
.map_err(ReadError::Decode)?
.is_ready()
{
return decoder.end().map_err(ReadError::Decode);
}
}
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {
}
Err(e) => return Err(ReadError::Io(e)),
}
}
decoder.end().map_err(ReadError::Decode)
}
#[track_caller]
pub fn check_decode<T: Decode + Eq + core::fmt::Debug>(bytes: &[u8], expected: &T)
where
<T::Decoder as Decoder>::Error: core::fmt::Debug,
{
let decoder = T::decoder();
check_decoder(decoder, bytes, expected);
}
#[track_caller]
pub fn check_decoder<D: Decoder>(mut decoder: D, mut bytes: &[u8], expected: &D::Output)
where
D::Output: Eq + core::fmt::Debug,
D::Error: core::fmt::Debug,
{
loop {
match decoder.push_bytes(&mut bytes) {
Ok(status) => {
if status.is_ready() {
break;
}
assert!(!bytes.is_empty(), "decoder needs more data but no bytes remaining");
}
Err(e) => panic!("decoder failed with error: {e:?}"),
}
}
match decoder.end() {
Ok(result) => {
assert_eq!(&result, expected, "decoded value doesn't match expected value");
}
Err(e) => panic!("decoder finalization failed with error: {e:?}"),
}
}