use std::io;
use std::ops::{Deref, DerefMut};
use crate::runtime::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
const RBUF_SIZE: usize = 8 * 1024;
pub struct BufStream<S> {
pub(crate) stream: S,
stream_eof: bool,
wbuf: Vec<u8>,
rbuf: Vec<u8>,
rbuf_rindex: usize,
rbuf_windex: usize,
}
impl<S> BufStream<S>
where
S: AsyncRead + AsyncWrite + Unpin,
{
pub fn new(stream: S) -> Self {
Self {
stream,
stream_eof: false,
wbuf: Vec::with_capacity(1024),
rbuf: vec![0; RBUF_SIZE],
rbuf_rindex: 0,
rbuf_windex: 0,
}
}
#[inline]
pub fn buffer_mut(&mut self) -> &mut Vec<u8> {
&mut self.wbuf
}
#[inline]
pub async fn flush(&mut self) -> io::Result<()> {
if !self.wbuf.is_empty() {
self.stream.write_all(&self.wbuf).await?;
self.wbuf.clear();
}
Ok(())
}
pub fn clear_bufs(&mut self) {
self.rbuf_rindex = 0;
self.rbuf_windex = 0;
self.wbuf.clear();
}
#[inline]
pub fn consume(&mut self, cnt: usize) {
self.rbuf_rindex += cnt;
}
pub async fn peek(&mut self, cnt: usize) -> io::Result<Option<&[u8]>> {
loop {
if self.stream_eof {
return Ok(None);
}
if self.rbuf_windex >= (self.rbuf_rindex + cnt) {
let buf = &self.rbuf[self.rbuf_rindex..(self.rbuf_rindex + cnt)];
return Ok(Some(buf));
}
if self.rbuf.len() < (self.rbuf_windex + cnt) {
if self.rbuf_rindex == self.rbuf_windex {
self.rbuf_rindex = 0;
self.rbuf_windex = 0;
} else {
let mut new_rbuf = Vec::with_capacity(RBUF_SIZE);
let min_index = self.rbuf_rindex.min(self.rbuf_windex);
new_rbuf.extend_from_slice(&self.rbuf[min_index..]);
new_rbuf.resize(new_rbuf.capacity(), 0);
self.rbuf = new_rbuf;
self.rbuf_rindex -= min_index;
self.rbuf_windex -= min_index;
}
if self.rbuf.len() < (self.rbuf_windex + cnt) {
let needed = (self.rbuf_windex + cnt) - self.rbuf.len();
self.rbuf.resize(self.rbuf.len() + needed, 0);
}
}
let n = self.stream.read(&mut self.rbuf[self.rbuf_windex..]).await?;
self.rbuf_windex += n;
if n == 0 {
self.stream_eof = true;
}
}
}
}
impl<S> Deref for BufStream<S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.stream
}
}
impl<S> DerefMut for BufStream<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stream
}
}
#[allow(unused)]
macro_rules! ret_if_none {
($val:expr) => {
match $val {
Some(val) => val,
None => {
return Ok(None);
}
}
};
}