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::AsyncOutput;
#[must_use = "futures do nothing unless polled"]
pub struct WriteFullyFuture<'a, O>
where
O: AsyncOutput + ?Sized,
{
output: Pin<&'a mut O>,
input: &'a [O::Item],
written: usize,
completed: bool,
}
impl<'a, O> WriteFullyFuture<'a, O>
where
O: AsyncOutput + ?Sized,
{
#[inline(always)]
pub const fn new(output: Pin<&'a mut O>, input: &'a [O::Item]) -> Self {
Self {
output,
input,
written: 0,
completed: false,
}
}
#[inline(always)]
#[must_use]
pub const fn items_written(&self) -> usize {
self.written
}
}
impl<O> Future for WriteFullyFuture<'_, O>
where
O: AsyncOutput + ?Sized,
{
type Output = Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
assert!(!this.completed, "WriteFullyFuture polled after completion");
let mut ready_operations = 0_usize;
while this.written < this.input.len() {
let remaining = &this.input[this.written..];
match this.output.as_mut().poll_write(cx, remaining) {
Poll::Ready(Ok(0)) => {
this.completed = true;
return Poll::Ready(Err(Error::new(
ErrorKind::WriteZero,
"failed to write whole output range",
)));
}
Poll::Ready(Ok(written)) => {
this.written += written;
ready_operations += 1;
if this.written < this.input.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(()))
}
}