use core::{cmp::min, pin::Pin, task::{Context, Poll}};
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;
#[allow(unused)]
use futures::{AsyncRead, AsyncBufRead, AsyncWrite, io::Result, ready};
pub struct BufferCursor {
offset: usize,
len: usize,
}
impl BufferCursor {
#[inline(always)]
pub fn new(buf: &[u8]) -> Self {
Self::with_len(buf.len())
}
#[inline(always)]
pub fn with_len(len: usize) -> Self {
Self {
offset: 0,
len,
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
pub fn is_pending(&self) -> bool {
self.offset < self.len
}
pub(crate) fn extend_len(&mut self, n: usize) {
self.len += n;
}
fn is_error(&self) -> bool {
self.len == 0
}
fn mark_as_error(&mut self) {
self.len = 0;
}
fn remaining(&self) -> usize {
self.len - self.offset
}
fn advance(&mut self, n: usize) {
self.offset += min(n, self.remaining());
}
pub fn write_remaining<W>(&mut self, mut writer: &mut W, data: &[u8], cx: &mut Context<'_>) -> Poll<Result<()>>
where
W: AsyncWrite + Unpin,
{
if self.len > data.len() {
self.mark_as_error();
return Poll::Ready(Err(futures::io::ErrorKind::InvalidInput.into()));
}
while self.is_pending() {
let n = ready!(Pin::new(&mut writer).poll_write(cx, &data[self.offset..self.len]))?;
if n == 0 {
self.mark_as_error();
} else {
self.advance(n);
}
}
if self.is_error() {
Poll::Ready(Err(futures::io::ErrorKind::WriteZero.into()))
} else {
Poll::Ready(Ok(()))
}
}
pub fn read_remaining<R>(&mut self, mut r: &mut R, data: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<()>>
where
R: AsyncRead + Unpin,
{
if self.len > data.len() {
self.mark_as_error();
return Poll::Ready(Err(futures::io::ErrorKind::InvalidInput.into()));
}
while self.is_pending() {
let n = ready!(Pin::new(&mut r).poll_read(cx, &mut data[self.offset..self.len]))?;
if n == 0 {
self.mark_as_error();
} else {
self.advance(n);
}
}
if self.is_error() {
Poll::Ready(Err(futures::io::ErrorKind::UnexpectedEof.into()))
} else {
Poll::Ready(Ok(()))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn fill_vec<R>(&mut self, mut reader: &mut R, data: &mut Vec<u8>, cx: &mut Context<'_>) -> Poll<Result<()>>
where
R: AsyncRead + AsyncBufRead + Unpin,
{
if self.len > data.capacity() {
self.mark_as_error();
return Poll::Ready(Err(futures::io::ErrorKind::InvalidInput.into()));
}
while self.is_pending() {
let buf = ready!(Pin::new(&mut reader).poll_fill_buf(cx))?;
if buf.is_empty() {
self.mark_as_error();
} else {
let n = min(buf.len(), self.remaining());
data.extend_from_slice(&buf[..n]);
Pin::new(&mut reader).consume(n);
self.advance(n);
}
}
if self.is_error() {
Poll::Ready(Err(futures::io::ErrorKind::UnexpectedEof.into()))
} else {
Poll::Ready(Ok(()))
}
}
}