#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "alloc")]
#[cfg_attr(test, macro_use)]
extern crate alloc;
#[cfg(any(feature = "tokio", feature = "async-std", feature = "futures_0_3"))]
use core::pin::Pin;
#[cfg(feature = "tokio")]
use actual_tokio as tokio;
#[cfg(feature = "async-std")]
use actual_async_std as async_std;
pub mod decoders;
pub mod encoders;
pub mod error;
pub mod int;
#[cfg(any(feature = "tokio", feature = "async-std", feature = "futures_0_3"))]
pub mod future;
mod macros;
use core::fmt;
use core::ops::ControlFlow;
pub trait Decoder: Sized {
type Value;
type Error;
fn decode_chunk(&mut self, bytes: &mut &[u8]) -> Result<(), Self::Error>;
fn end(self) -> Result<Self::Value, Self::Error>;
fn bytes_received(&mut self, mut bytes: &[u8]) -> Result<usize, Self::Error> {
let prev_len = bytes.len();
self.decode_chunk(&mut bytes)?;
Ok(prev_len - bytes.len())
}
fn then<R: Decoder, F: FnOnce(Self::Value) -> R>(self, fun: F) -> decoders::combinators::Then<Self, R, F> {
decoders::combinators::Then::new(self, fun)
}
fn then_try<E, R: Decoder, F: FnOnce(Self::Value) -> Result<R, E>>(self, fun: F) -> decoders::combinators::ThenTry<E, Self, R, F> where E: From<Self::Error> + From<R::Error> {
decoders::combinators::ThenTry::new(self, fun)
}
fn chain<D: Decoder>(self, following: D) -> decoders::combinators::Chain<Self, D> {
decoders::combinators::Chain::new(self, following)
}
fn take(&mut self) -> Result<Self::Value, Self::Error> where Self: Default {
core::mem::take(self).end()
}
fn sub_decode<E, F: FnMut(Self::Error) -> E>(&mut self, bytes: &mut &[u8], mut map_err: F) -> ControlFlow<Result<(), E>, Self::Value> where Self: Default {
if let Err(error) = self.decode_chunk(bytes) {
return ControlFlow::Break(Err(map_err(error)));
}
if bytes.is_empty() {
ControlFlow::Break(Ok(()))
} else {
match self.take() {
Ok(value) => ControlFlow::Continue(value),
Err(error) => ControlFlow::Break(Err(map_err(error))),
}
}
}
fn wrap_sub_decode<F: FnOnce() -> ControlFlow<Result<(), Self::Error>, core::convert::Infallible>>(f: F) -> Result<(), Self::Error> {
match f() {
ControlFlow::Continue(never) => match never {},
ControlFlow::Break(result) => result,
}
}
}
pub trait Encoder: Sized {
#[must_use = "This method only returns bytes and doesn't modify the target"]
fn encoded_chunk(&self) -> &[u8];
#[must_use = "Relying on encoded_chunk being empty is insufficient"]
fn next(&mut self) -> bool;
fn track_position(self) -> EncoderPositionTracker<Self> {
EncoderPositionTracker::new(self)
}
fn write_to_slice(mut self, buf: &mut &mut [u8]) -> Result<(), error::BufferOverflow> {
while !self.encoded_chunk().is_empty() {
let chunk = self.encoded_chunk();
if chunk.len() > buf.len() {
return Err(error::BufferOverflow { bytes_past_end: chunk.len() - buf.len()});
}
buf[..chunk.len()].copy_from_slice(chunk);
*buf = &mut core::mem::take(buf)[chunk.len()..];
if !self.next() {
break;
}
}
Ok(())
}
#[cfg(feature = "alloc")]
fn write_to_vec(mut self, buf: &mut alloc::vec::Vec<u8>) {
while !self.encoded_chunk().is_empty() {
buf.extend_from_slice(self.encoded_chunk());
if !self.next() {
break;
}
}
}
#[cfg(feature = "std")]
fn write_all_sync<W: std::io::Write + BufWrite>(mut self, mut writer: W) -> std::io::Result<()> {
while !self.encoded_chunk().is_empty() {
writer.write_all(self.encoded_chunk())?;
if !self.next() {
break;
}
}
Ok(())
}
#[cfg(feature = "lgio")]
fn write_all_sync_lgio<W: lgio::BufWrite>(mut self, mut writer: W) -> Result<(), W::WriteError> {
while !self.encoded_chunk().is_empty() {
writer.write_all(self.encoded_chunk())?;
if !self.next() {
break;
}
}
Ok(())
}
#[cfg(feature = "tokio")]
fn write_all_tokio<W: tokio::io::AsyncWrite + BufWrite>(self, writer: W) -> future::TokioEncodeFuture<W, Self> {
future::TokioEncodeFuture::new(writer, self)
}
#[cfg(feature = "async-std")]
fn write_all_async_std<W: async_std::io::Write + BufWrite>(self, writer: W) -> future::AsyncStdEncodeFuture<W, Self> {
future::AsyncStdEncodeFuture::new(writer, self)
}
#[cfg(feature = "futures_0_3")]
fn write_all_futures_0_3<W: futures_io_0_3::AsyncWrite + BufWrite>(self, writer: W) -> future::Futures0Dot3EncodeFuture<W, Self> {
future::Futures0Dot3EncodeFuture::new(writer, self)
}
fn then<E: Encoder, F: FnMut() -> E>(self, second_encoder_constructor: F) -> encoders::combinators::Then<Self, E, F> {
encoders::combinators::Then::new(self, second_encoder_constructor)
}
fn chain<T: Encoder>(self, second_encoder: T) -> encoders::combinators::Chain<Self, T> {
encoders::combinators::Chain::new(self, second_encoder)
}
}
#[cfg(any(feature = "std", feature = "tokio", feature = "async-std", feature = "futures_0_3"))]
pub trait BufWrite {}
#[cfg(any(feature = "std", feature = "tokio", feature = "async-std", feature = "futures_0_3"))]
impl<'a, T: BufWrite> BufWrite for &mut T {}
#[cfg(feature = "std")]
impl<T: std::io::Write> BufWrite for std::io::BufWriter<T> {}
#[cfg(feature = "tokio")]
impl<T: tokio::io::AsyncWrite> BufWrite for tokio::io::BufWriter<T> {}
#[cfg(feature = "async-std")]
impl<T: async_std::io::Write> BufWrite for async_std::io::BufWriter<T> {}
#[cfg(any(feature = "tokio", feature = "async-std", feature = "futures_0_3"))]
pin_project_lite::pin_project! {
pub struct AssumeBuffered<T> {
#[pin]
inner: T
}
}
#[cfg(all(feature = "std", not(any(feature = "tokio", feature = "async-std", feature = "futures_0_3"))))]
pub struct AssumeBuffered<T> {
inner: T,
}
#[cfg(any(feature = "std", feature = "tokio", feature = "async-std", feature = "futures_0_3"))]
impl<T> AssumeBuffered<T> {
pub fn new(writer: T) -> Self {
AssumeBuffered {
inner: writer,
}
}
pub fn inner(&self) -> &T {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut T {
&mut self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
}
#[cfg(any(feature = "std", feature = "tokio", feature = "async-std", feature = "futures_0_3"))]
impl<T> BufWrite for AssumeBuffered<T> {}
#[cfg(feature = "std")]
impl<T: std::io::Write> std::io::Write for AssumeBuffered<T> {
fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
self.inner.write(bytes)
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}
#[cfg(feature = "async-std")]
impl<T: async_std::io::Write> async_std::io::Write for AssumeBuffered<T> {
fn poll_write(self: Pin<&mut Self>, ctx: &mut core::task::Context, bytes: &[u8]) -> core::task::Poll<std::io::Result<usize>> {
self.project().inner.poll_write(ctx, bytes)
}
fn poll_flush(self: Pin<&mut Self>, ctx: &mut core::task::Context) -> core::task::Poll<std::io::Result<()>> {
self.project().inner.poll_flush(ctx)
}
fn poll_close(self: Pin<&mut Self>, ctx: &mut core::task::Context) -> core::task::Poll<std::io::Result<()>> {
self.project().inner.poll_close(ctx)
}
}
#[cfg(feature = "tokio")]
impl<T: tokio::io::AsyncWrite> tokio::io::AsyncWrite for AssumeBuffered<T> {
fn poll_write(self: Pin<&mut Self>, ctx: &mut core::task::Context, bytes: &[u8]) -> core::task::Poll<std::io::Result<usize>> {
self.project().inner.poll_write(ctx, bytes)
}
fn poll_flush(self: Pin<&mut Self>, ctx: &mut core::task::Context) -> core::task::Poll<std::io::Result<()>> {
self.project().inner.poll_flush(ctx)
}
fn poll_shutdown(self: Pin<&mut Self>, ctx: &mut core::task::Context) -> core::task::Poll<std::io::Result<()>> {
self.project().inner.poll_shutdown(ctx)
}
}
#[derive(Debug, Clone)]
pub struct EncoderPositionTracker<Enc> {
encoder: Enc,
pos: usize,
}
impl<Enc: Encoder> EncoderPositionTracker<Enc> {
fn new(encoder: Enc) -> Self {
EncoderPositionTracker {
encoder,
pos: 0,
}
}
#[must_use = "This method only returns bytes and doesn't modify the target"]
pub fn encoded_chunk(&self) -> &[u8] {
&self.encoder.encoded_chunk()[self.pos..]
}
#[track_caller]
pub fn consume(&mut self, amount: usize) {
self.pos += amount;
if self.pos >= self.encoder.encoded_chunk().len() {
debug_assert_eq!(self.pos, self.encoder.encoded_chunk().len());
if self.encoder.next() {
self.pos = 0;
}
}
}
#[cfg(feature = "std")]
pub fn write_once<W: std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<usize> {
if self.encoded_chunk().is_empty() {
return Ok(0);
}
let amount = writer.write(self.encoded_chunk())?;
self.consume(amount);
Ok(amount)
}
#[cfg(feature = "std")]
pub fn write_all<W: std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
while self.write_once(writer)? != 0 { }
Ok(())
}
}
#[cfg(feature = "std")]
pub fn decode_sync_with<D: Decoder, R: std::io::BufRead + ?Sized>(reader: &mut R, mut decoder: D) -> Result<D::Value, ReadError<D::Error>> {
loop {
let buf = match reader.fill_buf() {
Ok(buf) => buf,
Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue,
Err(error) => return Err(ReadError::Read(error)),
};
if buf.is_empty() {
break decoder.end().map_err(ReadError::Decode);
}
let num = decoder.bytes_received(buf).map_err(ReadError::Decode)?;
let buf_len = buf.len();
reader.consume(num);
if num < buf_len {
break decoder.end().map_err(ReadError::Decode);
}
}
}
#[cfg(feature = "std")]
pub fn decode_sync<D: Decoder + Default>(reader: &mut (impl std::io::BufRead + ?Sized)) -> Result<D::Value, ReadError<D::Error>> {
decode_sync_with(reader, D::default())
}
#[cfg(feature = "lgio")]
pub fn decode_sync_lgio_with<D: Decoder, R: lgio::BufRead + ?Sized>(reader: &mut R, mut decoder: D) -> Result<D::Value, ReadError<D::Error, R::ReadError>> {
loop {
let buf = reader.fill_buf().map_err(ReadError::Read)?;
if buf.is_empty() {
break decoder.end().map_err(ReadError::Decode);
}
let num = decoder.bytes_received(buf).map_err(ReadError::Decode)?;
let buf_len = buf.len();
reader.consume(num);
if num < buf_len {
break decoder.end().map_err(ReadError::Decode);
}
}
}
#[cfg(feature = "lgio")]
pub fn decode_sync_lgio<D: Decoder + Default, R: lgio::BufRead + ?Sized>(reader: &mut R) -> Result<D::Value, ReadError<D::Error, R::ReadError>> {
decode_sync_lgio_with(reader, D::default())
}
#[cfg(feature = "futures_0_3")]
pub async fn decode_futures_0_3_with<D: Decoder, R: futures_io_0_3::AsyncBufRead>(reader: R, decoder: D) -> Result<D::Value, ReadError<D::Error>> {
use futures_io_0_3::AsyncBufRead;
future::DecodeFuture {
reader,
poll_fn: <R as AsyncBufRead>::poll_fill_buf,
consume_fn: <R as AsyncBufRead>::consume,
decoder: Some(decoder),
}
.await
}
#[cfg(feature = "futures_0_3")]
pub async fn decode_futures_0_3<D: Decoder + Default>(reader: impl futures_io_0_3::AsyncBufRead) -> Result<D::Value, ReadError<D::Error>> {
decode_futures_0_3_with(reader, D::default()).await
}
#[cfg(feature = "tokio")]
pub async fn decode_tokio_with<D: Decoder, R: tokio::io::AsyncBufRead>(reader: R, decoder: D) -> Result<D::Value, ReadError<D::Error>> {
use tokio::io::AsyncBufRead;
future::DecodeFuture {
reader,
poll_fn: <R as AsyncBufRead>::poll_fill_buf,
consume_fn: <R as AsyncBufRead>::consume,
decoder: Some(decoder),
}
.await
}
#[cfg(feature = "tokio")]
pub async fn decode_tokio<D: Decoder + Default>(reader: impl tokio::io::AsyncBufRead) -> Result<D::Value, ReadError<D::Error>> {
decode_tokio_with(reader, D::default()).await
}
#[cfg(feature = "async-std")]
pub async fn decode_async_std_with<D: Decoder, R: async_std::io::BufRead>(reader: R, decoder: D) -> Result<D::Value, ReadError<D::Error>> {
use async_std::io::BufRead as AsyncBufRead;
future::DecodeFuture {
reader,
poll_fn: <R as AsyncBufRead>::poll_fill_buf,
consume_fn: <R as AsyncBufRead>::consume,
decoder: Some(decoder),
}
.await
}
#[cfg(feature = "async-std")]
pub async fn decode_async_std<D: Decoder + Default>(reader: impl async_std::io::BufRead) -> Result<D::Value, ReadError<D::Error>> {
decode_async_std_with(reader, D::default()).await
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(docsrs, doc(cfg(all())))]
#[cfg(not(feature = "std"))]
pub enum ReadError<Decode, Read> {
Read(Read),
Decode(Decode),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(docsrs, doc(cfg(all())))]
#[cfg(feature = "std")]
pub enum ReadError<Decode, Read = std::io::Error> {
Read(Read),
Decode(Decode),
}
impl<D, R> ReadError<D, R> {
pub fn convert_either<E>(self) -> E where D: Into<E>, R: Into<E> {
match self {
ReadError::Read(error) => error.into(),
ReadError::Decode(error) => error.into(),
}
}
pub fn map_read<E, F>(self, map: F) -> ReadError<D, E> where F: FnOnce(R) -> E {
match self {
ReadError::Read(error) => ReadError::Read(map(error)),
ReadError::Decode(error) => ReadError::Decode(error),
}
}
pub fn map_decode<E, F>(self, map: F) -> ReadError<E, R> where F: FnOnce(D) -> E {
match self {
ReadError::Read(error) => ReadError::Read(error),
ReadError::Decode(error) => ReadError::Decode(map(error)),
}
}
}
impl<E> ReadError<E, core::convert::Infallible> {
pub fn into_decode(self) -> E {
match self {
ReadError::Read(never) => match never {},
ReadError::Decode(error) => error,
}
}
}
impl<E> ReadError<core::convert::Infallible, E> {
pub fn into_read(self) -> E {
match self {
ReadError::Read(error) => error,
ReadError::Decode(never) => match never {},
}
}
}
impl From<ReadError<core::convert::Infallible, core::convert::Infallible>> for core::convert::Infallible {
fn from(error: ReadError<core::convert::Infallible, core::convert::Infallible>) -> Self {
match error {
ReadError::Read(error) => error,
ReadError::Decode(error) => error,
}
}
}
#[cfg(feature = "std")]
impl<E: std::error::Error + Send + Sync + 'static> From<ReadError<E, std::io::Error>> for std::io::Error {
fn from(error: ReadError<E, std::io::Error>) -> Self {
use std::io::ErrorKind;
match error {
ReadError::Read(error) => error,
ReadError::Decode(error) => std::io::Error::new(ErrorKind::InvalidData, error),
}
}
}
impl<D, R> fmt::Display for ReadError<D, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ReadError::Read(_) => write!(f, "reading failed"),
ReadError::Decode(_) => write!(f, "decoding failed"),
}
}
}
#[cfg(feature = "std")]
impl<D: std::error::Error + 'static, R: std::error::Error + 'static> std::error::Error for ReadError<D, R> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ReadError::Read(error) => Some(error),
ReadError::Decode(error) => Some(error),
}
}
}