diff options
| author | Taylor Cramer <cramertj@google.com> | 2018-09-14 17:40:52 -0700 |
|---|---|---|
| committer | Taylor Cramer <cramertj@google.com> | 2018-09-17 16:31:33 -0700 |
| commit | 3ec1810e329bb9dfa0cf0686bdc13558771785d2 (patch) | |
| tree | bb9f39ea9e7c740e1b8635f77868b3948a1e5b99 | |
| parent | 974bdc80fe3214159dc30e0bbb76694900e613c0 (diff) | |
| download | rust-3ec1810e329bb9dfa0cf0686bdc13558771785d2.tar.gz rust-3ec1810e329bb9dfa0cf0686bdc13558771785d2.zip | |
Cleanup and fix method resolution issue
| -rw-r--r-- | src/liballoc/boxed.rs | 6 | ||||
| -rw-r--r-- | src/libcore/future/future.rs | 14 | ||||
| -rw-r--r-- | src/libcore/option.rs | 6 | ||||
| -rw-r--r-- | src/libcore/pin.rs | 142 | ||||
| -rw-r--r-- | src/test/run-pass/async-await.rs | 11 | ||||
| -rw-r--r-- | 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 fce6417186f..744b611c061 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -98,8 +98,9 @@ impl<T> Box<T> { } #[unstable(feature = "pin", issue = "49150")] + #[inline(always)] pub fn pinned(x: T) -> Pin<Box<T>> { - unsafe { Pin::new_unchecked(box x) } + (box x).into() } } @@ -434,6 +435,9 @@ impl<T> From<T> for Box<T> { #[unstable(feature = "pin", issue = "49150")] impl<T> From<Box<T>> for Pin<Box<T>> { fn from(boxed: Box<T>) -> Self { + // It's not possible to move or replace the insides of a `Pin<Box<T>>` + // 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 6cf1925000e..f4b5cf95e37 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<P, F> Future for Pin<P> where - P: ops::DerefMut<Target = F> + Unpin, - F: Future + ?Sized, +impl<P> Future for Pin<P> +where + P: ops::DerefMut, + P::Target: Future, { - type Output = F::Output; + type Output = <<P as ops::Deref>::Target as Future>::Output; - fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> { - 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<Self::Output> { + Pin::get_mut(self).as_mut().poll(cx) } } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 83b1999f18b..5d81d21d1df 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -276,8 +276,7 @@ impl<T> Option<T> { #[unstable(feature = "pin", issue = "49150")] pub fn as_pin_ref<'a>(self: Pin<&'a Option<T>>) -> Option<Pin<&'a T>> { 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<T> Option<T> { #[unstable(feature = "pin", issue = "49150")] pub fn as_pin_mut<'a>(self: Pin<&'a mut Option<T>>) -> Option<Pin<&'a mut T>> { 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 29fc52fe3a0..3ab6dcd8531 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<Box<T>>` //! and `Box<T>` 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<P> { pointer: P, } -impl<P, T> Pin<P> where - P: Deref<Target = T>, - T: ?Sized + Unpin, +impl<P: Deref> Pin<P> +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<P> { + // Safety: the value pointed to is `Unpin`, and so has no requirements + // around pinning. unsafe { Pin::new_unchecked(pointer) } } } -impl<P, T> Pin<P> where - P: Deref<Target = T>, - T: ?Sized, -{ +impl<P: Deref> Pin<P> { /// 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<P>` does not guarantee - /// that the data is "pinned," constructing a `Pin<P>` 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<P>` does + /// not guarantee that the data `P` points to is pinned, constructing a + /// `Pin<P>` 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<P> { Pin { pointer } } - /// Get a pinned shared reference from this pinned pointer. #[unstable(feature = "pin", issue = "49150")] - pub fn as_ref(this: &Pin<P>) -> Pin<&T> { - unsafe { Pin::new_unchecked(&**this) } + #[inline(always)] + pub fn as_ref(self: &Pin<P>) -> Pin<&P::Target> { + unsafe { Pin::new_unchecked(&**self) } } } -impl<P, T> Pin<P> where - P: DerefMut<Target = T>, - T: ?Sized, -{ +impl<P: DerefMut> Pin<P> { /// Get a pinned mutable reference from this pinned pointer. #[unstable(feature = "pin", issue = "49150")] - pub fn as_mut(this: &mut Pin<P>) -> Pin<&mut T> { - unsafe { Pin::new_unchecked(&mut *this.pointer) } + #[inline(always)] + pub fn as_mut(self: &mut Pin<P>) -> 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<P>, 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<P, T> Deref for Pin<P> where - P: Deref<Target = T>, - T: ?Sized, -{ - type Target = T; - fn deref(&self) -> &T { +impl<P: Deref> Deref for Pin<P> { + type Target = P::Target; + fn deref(&self) -> &P::Target { &*self.pointer } } #[unstable(feature = "pin", issue = "49150")] -impl<P, T> DerefMut for Pin<P> where - P: DerefMut<Target = T>, - T: ?Sized + Unpin, +impl<P: DerefMut> DerefMut for Pin<P> +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<P> { } } +// Note: this means that any impl of `CoerceUnsized` that allows coercing from +// a type that impls `Deref<Target=impl !Unpin>` to a type that impls +// `Deref<Target=Unpin>` 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>, U: ?Sized> CoerceUnsized<Pin<&'a U>> for Pin<&'a T> {} - -#[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Pin<&'a mut U>> for Pin<&'a mut T> {} - -#[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Unpin for Pin<&'a T> {} +impl<'a, P, U> CoerceUnsized<Pin<U>> for Pin<P> +where + P: CoerceUnsized<U>, +{} #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Unpin for Pin<&'a mut T> {} +impl<'a, P> Unpin for Pin<P> {} diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 46f22845907..cdd65bfddd3 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<Self>, 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<Output = u8>, { - 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 69a04437691..6e757fb4f9a 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<Self>, cx: &mut Context) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { // 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)); } |
