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 { strong: Cell, weak: Cell, - value: T + value: T, } +#[cfg(not(stage0))] +struct RcBox { + strong: Cell, + weak: Cell, + 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 { @@ -188,11 +207,30 @@ pub struct Rc { // accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Rc { + // FIXME #12808: strange names to try to avoid interfering with field + // accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox>, +} +#[cfg(stage0)] impl !marker::Send for Rc {} +#[cfg(not(stage0))] +impl !marker::Send for Rc {} + +#[cfg(stage0)] impl !marker::Sync for Rc {} +#[cfg(not(stage0))] +impl !marker::Sync for Rc {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Rc {} + impl Rc { /// Constructs a new `Rc`. /// @@ -212,14 +250,39 @@ impl Rc { // 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 Rc { + /// Downgrades the `Rc` to a `Weak` 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 { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} + +#[cfg(stage0)] +impl Rc { /// Downgrades the `Rc` to a `Weak` reference. /// /// # Examples @@ -241,14 +304,24 @@ impl Rc { } /// Get the number of weak references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } /// Get the number of strong references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn strong_count(this: &Rc) -> usize { this.strong() } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn strong_count(this: &Rc) -> usize { this.strong() } /// Returns true if there are no other `Rc` or `Weak` values that share the /// same inner value. @@ -365,6 +438,7 @@ impl Rc { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Rc { type Target = T; @@ -374,7 +448,19 @@ impl Deref for Rc { &self.inner().value } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Deref for Rc { + 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 Drop for Rc { /// Drops the `Rc`. @@ -425,6 +511,61 @@ impl Drop for Rc { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Rc { + /// Drops the `Rc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak` 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 Clone for Rc { @@ -449,6 +590,31 @@ impl Clone for Rc { Rc { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Rc { + + /// Makes a clone of the `Rc`. + /// + /// When you clone an `Rc`, 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 { + self.inc_strong(); + Rc { _ptr: self._ptr } + } +} #[stable(feature = "rust1", since = "1.0.0")] impl Default for Rc { @@ -610,27 +776,50 @@ impl Ord for Rc { fn cmp(&self, other: &Rc) -> Ordering { (**self).cmp(&**other) } } -// FIXME (#18248) Make `T` `Sized?` +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Hash for Rc { fn hash(&self, state: &mut H) { (**self).hash(state); } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for Rc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Rc { 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 fmt::Display for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Rc { 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 fmt::Debug for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Rc { @@ -645,6 +834,7 @@ impl fmt::Pointer for Rc { /// 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 { // field accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +pub struct Weak { + // FIXME #12808: strange names to try to avoid interfering with + // field accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox>, +} +#[cfg(stage0)] impl !marker::Send for Weak {} +#[cfg(not(stage0))] +impl !marker::Send for Weak {} +#[cfg(stage0)] impl !marker::Sync for Weak {} +#[cfg(not(stage0))] +impl !marker::Sync for Weak {} +#[cfg(stage0)] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] impl Weak { @@ -691,7 +897,42 @@ impl Weak { } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl Weak { + /// Upgrades a weak reference to a strong reference. + /// + /// Upgrades the `Weak` reference to an `Rc`, 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> = weak_five.upgrade(); + /// ``` + pub fn upgrade(&self) -> Option> { + 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 Drop for Weak { /// Drops the `Weak`. @@ -736,6 +977,53 @@ impl Drop for Weak { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Weak { + /// Drops the `Weak`. + /// + /// 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 Clone for Weak { @@ -760,14 +1048,48 @@ impl Clone for Weak { Weak { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl Clone for Weak { + /// Makes a clone of the `Weak`. + /// + /// 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 { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} + +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(Weak)") } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Weak { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "(Weak)") + } +} +#[cfg(stage0)] #[doc(hidden)] trait RcBoxPtr { fn inner(&self) -> &RcBox; @@ -790,7 +1112,31 @@ trait RcBoxPtr { #[inline] fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } } +#[cfg(not(stage0))] +#[doc(hidden)] +trait RcBoxPtr { + fn inner(&self) -> &RcBox; + #[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 RcBoxPtr for Rc { #[inline(always)] fn inner(&self) -> &RcBox { @@ -799,12 +1145,27 @@ impl RcBoxPtr for Rc { // 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 RcBoxPtr for Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + 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 RcBoxPtr for Weak { #[inline(always)] fn inner(&self) -> &RcBox { @@ -813,7 +1174,21 @@ impl RcBoxPtr for Weak { // 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 RcBoxPtr for Weak { + #[inline(always)] + fn inner(&self) -> &RcBox { + 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) } }