use futures_lite::{AsyncBufRead, AsyncRead, AsyncWrite, io::BufReader, ready};
use std::{
future::Future,
io::{ErrorKind, Result},
pin::{Pin, pin},
task::{Context, Poll},
};
#[doc(hidden)]
pub async fn copy<R, W>(reader: R, writer: W, loops_per_yield: usize) -> Result<u64>
where
R: AsyncRead,
W: AsyncWrite,
{
struct CopyFuture<'r, 'w, R, W> {
reader: BufReader<Pin<&'r mut R>>,
writer: Pin<&'w mut W>,
amt: u64,
loops_per_yield: usize,
}
impl<R, W> Future for CopyFuture<'_, '_, R, W>
where
R: AsyncRead,
W: AsyncWrite,
{
type Output = Result<u64>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
for loop_number in 0..self.loops_per_yield {
log::trace!("copy loop number: {loop_number}");
let CopyFuture {
reader,
writer,
amt,
..
} = &mut *self;
let writer = Pin::new(writer);
let mut reader = Pin::new(reader);
let buffer = ready!(reader.as_mut().poll_fill_buf(cx))?;
if buffer.is_empty() {
ready!(writer.poll_flush(cx))?;
return Poll::Ready(Ok(self.amt));
}
let i = ready!(writer.poll_write(cx, buffer))?;
if i == 0 {
return Poll::Ready(Err(ErrorKind::WriteZero.into()));
}
*amt += i as u64;
reader.consume(i);
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
let reader = pin!(reader);
let writer = pin!(writer);
let future = CopyFuture {
reader: BufReader::new(reader),
writer,
amt: 0,
loops_per_yield,
};
future.await
}