Provides AsyncWrite with flush

As per Tokio and others, this commit provides a `poll_flush` method on `AsyncWrite` so that a best-effort attempt at wakening once all bytes are flushed can be made.
This commit is contained in:
huntc
2021-12-10 12:08:00 +11:00
parent 60b7c50d8b
commit 7256ff3e71
7 changed files with 100 additions and 0 deletions

View File

@ -89,6 +89,15 @@ pub trait AsyncWrite {
/// `poll_write` must try to make progress by flushing the underlying object if
/// that is the only way the underlying object can become writable again.
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>>;
/// Attempt to flush the object, ensuring that any buffered data reach their destination.
///
/// On success, returns Poll::Ready(Ok(())).
///
/// If flushing cannot immediately complete, this method returns [Poll::Pending] and arranges for the
/// current task (via cx.waker()) to receive a notification when the object can make progress
/// towards flushing.
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>>;
}
macro_rules! defer_async_read {
@ -135,6 +144,10 @@ macro_rules! deref_async_write {
) -> Poll<Result<usize>> {
Pin::new(&mut **self).poll_write(cx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
Pin::new(&mut **self).poll_flush(cx)
}
};
}
@ -155,4 +168,8 @@ where
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
self.get_mut().as_mut().poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
self.get_mut().as_mut().poll_flush(cx)
}
}

View File

@ -0,0 +1,32 @@
use core::pin::Pin;
use futures::future::Future;
use futures::ready;
use futures::task::{Context, Poll};
use super::super::error::Result;
use super::super::traits::AsyncWrite;
/// Future for the [`flush`](super::AsyncWriteExt::flush) method.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Flush<'a, W: ?Sized> {
writer: &'a mut W,
}
impl<W: ?Sized + Unpin> Unpin for Flush<'_, W> {}
impl<'a, W: AsyncWrite + ?Sized + Unpin> Flush<'a, W> {
pub(super) fn new(writer: &'a mut W) -> Self {
Flush { writer }
}
}
impl<W: AsyncWrite + ?Sized + Unpin> Future for Flush<'_, W> {
type Output = Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
let this = &mut *self;
let _ = ready!(Pin::new(&mut this.writer).poll_flush(cx))?;
Poll::Ready(Ok(()))
}
}

View File

@ -27,6 +27,9 @@ pub use self::skip_while::SkipWhile;
mod drain;
pub use self::drain::Drain;
mod flush;
pub use self::flush::Flush;
mod write;
pub use self::write::Write;
@ -160,6 +163,15 @@ pub trait AsyncWriteExt: AsyncWrite {
{
Write::new(self, buf)
}
/// Awaits until all bytes have actually been written, and
/// not just enqueued as per the other "write" methods.
fn flush<'a>(&mut self) -> Flush<Self>
where
Self: Unpin,
{
Flush::new(self)
}
}
impl<R: AsyncWrite + ?Sized> AsyncWriteExt for R {}