pub mod decoders;
pub trait Decodable {
type Decoder: Decoder<Output = Self>;
fn decoder() -> Self::Decoder;
}
pub trait Decoder: Sized {
type Output;
type Error;
#[must_use = "must check result to avoid panics on subsequent calls"]
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error>;
#[must_use = "must check result to avoid panics on subsequent calls"]
fn end(self) -> Result<Self::Output, Self::Error>;
fn read_limit(&self) -> usize;
}
pub fn decode_from_slice<T>(bytes: &[u8]) -> Result<T, <T::Decoder as Decoder>::Error>
where
T: Decodable,
{
let mut decoder = T::decoder();
let mut remaining = bytes;
while !remaining.is_empty() {
if !decoder.push_bytes(&mut remaining)? {
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: Decodable,
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 need_more = decoder.push_bytes(&mut buffer).map_err(ReadError::Decode)?;
let consumed = original_len - buffer.len();
reader.consume(consumed);
if !need_more {
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: Decodable,
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: Decodable,
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)?
{
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)
}
#[cfg(feature = "std")]
#[derive(Debug)]
pub enum ReadError<D> {
Io(std::io::Error),
Decode(D),
}
#[cfg(feature = "std")]
impl<D: core::fmt::Display> core::fmt::Display for ReadError<D> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Io(e) => write!(f, "I/O error: {}", e),
Self::Decode(e) => write!(f, "decode error: {}", e),
}
}
}
#[cfg(feature = "std")]
impl<D> std::error::Error for ReadError<D>
where
D: core::fmt::Debug + core::fmt::Display + std::error::Error + 'static,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Decode(e) => Some(e),
}
}
}
#[cfg(feature = "std")]
impl<D> From<std::io::Error> for ReadError<D> {
fn from(e: std::io::Error) -> Self { Self::Io(e) }
}
#[cfg(test)]
mod tests {
#[cfg(feature = "std")]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::io::{Cursor, Read};
use super::*;
use crate::decode::decoders::{ArrayDecoder, UnexpectedEofError};
#[derive(Debug, PartialEq)]
struct TestArray([u8; 4]);
impl Decodable for TestArray {
type Decoder = TestArrayDecoder;
fn decoder() -> Self::Decoder { TestArrayDecoder { inner: ArrayDecoder::new() } }
}
struct TestArrayDecoder {
inner: ArrayDecoder<4>,
}
impl Decoder for TestArrayDecoder {
type Output = TestArray;
type Error = UnexpectedEofError;
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
self.inner.push_bytes(bytes)
}
fn end(self) -> Result<Self::Output, Self::Error> { self.inner.end().map(TestArray) }
fn read_limit(&self) -> usize { self.inner.read_limit() }
}
#[test]
fn decode_from_slice_success() {
let data = [1, 2, 3, 4];
let result: Result<TestArray, _> = decode_from_slice(&data);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
}
#[test]
fn decode_from_slice_unexpected_eof() {
let data = [1, 2, 3];
let result: Result<TestArray, _> = decode_from_slice(&data);
assert!(result.is_err());
}
#[test]
fn decode_from_slice_extra_data() {
let data = [1, 2, 3, 4, 5];
let result: Result<TestArray, _> = decode_from_slice(&data);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_extra_data() {
let data = [1, 2, 3, 4, 5, 6];
let mut cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read(&mut cursor);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_success() {
let data = [1, 2, 3, 4];
let cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read(cursor);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_unexpected_eof() {
let data = [1, 2, 3];
let cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read(cursor);
assert!(matches!(result, Err(ReadError::Decode(_))));
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_trait_object() {
let data = [1, 2, 3, 4];
let mut cursor = Cursor::new(&data);
let reader: &mut dyn std::io::BufRead = &mut cursor;
let result: Result<TestArray, _> = decode_from_read(reader);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_by_reference() {
let data = [1, 2, 3, 4];
let mut cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read(&mut cursor);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
let mut buf = Vec::new();
let _ = cursor.read_to_end(&mut buf);
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_unbuffered_success() {
let data = [1, 2, 3, 4];
let cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_unbuffered_unexpected_eof() {
let data = [1, 2, 3];
let cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
assert!(matches!(result, Err(ReadError::Decode(_))));
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_unbuffered_empty() {
let data = [];
let cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
assert!(matches!(result, Err(ReadError::Decode(_))));
}
#[test]
#[cfg(feature = "std")]
fn decode_from_read_unbuffered_extra_data() {
let data = [1, 2, 3, 4, 5, 6];
let cursor = Cursor::new(&data);
let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.0, [1, 2, 3, 4]);
}
}