use crate::{
buf::{BufResult, IoBufMut, IoVectoredBuf, IoVectoredBufMut},
io::{AsyncBufRead, AsyncRead, AsyncWrite, AsyncWriteExt},
};
pub struct BufWriter<W> {
writer: W,
buf: Box<[u8]>,
written: usize,
}
impl<W> BufWriter<W> {
#[inline]
pub fn new(inner: W) -> Self {
Self::with_capacity(8 * 1024, inner)
}
#[inline]
pub fn with_capacity(capacity: usize, writer: W) -> Self {
let buffer = vec![0; capacity];
Self {
writer,
buf: buffer.into_boxed_slice(),
written: 0,
}
}
#[inline]
pub fn get_ref(&self) -> &W {
&self.writer
}
#[inline]
pub fn get_mut(&mut self) -> &mut W {
&mut self.writer
}
#[inline]
pub fn into_inner(self) -> W {
self.writer
}
#[inline]
pub fn buffer(&self) -> &[u8] {
&self.buf.as_ref()[..self.written]
}
#[inline]
fn discard_buffer(&mut self) {
self.written = 0;
}
}
impl<W: AsyncWrite> BufWriter<W> {
async fn flush_buf(&mut self) -> std::io::Result<()> {
if self.written != 0 {
let buf = std::mem::take(&mut self.buf);
let (ret, buf) = self.writer.write_all(buf).await.into_parts();
self.buf = buf;
ret?;
self.discard_buffer();
}
Ok(())
}
}
impl<W: AsyncWrite> AsyncWrite for BufWriter<W> {
async fn write<B: crate::buf::IoBuf>(&mut self, buf: B) -> crate::buf::BufResult<usize, B> {
let writer_buf = self.buf.as_ref();
let writer_buf_written = writer_buf.len();
let bytes_to_write = buf.as_init().len();
if self.written + bytes_to_write > writer_buf_written {
match self.flush_buf().await {
Ok(_) => (),
Err(e) => {
return BufResult(Err(e), buf);
}
}
}
if bytes_to_write > writer_buf_written {
self.writer.write(buf).await
} else {
unsafe {
let writer_buf = self.buf.as_mut();
writer_buf
.as_mut_ptr()
.add(self.written)
.copy_from_nonoverlapping(buf.as_init().as_ptr(), bytes_to_write);
}
self.written += bytes_to_write;
BufResult(Ok(bytes_to_write), buf)
}
}
async fn write_vectored<V: IoVectoredBuf>(&mut self, bufs: V) -> crate::buf::BufResult<usize, V> {
if let Err(e) = self.flush_buf().await {
return BufResult(Err(e), bufs);
}
self.writer.write_vectored(bufs).await
}
async fn flush(&mut self) -> std::io::Result<()> {
self.flush_buf().await?;
self.writer.flush().await
}
async fn shutdown(&mut self) -> std::io::Result<()> {
self.flush_buf().await?;
self.writer.shutdown().await
}
}
impl<W: AsyncRead + AsyncWrite> AsyncRead for BufWriter<W> {
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
self.writer.read(buf).await
}
async fn read_vectored<V: IoVectoredBufMut>(&mut self, bufs: V) -> BufResult<usize, V> {
self.writer.read_vectored(bufs).await
}
}
impl<W: AsyncBufRead + AsyncWrite> AsyncBufRead for BufWriter<W> {
async fn fill_buf(&mut self) -> std::io::Result<&'_ [u8]> {
self.writer.fill_buf().await
}
fn consume(&mut self, amount: usize) {
self.writer.consume(amount)
}
fn buffer(&self) -> &[u8] {
self.writer.buffer()
}
}