io: read/write big-endian numbers (#1863)

Provide convenience methods for encoding and decoding big-endian numbers
on top of asynchronous I/O streams. Only primitive types are provided
(24 and 48 bit numbers are omitted).

In general, using these methods won't be the fastest way to do
encoding/decoding with asynchronous byte streams, but they help to get
simple things working fast.
This commit is contained in:
Carl Lerche 2019-11-30 13:13:21 -08:00 committed by GitHub
parent 8ce408492a
commit 1ea6733568
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1053 additions and 0 deletions

View File

@ -1,12 +1,31 @@
use crate::io::util::chain::{chain, Chain};
use crate::io::util::read::{read, Read};
use crate::io::util::read_exact::{read_exact, ReadExact};
use crate::io::util::read_int::{ReadU8, ReadU16, ReadU32, ReadU64, ReadU128};
use crate::io::util::read_int::{ReadI8, ReadI16, ReadI32, ReadI64, ReadI128};
use crate::io::util::read_to_end::{read_to_end, ReadToEnd};
use crate::io::util::read_to_string::{read_to_string, ReadToString};
use crate::io::util::take::{take, Take};
use crate::io::AsyncRead;
cfg_io_util! {
/// Define numeric reader
macro_rules! read_impl {
(
$(
$(#[$outer:meta])*
fn $name:ident(&mut self) -> $($fut:ident)*;
)*
) => {
$(
$(#[$outer])*
fn $name<'a>(&'a mut self) -> $($fut)*<&'a mut Self> where Self: Unpin {
$($fut)*::new(self)
}
)*
}
}
/// Read bytes from a source.
///
/// Implemented as an extention trait, adding utility methods to all
@ -199,6 +218,391 @@ cfg_io_util! {
read_exact(self, buf)
}
read_impl! {
/// Reads an unsigned 8 bit integer from the underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_u8(&mut self) -> io::Result<u8>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read unsigned 8 bit integers from an `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![2, 5]);
///
/// assert_eq!(2, reader.read_u8().await?);
/// assert_eq!(5, reader.read_u8().await?);
///
/// Ok(())
/// }
/// ```
fn read_u8(&mut self) -> ReadU8;
/// Reads a signed 8 bit integer from the underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_i8(&mut self) -> io::Result<i8>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read unsigned 8 bit integers from an `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![0x02, 0xfb]);
///
/// assert_eq!(2, reader.read_i8().await?);
/// assert_eq!(-5, reader.read_i8().await?);
///
/// Ok(())
/// }
/// ```
fn read_i8(&mut self) -> ReadI8;
/// Reads an unsigned 16-bit integer in big-endian order from the
/// underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_u16(&mut self) -> io::Result<u16>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read unsigned 16 bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![2, 5, 3, 0]);
///
/// assert_eq!(517, reader.read_u16().await?);
/// assert_eq!(768, reader.read_u16().await?);
/// Ok(())
/// }
/// ```
fn read_u16(&mut self) -> ReadU16;
/// Reads a signed 16-bit integer in big-endian order from the
/// underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_i16(&mut self) -> io::Result<i16>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read signed 16 bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![0x00, 0xc1, 0xff, 0x7c]);
///
/// assert_eq!(193, reader.read_i16().await?);
/// assert_eq!(-132, reader.read_i16().await?);
/// Ok(())
/// }
/// ```
fn read_i16(&mut self) -> ReadI16;
/// Reads an unsigned 32-bit integer in big-endian order from the
/// underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_u32(&mut self) -> io::Result<u32>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read unsigned 32-bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![0x00, 0x00, 0x01, 0x0b]);
///
/// assert_eq!(267, reader.read_u32().await?);
/// Ok(())
/// }
/// ```
fn read_u32(&mut self) -> ReadU32;
/// Reads a signed 32-bit integer in big-endian order from the
/// underlying reader.
///
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_i32(&mut self) -> io::Result<i32>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read signed 32-bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![0xff, 0xff, 0x7a, 0x33]);
///
/// assert_eq!(-34253, reader.read_i32().await?);
/// Ok(())
/// }
/// ```
fn read_i32(&mut self) -> ReadI32;
/// Reads an unsigned 64-bit integer in big-endian order from the
/// underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_u64(&mut self) -> io::Result<u64>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read unsigned 64-bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![
/// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83
/// ]);
///
/// assert_eq!(918733457491587, reader.read_u64().await?);
/// Ok(())
/// }
/// ```
fn read_u64(&mut self) -> ReadU64;
/// Reads an signed 64-bit integer in big-endian order from the
/// underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_i64(&mut self) -> io::Result<i64>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read signed 64-bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![0x80, 0, 0, 0, 0, 0, 0, 0]);
///
/// assert_eq!(i64::min_value(), reader.read_i64().await?);
/// Ok(())
/// }
/// ```
fn read_i64(&mut self) -> ReadI64;
/// Reads an unsigned 128-bit integer in big-endian order from the
/// underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_u128(&mut self) -> io::Result<u128>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read unsigned 128-bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![
/// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83,
/// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83
/// ]);
///
/// assert_eq!(16947640962301618749969007319746179, reader.read_u128().await?);
/// Ok(())
/// }
/// ```
fn read_u128(&mut self) -> ReadU128;
/// Reads an signed 128-bit integer in big-endian order from the
/// underlying reader.
///
/// Equivalent to:
///
/// ```ignore
/// async fn read_i128(&mut self) -> io::Result<i128>;
/// ```
///
/// It is recommended to use a buffered reader to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncReadExt::read_exact`].
///
/// [`AsyncReadExt::read_exact`]: AsyncReadExt::read_exact
///
/// # Examples
///
/// Read signed 128-bit big-endian integers from a `AsyncRead`:
///
/// ```rust
/// use tokio::io::{self, AsyncReadExt};
///
/// use std::io::Cursor;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut reader = Cursor::new(vec![
/// 0x80, 0, 0, 0, 0, 0, 0, 0,
/// 0, 0, 0, 0, 0, 0, 0, 0
/// ]);
///
/// assert_eq!(i128::min_value(), reader.read_i128().await?);
/// Ok(())
/// }
/// ```
fn read_i128(&mut self) -> ReadI128;
}
/// Read all bytes until EOF in this source, placing them into `buf`.
///
/// Equivalent to:

View File

@ -2,9 +2,28 @@ use crate::io::util::flush::{flush, Flush};
use crate::io::util::shutdown::{shutdown, Shutdown};
use crate::io::util::write::{write, Write};
use crate::io::util::write_all::{write_all, WriteAll};
use crate::io::util::write_int::{WriteU8, WriteU16, WriteU32, WriteU64, WriteU128};
use crate::io::util::write_int::{WriteI8, WriteI16, WriteI32, WriteI64, WriteI128};
use crate::io::AsyncWrite;
cfg_io_util! {
/// Define numeric writer
macro_rules! write_impl {
(
$(
$(#[$outer:meta])*
fn $name:ident(&mut self, n: $ty:ty) -> $($fut:ident)*;
)*
) => {
$(
$(#[$outer])*
fn $name<'a>(&'a mut self, n: $ty) -> $($fut)*<&'a mut Self> where Self: Unpin {
$($fut)*::new(self, n)
}
)*
}
}
/// Write bytes to a sink.
///
/// Implemented as an extention trait, adding utility methods to all
@ -129,6 +148,390 @@ cfg_io_util! {
write_all(self, src)
}
write_impl! {
/// Writes an unsigned 8-bit integer to the underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_u8(&mut self, n: u8) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write unsigned 8 bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_u8(2).await?;
/// writer.write_u8(5).await?;
///
/// assert_eq!(writer, b"\x02\x05");
/// Ok(())
/// }
/// ```
fn write_u8(&mut self, n: u8) -> WriteU8;
/// Writes an unsigned 8-bit integer to the underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_i8(&mut self, n: i8) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write unsigned 8 bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_u8(2).await?;
/// writer.write_u8(5).await?;
///
/// assert_eq!(writer, b"\x02\x05");
/// Ok(())
/// }
/// ```
fn write_i8(&mut self, n: i8) -> WriteI8;
/// Writes an unsigned 16-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_u16(&mut self, n: u16) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write unsigned 16-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_u16(517).await?;
/// writer.write_u16(768).await?;
///
/// assert_eq!(writer, b"\x02\x05\x03\x00");
/// Ok(())
/// }
/// ```
fn write_u16(&mut self, n: u16) -> WriteU16;
/// Writes a signed 16-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_i16(&mut self, n: i16) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write signed 16-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_i16(193).await?;
/// writer.write_i16(-132).await?;
///
/// assert_eq!(writer, b"\x00\xc1\xff\x7c");
/// Ok(())
/// }
/// ```
fn write_i16(&mut self, n: i16) -> WriteI16;
/// Writes an unsigned 32-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_u32(&mut self, n: u32) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write unsigned 32-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_u32(267).await?;
/// writer.write_u32(1205419366).await?;
///
/// assert_eq!(writer, b"\x00\x00\x01\x0b\x47\xd9\x3d\x66");
/// Ok(())
/// }
/// ```
fn write_u32(&mut self, n: u32) -> WriteU32;
/// Writes a signed 32-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_i32(&mut self, n: i32) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write signed 32-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_i32(267).await?;
/// writer.write_i32(1205419366).await?;
///
/// assert_eq!(writer, b"\x00\x00\x01\x0b\x47\xd9\x3d\x66");
/// Ok(())
/// }
/// ```
fn write_i32(&mut self, n: i32) -> WriteI32;
/// Writes an unsigned 64-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_u64(&mut self, n: u64) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write unsigned 64-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_u64(918733457491587).await?;
/// writer.write_u64(143).await?;
///
/// assert_eq!(writer, b"\x00\x03\x43\x95\x4d\x60\x86\x83\x00\x00\x00\x00\x00\x00\x00\x8f");
/// Ok(())
/// }
/// ```
fn write_u64(&mut self, n: u64) -> WriteU64;
/// Writes an signed 64-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_i64(&mut self, n: i64) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write signed 64-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_i64(i64::min_value()).await?;
/// writer.write_i64(i64::max_value()).await?;
///
/// assert_eq!(writer, b"\x80\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff");
/// Ok(())
/// }
/// ```
fn write_i64(&mut self, n: i64) -> WriteI64;
/// Writes an unsigned 128-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_u128(&mut self, n: u128) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write unsigned 128-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_u128(16947640962301618749969007319746179).await?;
///
/// assert_eq!(writer, vec![
/// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83,
/// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83
/// ]);
/// Ok(())
/// }
/// ```
fn write_u128(&mut self, n: u128) -> WriteU128;
/// Writes an signed 128-bit integer in big-endian order to the
/// underlying writer.
///
/// Equivalent to:
///
/// ```ignore
/// async fn write_i128(&mut self, n: i128) -> io::Result<()>;
/// ```
///
/// It is recommended to use a buffered writer to avoid excessive
/// syscalls.
///
/// # Errors
///
/// This method returns the same errors as [`AsyncWriteExt::write_all`].
///
/// [`AsyncWriteExt::write_all`]: AsyncWriteExt::write_all
///
/// # Examples
///
/// Write signed 128-bit integers to a `AsyncWrite`:
///
/// ```rust
/// use tokio::io::{self, AsyncWriteExt};
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let mut writer = Vec::new();
///
/// writer.write_i128(i128::min_value()).await?;
///
/// assert_eq!(writer, vec![
/// 0x80, 0, 0, 0, 0, 0, 0, 0,
/// 0, 0, 0, 0, 0, 0, 0, 0
/// ]);
/// Ok(())
/// }
/// ```
fn write_i128(&mut self, n: i128) -> WriteI128;
}
/// Flush this output stream, ensuring that all intermediately buffered
/// contents reach their destination.
///

View File

@ -34,6 +34,7 @@ cfg_io_util! {
mod read;
mod read_exact;
mod read_int;
mod read_line;
mod read_to_end;
@ -60,6 +61,8 @@ cfg_io_util! {
mod write;
mod write_all;
mod write_int;
// used by `BufReader` and `BufWriter`
// https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1

View File

@ -0,0 +1,122 @@
use crate::io::AsyncRead;
use bytes::Buf;
use pin_project_lite::pin_project;
use std::future::Future;
use std::io;
use std::io::ErrorKind::UnexpectedEof;
use std::mem::size_of;
use std::pin::Pin;
use std::task::{Context, Poll};
macro_rules! reader {
($name:ident, $ty:ty, $reader:ident) => {
reader!($name, $ty, $reader, size_of::<$ty>());
};
($name:ident, $ty:ty, $reader:ident, $bytes:expr) => {
pin_project! {
#[doc(hidden)]
pub struct $name<R> {
#[pin]
src: R,
buf: [u8; $bytes],
read: u8,
}
}
impl<R> $name<R> {
pub(crate) fn new(src: R) -> Self {
$name {
src,
buf: [0; $bytes],
read: 0,
}
}
}
impl<R> Future for $name<R>
where
R: AsyncRead,
{
type Output = io::Result<$ty>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut me = self.project();
if *me.read == $bytes as u8 {
return Poll::Ready(Ok(Buf::$reader(&mut &me.buf[..])));
}
while *me.read < $bytes as u8 {
*me.read += match me.src
.as_mut()
.poll_read(cx, &mut me.buf[*me.read as usize..])
{
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
Poll::Ready(Ok(0)) => {
return Poll::Ready(Err(UnexpectedEof.into()));
}
Poll::Ready(Ok(n)) => n as u8,
};
}
let num = Buf::$reader(&mut &me.buf[..]);
Poll::Ready(Ok(num))
}
}
};
}
macro_rules! reader8 {
($name:ident, $ty:ty) => {
pin_project! {
/// Future returned from `read_u8`
#[doc(hidden)]
pub struct $name<R> {
#[pin]
reader: R,
}
}
impl<R> $name<R> {
pub(crate) fn new(reader: R) -> $name<R> {
$name { reader }
}
}
impl<R> Future for $name<R>
where
R: AsyncRead,
{
type Output = io::Result<$ty>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = self.project();
let mut buf = [0; 1];
match me.reader.poll_read(cx, &mut buf[..]) {
Poll::Pending => Poll::Pending,
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
Poll::Ready(Ok(0)) => Poll::Ready(Err(UnexpectedEof.into())),
Poll::Ready(Ok(1)) => Poll::Ready(Ok(buf[0] as $ty)),
Poll::Ready(Ok(_)) => unreachable!(),
}
}
}
};
}
reader8!(ReadU8, u8);
reader8!(ReadI8, i8);
reader!(ReadU16, u16, get_u16);
reader!(ReadU32, u32, get_u32);
reader!(ReadU64, u64, get_u64);
reader!(ReadU128, u128, get_u128);
reader!(ReadI16, i16, get_i16);
reader!(ReadI32, i32, get_i32);
reader!(ReadI64, i64, get_i64);
reader!(ReadI128, i128, get_i128);

View File

@ -0,0 +1,121 @@
use crate::io::AsyncWrite;
use bytes::BufMut;
use pin_project_lite::pin_project;
use std::future::Future;
use std::io;
use std::mem::size_of;
use std::pin::Pin;
use std::task::{Context, Poll};
macro_rules! writer {
($name:ident, $ty:ty, $writer:ident) => {
writer!($name, $ty, $writer, size_of::<$ty>());
};
($name:ident, $ty:ty, $writer:ident, $bytes:expr) => {
pin_project! {
#[doc(hidden)]
pub struct $name<W> {
#[pin]
dst: W,
buf: [u8; $bytes],
written: u8,
}
}
impl<W> $name<W> {
pub(crate) fn new(w: W, value: $ty) -> Self {
let mut writer = $name {
buf: [0; $bytes],
written: 0,
dst: w,
};
BufMut::$writer(&mut &mut writer.buf[..], value);
writer
}
}
impl<W> Future for $name<W>
where
W: AsyncWrite,
{
type Output = io::Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut me = self.project();
if *me.written == $bytes as u8 {
return Poll::Ready(Ok(()));
}
while *me.written < $bytes as u8 {
*me.written += match me.dst
.as_mut()
.poll_write(cx, &me.buf[*me.written as usize..])
{
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
Poll::Ready(Ok(n)) => n as u8,
};
}
Poll::Ready(Ok(()))
}
}
};
}
macro_rules! writer8 {
($name:ident, $ty:ty) => {
pin_project! {
#[doc(hidden)]
pub struct $name<W> {
#[pin]
dst: W,
byte: $ty,
}
}
impl<W> $name<W> {
pub(crate) fn new(dst: W, byte: $ty) -> Self {
Self {
dst,
byte,
}
}
}
impl<W> Future for $name<W>
where
W: AsyncWrite,
{
type Output = io::Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = self.project();
let buf = [*me.byte as u8];
match me.dst.poll_write(cx, &buf[..]) {
Poll::Pending => Poll::Pending,
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
Poll::Ready(Ok(0)) => Poll::Pending,
Poll::Ready(Ok(1)) => Poll::Ready(Ok(())),
Poll::Ready(Ok(_)) => unreachable!(),
}
}
}
};
}
writer8!(WriteU8, u8);
writer8!(WriteI8, i8);
writer!(WriteU16, u16, put_u16);
writer!(WriteU32, u32, put_u32);
writer!(WriteU64, u64, put_u64);
writer!(WriteU128, u128, put_u128);
writer!(WriteI16, i16, put_i16);
writer!(WriteI32, i32, put_i32);
writer!(WriteI64, i64, put_i64);
writer!(WriteI128, i128, put_i128);