Skip to content

Commit

Permalink
fix(rt): implement Read/Write for Pin<P> (#3413)
Browse files Browse the repository at this point in the history
Without these impls, something like Pin<Box<T: Read>> does not actually
implement Read.

Closes #3412

BREAKING CHANGE: Pin is #[fundamental], so this theoretically conflicts
  with existing user Read/Write for Pin<...> impls. However, those impls
  probably don't exist yet.
  • Loading branch information
coolreader18 authored Nov 16, 2023
1 parent a475ada commit dd6d81c
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions src/rt/io.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt;
use std::mem::MaybeUninit;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};

Expand Down Expand Up @@ -294,6 +295,20 @@ impl<T: ?Sized + Read + Unpin> Read for &mut T {
deref_async_read!();
}

impl<P> Read for Pin<P>
where
P: DerefMut,
P::Target: Read,
{
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: ReadBufCursor<'_>,
) -> Poll<std::io::Result<()>> {
pin_as_deref_mut(self).poll_read(cx, buf)
}
}

macro_rules! deref_async_write {
() => {
fn poll_write(
Expand Down Expand Up @@ -336,3 +351,45 @@ impl<T: ?Sized + Write + Unpin> Write for Box<T> {
impl<T: ?Sized + Write + Unpin> Write for &mut T {
deref_async_write!();
}

impl<P> Write for Pin<P>
where
P: DerefMut,
P::Target: Write,
{
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<std::io::Result<usize>> {
pin_as_deref_mut(self).poll_write(cx, buf)
}

fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[std::io::IoSlice<'_>],
) -> Poll<std::io::Result<usize>> {
pin_as_deref_mut(self).poll_write_vectored(cx, bufs)
}

fn is_write_vectored(&self) -> bool {
(**self).is_write_vectored()
}

fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
pin_as_deref_mut(self).poll_flush(cx)
}

fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
pin_as_deref_mut(self).poll_shutdown(cx)
}
}

/// Polyfill for Pin::as_deref_mut()
/// TODO: use Pin::as_deref_mut() instead once stabilized
fn pin_as_deref_mut<P: DerefMut>(pin: Pin<&mut Pin<P>>) -> Pin<&mut P::Target> {
// SAFETY: we go directly from Pin<&mut Pin<P>> to Pin<&mut P::Target>, without moving or
// giving out the &mut Pin<P> in the process. See Pin::as_deref_mut() for more detail.
unsafe { pin.get_unchecked_mut() }.as_mut()
}

0 comments on commit dd6d81c

Please sign in to comment.