From 6e2efe3aa477bdc8d7ccdb904523ad18d612bbb6 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Tue, 4 Apr 2017 12:31:03 -0400 Subject: [PATCH] refactor NonZero, Shared, and Unique APIs Major difference is that I removed Deref impls, as apparently LLVM has trouble maintaining metadata with a `&ptr -> &ptr` API. This was cited as a blocker for ever stabilizing this API. It wasn't that ergonomic anyway. * Added `get` to NonZero to replace Deref impl * Added `as_ptr` to Shared/Unique to replace Deref impl * Added Unique's `as_ref` and `as_mut` conveniences to Shared * Added `::empty()` convenience constructor for Unique/Shared * Deprecated `as_mut_ptr` on Shared in favour of `as_ptr` * Improved documentation of types Note that Shared now only refers to *mut, and not *const --- src/libcore/nonzero.rs | 13 +--- src/libcore/ptr.rs | 171 ++++++++++++++++++++++++++++++----------- 2 files changed, 131 insertions(+), 53 deletions(-) diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index d7382501bc32..d93085e96dbb 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -13,7 +13,7 @@ reason = "needs an RFC to flesh out the design", issue = "27730")] -use ops::{CoerceUnsized, Deref}; +use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct pub unsafe trait Zeroable {} @@ -46,15 +46,10 @@ impl NonZero { pub const unsafe fn new(inner: T) -> NonZero { NonZero(inner) } -} -impl Deref for NonZero { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - let NonZero(ref inner) = *self; - inner + /// Gets the inner value. + pub fn get(self) -> T { + self.0 } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 115326bb9169..a60abefc0765 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -17,7 +17,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use intrinsics; -use ops::{CoerceUnsized, Deref}; +use ops::CoerceUnsized; use fmt; use hash; use marker::{PhantomData, Unsize}; @@ -957,13 +957,25 @@ impl PartialOrd for *mut T { } /// A wrapper around a raw non-null `*mut T` that indicates that the possessor -/// of this wrapper owns the referent. This in turn implies that the -/// `Unique` is `Send`/`Sync` if `T` is `Send`/`Sync`, unlike a raw -/// `*mut T` (which conveys no particular ownership semantics). It -/// also implies that the referent of the pointer should not be -/// modified without a unique path to the `Unique` reference. Useful -/// for building abstractions like `Vec` or `Box`, which -/// internally use raw pointers to manage the memory that they own. +/// of this wrapper owns the referent. Useful for building abstractions like +/// `Box`, `Vec`, `String`, and `HashMap`. +/// +/// Unlike `*mut T`, `Unique` behaves "as if" it were an instance of `T`. +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies +/// the kind of strong aliasing guarantees an instance of `T` can expect: +/// the referent of the pointer should not be modified without a unique path to +/// its owning Unique. +/// +/// If you're uncertain of whether it's correct to use `Unique` for your purposes, +/// consider using `Shared`, which has weaker semantics. +/// +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer +/// is never dereferenced. This is so that enums may use this forbidden value +/// as a discriminant -- `Option>` has the same size as `Unique`. +/// However the pointer may still dangle if it isn't dereferenced. +/// +/// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct +/// for any type which upholds Unique's aliasing requirements. #[allow(missing_debug_implementations)] #[unstable(feature = "unique", reason = "needs an RFC to flesh out design", issue = "27730")] @@ -991,6 +1003,20 @@ unsafe impl Send for Unique { } #[unstable(feature = "unique", issue = "27730")] unsafe impl Sync for Unique { } +#[unstable(feature = "unique", issue = "27730")] +impl Unique { + /// Creates a new `Shared` that is dangling, but well-aligned. + /// + /// This is useful for initializing types which lazily allocate, like + /// `Vec::new` does. + pub fn empty() -> Self { + unsafe { + let ptr = mem::align_of::() as *mut T; + Unique::new(ptr) + } + } +} + #[unstable(feature = "unique", issue = "27730")] impl Unique { /// Creates a new `Unique`. @@ -1002,41 +1028,72 @@ impl Unique { Unique { pointer: NonZero::new(ptr), _marker: PhantomData } } + /// Acquires the underlying `*mut` pointer. + pub fn as_ptr(self) -> *mut T { + self.pointer.get() as *mut T + } + /// Dereferences the content. - pub unsafe fn get(&self) -> &T { - &**self.pointer + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`. + pub unsafe fn as_ref(&self) -> &T { + &*self.as_ptr() } /// Mutably dereferences the content. - pub unsafe fn get_mut(&mut self) -> &mut T { - &mut ***self + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr()`. + pub unsafe fn as_mut(&mut self) -> &mut T { + &mut *self.as_ptr() } } +#[unstable(feature = "shared", issue = "27730")] +impl Clone for Unique { + fn clone(&self) -> Self { + *self + } +} + +#[unstable(feature = "shared", issue = "27730")] +impl Copy for Unique { } + #[unstable(feature = "unique", issue = "27730")] impl CoerceUnsized> for Unique where T: Unsize { } -#[unstable(feature = "unique", issue= "27730")] -impl Deref for Unique { - type Target = *mut T; - - #[inline] - fn deref(&self) -> &*mut T { - unsafe { mem::transmute(&*self.pointer) } - } -} - #[unstable(feature = "unique", issue = "27730")] -impl fmt::Pointer for Unique { +impl fmt::Pointer for Unique { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&*self.pointer, f) + fmt::Pointer::fmt(&self.as_ptr(), f) } } -/// A wrapper around a raw non-null `*mut T` that indicates that the possessor +/// A wrapper around a raw `*mut T` that indicates that the possessor /// of this wrapper has shared ownership of the referent. Useful for -/// building abstractions like `Rc` or `Arc`, which internally -/// use raw pointers to manage the memory that they own. +/// building abstractions like `Rc`, `Arc`, or doubly-linked lists, which +/// internally use aliased raw pointers to manage the memory that they own. +/// +/// This is similar to `Unique`, except that it doesn't make any aliasing +/// guarantees, and doesn't derive Send and Sync. Note that unlike `&T`, +/// Shared has no special mutability requirements. Shared may mutate data +/// aliased by other Shared pointers. More precise rules require Rust to +/// develop an actual aliasing model. +/// +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer +/// is never dereferenced. This is so that enums may use this forbidden value +/// as a discriminant -- `Option>` has the same size as `Shared`. +/// However the pointer may still dangle if it isn't dereferenced. +/// +/// Unlike `*mut T`, `Shared` is covariant over `T`. If this is incorrect +/// for your use case, you should include some PhantomData in your type to +/// provide invariance, such as `PhantomData>` or `PhantomData<&'a mut T>`. +/// Usually this won't be necessary; covariance is correct for Rc, Arc, and LinkedList +/// because they provide a public API that follows the normal shared XOR mutable +/// rules of Rust. #[allow(missing_debug_implementations)] #[unstable(feature = "shared", reason = "needs an RFC to flesh out design", issue = "27730")] @@ -1060,6 +1117,20 @@ impl !Send for Shared { } #[unstable(feature = "shared", issue = "27730")] impl !Sync for Shared { } +#[unstable(feature = "shared", issue = "27730")] +impl Shared { + /// Creates a new `Shared` that is dangling, but well-aligned. + /// + /// This is useful for initializing types which lazily allocate, like + /// `Vec::new` does. + pub fn empty() -> Self { + unsafe { + let ptr = mem::align_of::() as *mut T; + Shared::new(ptr) + } + } +} + #[unstable(feature = "shared", issue = "27730")] impl Shared { /// Creates a new `Shared`. @@ -1067,16 +1138,38 @@ impl Shared { /// # Safety /// /// `ptr` must be non-null. - pub unsafe fn new(ptr: *const T) -> Self { + pub unsafe fn new(ptr: *mut T) -> Self { Shared { pointer: NonZero::new(ptr), _marker: PhantomData } } -} -#[unstable(feature = "shared", issue = "27730")] -impl Shared { + /// Acquires the underlying `*mut` pointer. + pub fn as_ptr(self) -> *mut T { + self.pointer.get() as *mut T + } + + /// Dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`. + pub unsafe fn as_ref(&self) -> &T { + &*self.as_ptr() + } + + /// Mutably dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr_mut()`. + pub unsafe fn as_mut(&mut self) -> &mut T { + &mut *self.as_ptr() + } + /// Acquires the underlying pointer as a `*mut` pointer. + #[rustc_deprecated(since = "1.19", reason = "renamed to `as_ptr` for ergonomics/consistency")] + #[unstable(feature = "shared", issue = "27730")] pub unsafe fn as_mut_ptr(&self) -> *mut T { - **self as _ + self.as_ptr() } } @@ -1094,18 +1187,8 @@ impl Copy for Shared { } impl CoerceUnsized> for Shared where T: Unsize { } #[unstable(feature = "shared", issue = "27730")] -impl Deref for Shared { - type Target = *const T; - - #[inline] - fn deref(&self) -> &*const T { - unsafe { mem::transmute(&*self.pointer) } - } -} - -#[unstable(feature = "shared", issue = "27730")] -impl fmt::Pointer for Shared { +impl fmt::Pointer for Shared { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&*self.pointer, f) + fmt::Pointer::fmt(&self.as_ptr(), f) } }