use std::future::Future;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Result;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use super::read_fully_future::MAX_READY_OPERATIONS_PER_POLL;
use crate::AsyncInput;
#[must_use = "futures do nothing unless polled"]
pub struct ReadExactFuture<'a, I>
where
I: AsyncInput + ?Sized,
{
input: Pin<&'a mut I>,
output: &'a mut [I::Item],
read: usize,
completed: bool,
}
impl<'a, I> ReadExactFuture<'a, I>
where
I: AsyncInput + ?Sized,
{
#[inline(always)]
pub const fn new(input: Pin<&'a mut I>, output: &'a mut [I::Item]) -> Self {
Self {
input,
output,
read: 0,
completed: false,
}
}
#[inline(always)]
#[must_use]
pub const fn items_read(&self) -> usize {
self.read
}
}
impl<I> Future for ReadExactFuture<'_, I>
where
I: AsyncInput + ?Sized,
{
type Output = Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
assert!(!this.completed, "ReadExactFuture polled after completion");
let mut ready_operations = 0_usize;
while this.read < this.output.len() {
let remaining = &mut this.output[this.read..];
match this.input.as_mut().poll_read(cx, remaining) {
Poll::Ready(Ok(0)) => {
this.completed = true;
return Poll::Ready(Err(Error::new(
ErrorKind::UnexpectedEof,
"failed to fill whole input range",
)));
}
Poll::Ready(Ok(read)) => {
this.read += read;
ready_operations += 1;
if this.read < this.output.len() && ready_operations >= MAX_READY_OPERATIONS_PER_POLL {
cx.waker().wake_by_ref();
return Poll::Pending;
}
}
Poll::Ready(Err(error)) => {
this.completed = true;
return Poll::Ready(Err(error));
}
Poll::Pending => return Poll::Pending,
}
}
this.completed = true;
Poll::Ready(Ok(()))
}
}