diff options
| author | Nick Cameron <ncameron@mozilla.com> | 2015-04-16 14:36:47 +1200 |
|---|---|---|
| committer | Nick Cameron <ncameron@mozilla.com> | 2015-05-13 14:19:51 +1200 |
| commit | 7d953538d10c4a31300afd27f73563adb056beab (patch) | |
| tree | 7c67eded203cffb8a617bfb440e7c2f4008b17b5 /src/liballoc | |
| parent | 843db01bd925279da0a56efde532c9e3ecf73610 (diff) | |
| download | rust-7d953538d10c4a31300afd27f73563adb056beab.tar.gz rust-7d953538d10c4a31300afd27f73563adb056beab.zip | |
Make Rc DST-compatible
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/rc.rs | 389 |
1 files changed, 382 insertions, 7 deletions
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index a1b5e6e6baf..4e8a7e8bfc9 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -159,7 +159,7 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; use core::default::Default; use core::fmt; use core::hash::{Hasher, Hash}; -use core::marker; +use core::marker::{self, Sized}; use core::mem::{self, min_align_of, size_of, forget}; use core::nonzero::NonZero; use core::ops::{Deref, Drop}; @@ -170,17 +170,36 @@ use core::result::Result; use core::result::Result::{Ok, Err}; use core::intrinsics::assume; +#[cfg(not(stage0))] +use core::intrinsics::drop_in_place; +#[cfg(not(stage0))] +use core::marker::Unsize; +#[cfg(not(stage0))] +use core::mem::{min_align_of_val, size_of_val}; +#[cfg(not(stage0))] +use core::ops::CoerceUnsized; + use heap::deallocate; +#[cfg(stage0)] struct RcBox<T> { strong: Cell<usize>, weak: Cell<usize>, - value: T + value: T, +} + +#[cfg(not(stage0))] +struct RcBox<T: ?Sized> { + strong: Cell<usize>, + weak: Cell<usize>, + value: T, } + /// A reference-counted pointer type over an immutable value. /// /// See the [module level documentation](./index.html) for more details. +#[cfg(stage0)] #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc<T> { @@ -188,11 +207,30 @@ pub struct Rc<T> { // accesses of the contained type via Deref _ptr: NonZero<*mut RcBox<T>>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Rc<T: ?Sized> { + // FIXME #12808: strange names to try to avoid interfering with field + // accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox<T>>, +} +#[cfg(stage0)] impl<T> !marker::Send for Rc<T> {} +#[cfg(not(stage0))] +impl<T: ?Sized> !marker::Send for Rc<T> {} + +#[cfg(stage0)] impl<T> !marker::Sync for Rc<T> {} +#[cfg(not(stage0))] +impl<T: ?Sized> !marker::Sync for Rc<T> {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {} + impl<T> Rc<T> { /// Constructs a new `Rc<T>`. /// @@ -212,14 +250,39 @@ impl<T> Rc<T> { // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. _ptr: NonZero::new(boxed::into_raw(box RcBox { - value: value, strong: Cell::new(1), - weak: Cell::new(1) + weak: Cell::new(1), + value: value })), } } } +} +#[cfg(not(stage0))] +impl<T: ?Sized> Rc<T> { + /// Downgrades the `Rc<T>` to a `Weak<T>` reference. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = five.downgrade(); + /// ``` + #[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module")] + pub fn downgrade(&self) -> Weak<T> { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} + +#[cfg(stage0)] +impl<T> Rc<T> { /// Downgrades the `Rc<T>` to a `Weak<T>` reference. /// /// # Examples @@ -241,14 +304,24 @@ impl<T> Rc<T> { } /// Get the number of weak references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn weak_count<T>(this: &Rc<T>) -> usize { this.weak() - 1 } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn weak_count<T: ?Sized>(this: &Rc<T>) -> usize { this.weak() - 1 } /// Get the number of strong references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn strong_count<T>(this: &Rc<T>) -> usize { this.strong() } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn strong_count<T: ?Sized>(this: &Rc<T>) -> usize { this.strong() } /// Returns true if there are no other `Rc` or `Weak<T>` values that share the /// same inner value. @@ -365,6 +438,7 @@ impl<T: Clone> Rc<T> { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl<T> Deref for Rc<T> { type Target = T; @@ -374,7 +448,19 @@ impl<T> Deref for Rc<T> { &self.inner().value } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Deref for Rc<T> { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &self.inner().value + } +} +#[cfg(stage0)] // SNAP c64d671 +#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl<T> Drop for Rc<T> { /// Drops the `Rc<T>`. @@ -425,6 +511,61 @@ impl<T> Drop for Rc<T> { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Drop for Rc<T> { + /// Drops the `Rc<T>`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak<T>` ones, + /// `drop`s the inner value. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// drop(five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).is_null() { + self.dec_strong(); + if self.strong() == 0 { + // destroy the contained object + drop_in_place(&mut (*ptr).value); + + // remove the implicit "strong weak" pointer now that we've + // destroyed the contents. + self.dec_weak(); + + if self.weak() == 0 { + deallocate(ptr as *mut u8, + size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } + } +} + +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl<T> Clone for Rc<T> { @@ -449,6 +590,31 @@ impl<T> Clone for Rc<T> { Rc { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Clone for Rc<T> { + + /// Makes a clone of the `Rc<T>`. + /// + /// When you clone an `Rc<T>`, it will create another pointer to the data and + /// increase the strong reference counter. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// five.clone(); + /// ``` + #[inline] + fn clone(&self) -> Rc<T> { + self.inc_strong(); + Rc { _ptr: self._ptr } + } +} #[stable(feature = "rust1", since = "1.0.0")] impl<T: Default> Default for Rc<T> { @@ -610,27 +776,50 @@ impl<T: Ord> Ord for Rc<T> { fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) } } -// FIXME (#18248) Make `T` `Sized?` +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Hash> Hash for Rc<T> { fn hash<H: Hasher>(&self, state: &mut H) { (**self).hash(state); } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized+Hash> Hash for Rc<T> { + fn hash<H: Hasher>(&self, state: &mut H) { + (**self).hash(state); + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl<T: fmt::Display> fmt::Display for Rc<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized+fmt::Display> fmt::Display for Rc<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl<T: fmt::Debug> fmt::Debug for Rc<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized+fmt::Debug> fmt::Debug for Rc<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl<T> fmt::Pointer for Rc<T> { @@ -645,6 +834,7 @@ impl<T> fmt::Pointer for Rc<T> { /// dropped. /// /// See the [module level documentation](./index.html) for more. +#[cfg(stage0)] #[unsafe_no_drop_flag] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] @@ -653,12 +843,28 @@ pub struct Weak<T> { // field accesses of the contained type via Deref _ptr: NonZero<*mut RcBox<T>>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +pub struct Weak<T: ?Sized> { + // FIXME #12808: strange names to try to avoid interfering with + // field accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox<T>>, +} +#[cfg(stage0)] impl<T> !marker::Send for Weak<T> {} +#[cfg(not(stage0))] +impl<T: ?Sized> !marker::Send for Weak<T> {} +#[cfg(stage0)] impl<T> !marker::Sync for Weak<T> {} +#[cfg(not(stage0))] +impl<T: ?Sized> !marker::Sync for Weak<T> {} +#[cfg(stage0)] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] impl<T> Weak<T> { @@ -691,7 +897,42 @@ impl<T> Weak<T> { } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl<T: ?Sized> Weak<T> { + /// Upgrades a weak reference to a strong reference. + /// + /// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible. + /// + /// Returns `None` if there were no strong references and the data was + /// destroyed. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = five.downgrade(); + /// + /// let strong_five: Option<Rc<_>> = weak_five.upgrade(); + /// ``` + pub fn upgrade(&self) -> Option<Rc<T>> { + if self.strong() == 0 { + None + } else { + self.inc_strong(); + Some(Rc { _ptr: self._ptr }) + } + } +} + +#[cfg(stage0)] // SNAP c64d671 +#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl<T> Drop for Weak<T> { /// Drops the `Weak<T>`. @@ -736,6 +977,53 @@ impl<T> Drop for Weak<T> { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Drop for Weak<T> { + /// Drops the `Weak<T>`. + /// + /// This will decrement the weak reference count. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// drop(weak_five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).is_null() { + self.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if self.weak() == 0 { + deallocate(ptr as *mut u8, size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } +} + +#[cfg(stage0)] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] impl<T> Clone for Weak<T> { @@ -760,14 +1048,48 @@ impl<T> Clone for Weak<T> { Weak { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl<T: ?Sized> Clone for Weak<T> { + + /// Makes a clone of the `Weak<T>`. + /// + /// This increases the weak reference count. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let weak_five = Rc::new(5).downgrade(); + /// + /// weak_five.clone(); + /// ``` + #[inline] + fn clone(&self) -> Weak<T> { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl<T: fmt::Debug> fmt::Debug for Weak<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(Weak)") } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized+fmt::Debug> fmt::Debug for Weak<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "(Weak)") + } +} +#[cfg(stage0)] #[doc(hidden)] trait RcBoxPtr<T> { fn inner(&self) -> &RcBox<T>; @@ -790,7 +1112,31 @@ trait RcBoxPtr<T> { #[inline] fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } } +#[cfg(not(stage0))] +#[doc(hidden)] +trait RcBoxPtr<T: ?Sized> { + fn inner(&self) -> &RcBox<T>; + + #[inline] + fn strong(&self) -> usize { self.inner().strong.get() } + + #[inline] + fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } + + #[inline] + fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } + + #[inline] + fn weak(&self) -> usize { self.inner().weak.get() } + + #[inline] + fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); } + + #[inline] + fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } +} +#[cfg(stage0)] impl<T> RcBoxPtr<T> for Rc<T> { #[inline(always)] fn inner(&self) -> &RcBox<T> { @@ -799,12 +1145,27 @@ impl<T> RcBoxPtr<T> for Rc<T> { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); + &(**self._ptr) + } + } +} +#[cfg(not(stage0))] +impl<T: ?Sized> RcBoxPtr<T> for Rc<T> { + #[inline(always)] + fn inner(&self) -> &RcBox<T> { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway. + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } } } +#[cfg(stage0)] impl<T> RcBoxPtr<T> for Weak<T> { #[inline(always)] fn inner(&self) -> &RcBox<T> { @@ -813,7 +1174,21 @@ impl<T> RcBoxPtr<T> for Weak<T> { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); + &(**self._ptr) + } + } +} +#[cfg(not(stage0))] +impl<T: ?Sized> RcBoxPtr<T> for Weak<T> { + #[inline(always)] + fn inner(&self) -> &RcBox<T> { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway. + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } } |
