use std::future::Future;
use std::io;
pub trait AsyncRead {
fn read(&self, buf: &mut [u8]) -> impl Future<Output = io::Result<usize>> + Send;
}
pub trait AsyncWrite {
fn write(&self, buf: &[u8]) -> impl Future<Output = io::Result<usize>> + Send;
}
#[inline]
pub async fn copy<R: AsyncRead + Sync + ?Sized, W: AsyncWrite + Sync + ?Sized>(
reader: &R,
writer: &W,
) -> io::Result<u64> {
let mut buf = [0u8; 8192];
let mut total: u64 = 0;
loop {
let n = reader.read(&mut buf).await?;
if n == 0 {
return Ok(total);
}
let mut written = 0;
while written < n {
let w = writer.write(&buf[written..n]).await?;
if w == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"dtact-io: copy's writer reported 0 bytes written for a nonempty buffer",
));
}
written += w;
}
total += written as u64;
}
}
pub struct BufReader<T> {
inner: T,
buf: Box<[u8]>,
pos: usize,
filled: usize,
}
impl<T> BufReader<T> {
pub fn new(inner: T) -> Self {
Self::with_capacity(8192, inner)
}
#[must_use]
pub fn with_capacity(capacity: usize, inner: T) -> Self {
Self {
inner,
buf: vec![0u8; capacity.max(1)].into_boxed_slice(),
pos: 0,
filled: 0,
}
}
pub const fn get_ref(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T: AsyncRead> BufReader<T> {
#[inline]
pub async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.pos == self.filled {
let n = self.inner.read(&mut self.buf).await?;
self.pos = 0;
self.filled = n;
if n == 0 {
return Ok(0);
}
}
let available = &self.buf[self.pos..self.filled];
let n = available.len().min(buf.len());
buf[..n].copy_from_slice(&available[..n]);
self.pos += n;
Ok(n)
}
}
pub struct BufWriter<T> {
inner: T,
buf: Vec<u8>,
capacity: usize,
}
impl<T> BufWriter<T> {
pub fn new(inner: T) -> Self {
Self::with_capacity(8192, inner)
}
#[must_use]
pub fn with_capacity(capacity: usize, inner: T) -> Self {
let capacity = capacity.max(1);
Self {
inner,
buf: Vec::with_capacity(capacity),
capacity,
}
}
pub const fn get_ref(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T: AsyncWrite> BufWriter<T> {
#[inline]
pub async fn write(&mut self, data: &[u8]) -> io::Result<usize> {
if data.len() >= self.capacity {
self.flush().await?;
return self.inner.write(data).await;
}
if self.buf.len() + data.len() > self.capacity {
self.flush().await?;
}
self.buf.extend_from_slice(data);
Ok(data.len())
}
#[inline(always)]
pub async fn flush(&mut self) -> io::Result<()> {
let mut written = 0;
while written < self.buf.len() {
let n = self.inner.write(&self.buf[written..]).await?;
if n == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"dtact-io: BufWriter's wrapped stream reported 0 bytes written",
));
}
written += n;
}
self.buf.clear();
Ok(())
}
}