From 3ec1810e329bb9dfa0cf0686bdc13558771785d2 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 14 Sep 2018 17:40:52 -0700 Subject: [PATCH] Cleanup and fix method resolution issue --- src/liballoc/boxed.rs | 6 +- src/libcore/future/future.rs | 14 +-- src/libcore/option.rs | 6 +- src/libcore/pin.rs | 142 ++++++++++++++++++++----------- src/test/run-pass/async-await.rs | 11 ++- src/test/run-pass/futures-api.rs | 11 ++- 6 files changed, 117 insertions(+), 73 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index fce6417186fc..744b611c061b 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -98,8 +98,9 @@ impl Box { } #[unstable(feature = "pin", issue = "49150")] + #[inline(always)] pub fn pinned(x: T) -> Pin> { - unsafe { Pin::new_unchecked(box x) } + (box x).into() } } @@ -434,6 +435,9 @@ impl From for Box { #[unstable(feature = "pin", issue = "49150")] impl From> for Pin> { fn from(boxed: Box) -> Self { + // It's not possible to move or replace the insides of a `Pin>` + // when `T: !Unpin`, so it's safe to pin it directly without any + // additional requirements. unsafe { Pin::new_unchecked(boxed) } } } diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 6cf1925000e9..f4b5cf95e37f 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -104,14 +104,14 @@ impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { } } -impl Future for Pin

where - P: ops::DerefMut + Unpin, - F: Future + ?Sized, +impl

Future for Pin

+where + P: ops::DerefMut, + P::Target: Future, { - type Output = F::Output; + type Output = <

::Target as Future>::Output; - fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll { - let pin: Pin<&mut F> = Pin::as_mut(&mut *self); - F::poll(pin, cx) + fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll { + Pin::get_mut(self).as_mut().poll(cx) } } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 83b1999f18b1..5d81d21d1dfc 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -276,8 +276,7 @@ impl Option { #[unstable(feature = "pin", issue = "49150")] pub fn as_pin_ref<'a>(self: Pin<&'a Option>) -> Option> { unsafe { - let option: Option<&'a T> = Pin::get(self).as_ref(); - option.map(|x| Pin::new_unchecked(x)) + Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } } @@ -286,8 +285,7 @@ impl Option { #[unstable(feature = "pin", issue = "49150")] pub fn as_pin_mut<'a>(self: Pin<&'a mut Option>) -> Option> { unsafe { - let option: Option<&'a mut T> = Pin::get_mut_unchecked(self).as_mut(); - option.map(|x| Pin::new_unchecked(x)) + Pin::get_mut_unchecked(self).as_mut().map(|x| Pin::new_unchecked(x)) } } diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 29fc52fe3a02..3ab6dcd8531d 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -7,7 +7,7 @@ //! since moving an object with pointers to itself will invalidate them, //! which could cause undefined behavior. //! -//! In order to prevent objects from moving, they must be *pinned*, +//! In order to prevent objects from moving, they must be pinned //! by wrapping a pointer to the data in the [`Pin`] type. A pointer wrapped //! in a `Pin` is otherwise equivalent to its normal version, e.g. `Pin>` //! and `Box` work the same way except that the first is pinning the value @@ -15,7 +15,7 @@ //! //! First of all, these are pointer types because pinned data mustn't be passed around by value //! (that would change its location in memory). -//! Secondly, since data can be moved out of `&mut` and [`Box`] with functions such as [`swap`], +//! Secondly, since data can be moved out of `&mut` and `Box` with functions such as [`swap`], //! which causes their contents to swap places in memory, //! we need dedicated types that prohibit such operations. //! @@ -28,7 +28,7 @@ //! [`Pin`]: struct.Pin.html //! [`Unpin`]: trait.Unpin.html //! [`swap`]: ../../std/mem/fn.swap.html -//! [`Box`]: ../boxed/struct.Box.html +//! [`Box`]: ../../std/boxed/struct.Box.html //! //! # Examples //! @@ -66,7 +66,7 @@ //! //! let slice = NonNull::from(&boxed.data); //! // we know this is safe because modifying a field doesn't move the whole struct -//! unsafe { +//! unsafe { //! let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed); //! Pin::get_mut_unchecked(mut_ref).slice = slice; //! } @@ -90,9 +90,12 @@ #![unstable(feature = "pin", issue = "49150")] use fmt; -use marker::{Sized, Unpin, Unsize}; +use marker::Sized; use ops::{Deref, DerefMut, CoerceUnsized}; +#[doc(inline)] +pub use marker::Unpin; + /// A pinned pointer. /// /// This is a wrapper around a kind of pointer which makes that pointer "pin" its @@ -103,6 +106,9 @@ use ops::{Deref, DerefMut, CoerceUnsized}; /// /// [`Unpin`]: ../../std/marker/trait.Unpin.html /// [`pin` module]: ../../std/pin/index.html +// +// Note: the derives below are allowed because they all only use `&P`, so they +// cannot move the value behind `pointer`. #[unstable(feature = "pin", issue = "49150")] #[fundamental] #[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] @@ -110,64 +116,68 @@ pub struct Pin

{ pointer: P, } -impl Pin

where - P: Deref, - T: ?Sized + Unpin, +impl Pin

+where + P::Target: Unpin, { /// Construct a new `Pin` around a pointer to some data of a type that /// implements `Unpin`. #[unstable(feature = "pin", issue = "49150")] + #[inline(always)] pub fn new(pointer: P) -> Pin

{ + // Safety: the value pointed to is `Unpin`, and so has no requirements + // around pinning. unsafe { Pin::new_unchecked(pointer) } } } -impl Pin

where - P: Deref, - T: ?Sized, -{ +impl Pin

{ /// Construct a new `Pin` around a reference to some data of a type that /// may or may not implement `Unpin`. /// /// # Safety /// - /// This constructor is unsafe because we cannot guarantee that the target data - /// is properly pinned by this pointer. If the constructed `Pin

` does not guarantee - /// that the data is "pinned," constructing a `Pin

` is undefined behavior and could lead - /// to segmentation faults or worse. + /// This constructor is unsafe because we cannot guarantee that the data + /// pointed to by `pointer` is pinned. If the constructed `Pin

` does + /// not guarantee that the data `P` points to is pinned, constructing a + /// `Pin

` is undefined behavior. + /// + /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used + /// instead. #[unstable(feature = "pin", issue = "49150")] + #[inline(always)] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } - /// Get a pinned shared reference from this pinned pointer. #[unstable(feature = "pin", issue = "49150")] - pub fn as_ref(this: &Pin

) -> Pin<&T> { - unsafe { Pin::new_unchecked(&**this) } + #[inline(always)] + pub fn as_ref(self: &Pin

) -> Pin<&P::Target> { + unsafe { Pin::new_unchecked(&**self) } } } -impl Pin

where - P: DerefMut, - T: ?Sized, -{ +impl Pin

{ /// Get a pinned mutable reference from this pinned pointer. #[unstable(feature = "pin", issue = "49150")] - pub fn as_mut(this: &mut Pin

) -> Pin<&mut T> { - unsafe { Pin::new_unchecked(&mut *this.pointer) } + #[inline(always)] + pub fn as_mut(self: &mut Pin

) -> Pin<&mut P::Target> { + unsafe { Pin::new_unchecked(&mut *self.pointer) } } /// Assign a new value to the memory behind the pinned reference. #[unstable(feature = "pin", issue = "49150")] - pub fn set(this: Pin<&mut T>, value: T) - where T: Sized, + #[inline(always)] + pub fn set(mut self: Pin

, value: P::Target) + where + P::Target: Sized, { - *this.pointer = value; + *self.pointer = value; } } -impl<'a, T> Pin<&'a T> { +impl<'a, T: ?Sized> Pin<&'a T> { /// Construct a new pin by mapping the interior value. /// /// For example, if you wanted to get a `Pin` of a field of something, @@ -188,14 +198,45 @@ impl<'a, T> Pin<&'a T> { Pin::new_unchecked(new_pointer) } - /// Get a safe reference out of a pin. + /// Get a shared reference out of a pin. + /// + /// Note: `Pin` also implements `Deref` to the target, which can be used + /// to access the inner value. However, `Deref` only provides a reference + /// that lives for as long as the borrow of the `Pin`, not the lifetime of + /// the `Pin` itself. This method allows turning the `Pin` into a reference + /// with the same lifetime as the original `Pin`. #[unstable(feature = "pin", issue = "49150")] - pub fn get(this: Pin<&'a T>) -> &'a T { + #[inline(always)] + pub fn get_ref(this: Pin<&'a T>) -> &'a T { this.pointer } } impl<'a, T> Pin<&'a mut T> { + /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. + #[unstable(feature = "pin", issue = "49150")] + #[inline(always)] + pub fn into_ref(this: Pin<&'a mut T>) -> Pin<&'a T> { + Pin { pointer: this.pointer } + } + + /// Get a mutable reference to the data inside of this `Pin`. + /// + /// This requires that the data inside this `Pin` is `Unpin`. + /// + /// Note: `Pin` also implements `DerefMut` to the data, which can be used + /// to access the inner value. However, `DerefMut` only provides a reference + /// that lives for as long as the borrow of the `Pin`, not the lifetime of + /// the `Pin` itself. This method allows turning the `Pin` into a reference + /// with the same lifetime as the original `Pin`. + #[unstable(feature = "pin", issue = "49150")] + #[inline(always)] + pub fn get_mut(this: Pin<&'a mut T>) -> &'a mut T + where T: Unpin, + { + this.pointer + } + /// Get a mutable reference to the data inside of this `Pin`. /// /// # Safety @@ -203,7 +244,11 @@ impl<'a, T> Pin<&'a mut T> { /// This function is unsafe. You must guarantee that you will never move /// the data out of the mutable reference you receive when you call this /// function, so that the invariants on the `Pin` type can be upheld. + /// + /// If the underlying data is `Unpin`, `Pin::get_mut` should be used + /// instead. #[unstable(feature = "pin", issue = "49150")] + #[inline(always)] pub unsafe fn get_mut_unchecked(this: Pin<&'a mut T>) -> &'a mut T { this.pointer } @@ -230,22 +275,19 @@ impl<'a, T> Pin<&'a mut T> { } #[unstable(feature = "pin", issue = "49150")] -impl Deref for Pin

where - P: Deref, - T: ?Sized, -{ - type Target = T; - fn deref(&self) -> &T { +impl Deref for Pin

{ + type Target = P::Target; + fn deref(&self) -> &P::Target { &*self.pointer } } #[unstable(feature = "pin", issue = "49150")] -impl DerefMut for Pin

where - P: DerefMut, - T: ?Sized + Unpin, +impl DerefMut for Pin

+where + P::Target: Unpin { - fn deref_mut(&mut self) -> &mut T { + fn deref_mut(&mut self) -> &mut P::Target { &mut *self.pointer } } @@ -271,14 +313,16 @@ impl<'a, P: fmt::Pointer> fmt::Pointer for Pin

{ } } +// Note: this means that any impl of `CoerceUnsized` that allows coercing from +// a type that impls `Deref` to a type that impls +// `Deref` is unsound. Any such impl would probably be unsound +// for other reasons, though, so we just need to take care not to allow such +// impls to land in std. #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<&'a T> {} +impl<'a, P, U> CoerceUnsized> for Pin

+where + P: CoerceUnsized, +{} #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<&'a mut T> {} - -#[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Unpin for Pin<&'a T> {} - -#[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Unpin for Pin<&'a mut T> {} +impl<'a, P> Unpin for Pin

{} diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 46f228459079..cdd65bfddd3c 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -12,8 +12,7 @@ #![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)] -use std::pin::PinBox; -use std::pin::PinMut; +use std::pin::Pin; use std::future::Future; use std::sync::{ Arc, @@ -49,7 +48,7 @@ fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } impl Future for WakeOnceThenComplete { type Output = (); - fn poll(mut self: PinMut, cx: &mut Context) -> Poll<()> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> { if self.0 { Poll::Ready(()) } else { @@ -124,16 +123,16 @@ where F: FnOnce(u8) -> Fut, Fut: Future, { - let mut fut = PinBox::new(f(9)); + let mut fut = Box::pinned(f(9)); let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); let waker = local_waker_from_nonlocal(counter.clone()); let spawner = &mut NoopSpawner; let cx = &mut Context::new(&waker, spawner); assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Pending, fut.as_pin_mut().poll(cx)); + assert_eq!(Poll::Pending, fut.as_mut().poll(cx)); assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Ready(9), fut.as_pin_mut().poll(cx)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(cx)); } fn main() { diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index 69a04437691d..6e757fb4f9a4 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -11,9 +11,8 @@ #![feature(arbitrary_self_types, futures_api, pin)] #![allow(unused)] -use std::pin::PinBox; use std::future::Future; -use std::pin::PinMut; +use std::pin::Pin; use std::rc::Rc; use std::sync::{ Arc, @@ -54,12 +53,12 @@ struct MyFuture; impl Future for MyFuture { type Output = (); - fn poll(self: PinMut, cx: &mut Context) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { // Ensure all the methods work appropriately cx.waker().wake(); cx.waker().wake(); cx.local_waker().wake(); - cx.spawner().spawn_obj(PinBox::new(MyFuture).into()).unwrap(); + cx.spawner().spawn_obj(Box::pinned(MyFuture).into()).unwrap(); Poll::Ready(()) } } @@ -72,7 +71,7 @@ fn test_local_waker() { let waker = unsafe { local_waker(counter.clone()) }; let spawner = &mut NoopSpawner; let cx = &mut Context::new(&waker, spawner); - assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx)); + assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(cx)); assert_eq!(1, counter.local_wakes.load(atomic::Ordering::SeqCst)); assert_eq!(2, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst)); } @@ -85,7 +84,7 @@ fn test_local_as_nonlocal_waker() { let waker: LocalWaker = local_waker_from_nonlocal(counter.clone()); let spawner = &mut NoopSpawner; let cx = &mut Context::new(&waker, spawner); - assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx)); + assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(cx)); assert_eq!(0, counter.local_wakes.load(atomic::Ordering::SeqCst)); assert_eq!(3, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst)); }