Skip to content

Commit c412131

Browse files
committed
Make Rc allocator_api APIs more consistent.
* Add `into_raw_with_allocator` on `Rc`/`Weak` * Remove `where A: Clone` from `Rc::assume_init`s, `Rc::unwrap_or_clone`, and `Rc::downcast(_unchecked)` * Add `fn allocator(&self)` to `Rc`/`Weak` for all `T: ?Sized` * Make `TryFrom<Rc<[T]>> for Rc<[T; N]>` allocator-aware
1 parent b5c46dc commit c412131

File tree

1 file changed

+82
-52
lines changed

1 file changed

+82
-52
lines changed

library/alloc/src/rc.rs

+82-52
Original file line numberDiff line numberDiff line change
@@ -661,16 +661,6 @@ impl<T> Rc<T> {
661661
}
662662

663663
impl<T, A: Allocator> Rc<T, A> {
664-
/// Returns a reference to the underlying allocator.
665-
///
666-
/// Note: this is an associated function, which means that you have
667-
/// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This
668-
/// is so that there is no conflict with a method on the inner type.
669-
#[inline]
670-
#[unstable(feature = "allocator_api", issue = "32838")]
671-
pub fn allocator(this: &Self) -> &A {
672-
&this.alloc
673-
}
674664
/// Constructs a new `Rc` in the provided allocator.
675665
///
676666
/// # Examples
@@ -1127,12 +1117,9 @@ impl<T, A: Allocator> Rc<mem::MaybeUninit<T>, A> {
11271117
/// ```
11281118
#[unstable(feature = "new_uninit", issue = "63291")]
11291119
#[inline]
1130-
pub unsafe fn assume_init(self) -> Rc<T, A>
1131-
where
1132-
A: Clone,
1133-
{
1134-
let md_self = mem::ManuallyDrop::new(self);
1135-
unsafe { Rc::from_inner_in(md_self.ptr.cast(), md_self.alloc.clone()) }
1120+
pub unsafe fn assume_init(self) -> Rc<T, A> {
1121+
let (ptr, alloc) = Self::into_raw_with_allocator(self);
1122+
unsafe { Rc::from_raw_in(ptr.cast(), alloc) }
11361123
}
11371124
}
11381125

@@ -1171,12 +1158,9 @@ impl<T, A: Allocator> Rc<[mem::MaybeUninit<T>], A> {
11711158
/// ```
11721159
#[unstable(feature = "new_uninit", issue = "63291")]
11731160
#[inline]
1174-
pub unsafe fn assume_init(self) -> Rc<[T], A>
1175-
where
1176-
A: Clone,
1177-
{
1178-
let md_self = mem::ManuallyDrop::new(self);
1179-
unsafe { Rc::from_ptr_in(md_self.ptr.as_ptr() as _, md_self.alloc.clone()) }
1161+
pub unsafe fn assume_init(self) -> Rc<[T], A> {
1162+
let (ptr, alloc) = Self::into_raw_with_allocator(self);
1163+
unsafe { Rc::from_raw_in(ptr as *const [T], alloc) }
11801164
}
11811165
}
11821166

@@ -1293,6 +1277,17 @@ impl<T: ?Sized> Rc<T> {
12931277
}
12941278

12951279
impl<T: ?Sized, A: Allocator> Rc<T, A> {
1280+
/// Returns a reference to the underlying allocator.
1281+
///
1282+
/// Note: this is an associated function, which means that you have
1283+
/// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This
1284+
/// is so that there is no conflict with a method on the inner type.
1285+
#[inline]
1286+
#[unstable(feature = "allocator_api", issue = "32838")]
1287+
pub fn allocator(this: &Self) -> &A {
1288+
&this.alloc
1289+
}
1290+
12961291
/// Consumes the `Rc`, returning the wrapped pointer.
12971292
///
12981293
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -1315,6 +1310,33 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
13151310
ptr
13161311
}
13171312

1313+
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
1314+
///
1315+
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
1316+
/// [`Rc::from_raw_in`].
1317+
///
1318+
/// # Examples
1319+
///
1320+
/// ```
1321+
/// #![feature(allocator_api)]
1322+
/// use std::rc::Rc;
1323+
/// use std::alloc::System;
1324+
///
1325+
/// let x = Rc::new_in("hello".to_owned(), System);
1326+
/// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
1327+
/// assert_eq!(unsafe { &*ptr }, "hello");
1328+
/// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
1329+
/// assert_eq!(&*x, "hello");
1330+
/// ```
1331+
#[unstable(feature = "allocator_api", issue = "32838")]
1332+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1333+
let this = mem::ManuallyDrop::new(this);
1334+
let ptr = Self::as_ptr(&this);
1335+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1336+
let alloc = unsafe { ptr::read(Self::allocator(&this)) };
1337+
(ptr, alloc)
1338+
}
1339+
13181340
/// Provides a raw pointer to the data.
13191341
///
13201342
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
@@ -1742,7 +1764,9 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
17421764
// reference to the allocation.
17431765
unsafe { &mut this.ptr.as_mut().value }
17441766
}
1767+
}
17451768

1769+
impl<T: Clone, A: Allocator> Rc<T, A> {
17461770
/// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
17471771
/// clone.
17481772
///
@@ -1778,7 +1802,7 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
17781802
}
17791803
}
17801804

1781-
impl<A: Allocator + Clone> Rc<dyn Any, A> {
1805+
impl<A: Allocator> Rc<dyn Any, A> {
17821806
/// Attempt to downcast the `Rc<dyn Any>` to a concrete type.
17831807
///
17841808
/// # Examples
@@ -1801,12 +1825,11 @@ impl<A: Allocator + Clone> Rc<dyn Any, A> {
18011825
#[stable(feature = "rc_downcast", since = "1.29.0")]
18021826
pub fn downcast<T: Any>(self) -> Result<Rc<T, A>, Self> {
18031827
if (*self).is::<T>() {
1804-
unsafe {
1805-
let ptr = self.ptr.cast::<RcBox<T>>();
1806-
let alloc = self.alloc.clone();
1807-
forget(self);
1808-
Ok(Rc::from_inner_in(ptr, alloc))
1809-
}
1828+
let this = mem::ManuallyDrop::new(self);
1829+
let ptr = this.ptr.cast::<RcBox<T>>();
1830+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1831+
let alloc = unsafe { ptr::read(&this.alloc) };
1832+
unsafe { Ok(Rc::from_inner_in(ptr, alloc)) }
18101833
} else {
18111834
Err(self)
18121835
}
@@ -1841,12 +1864,11 @@ impl<A: Allocator + Clone> Rc<dyn Any, A> {
18411864
#[inline]
18421865
#[unstable(feature = "downcast_unchecked", issue = "90850")]
18431866
pub unsafe fn downcast_unchecked<T: Any>(self) -> Rc<T, A> {
1844-
unsafe {
1845-
let ptr = self.ptr.cast::<RcBox<T>>();
1846-
let alloc = self.alloc.clone();
1847-
mem::forget(self);
1848-
Rc::from_inner_in(ptr, alloc)
1849-
}
1867+
let this = mem::ManuallyDrop::new(self);
1868+
let ptr = this.ptr.cast::<RcBox<T>>();
1869+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1870+
let alloc = unsafe { ptr::read(&this.alloc) };
1871+
unsafe { Rc::from_inner_in(ptr, alloc) }
18501872
}
18511873
}
18521874

@@ -2591,12 +2613,13 @@ impl From<Rc<str>> for Rc<[u8]> {
25912613
}
25922614

25932615
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
2594-
impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]> {
2595-
type Error = Rc<[T]>;
2616+
impl<T, A: Allocator, const N: usize> TryFrom<Rc<[T], A>> for Rc<[T; N], A> {
2617+
type Error = Rc<[T], A>;
25962618

2597-
fn try_from(boxed_slice: Rc<[T]>) -> Result<Self, Self::Error> {
2619+
fn try_from(boxed_slice: Rc<[T], A>) -> Result<Self, Self::Error> {
25982620
if boxed_slice.len() == N {
2599-
Ok(unsafe { Rc::from_raw(Rc::into_raw(boxed_slice) as *mut [T; N]) })
2621+
let (ptr, alloc) = Rc::into_raw_with_allocator(boxed_slice);
2622+
Ok(unsafe { Rc::from_raw_in(ptr as *mut [T; N], alloc) })
26002623
} else {
26012624
Err(boxed_slice)
26022625
}
@@ -2849,6 +2872,13 @@ impl<T: ?Sized> Weak<T> {
28492872
}
28502873

28512874
impl<T: ?Sized, A: Allocator> Weak<T, A> {
2875+
/// Returns a reference to the underlying allocator.
2876+
#[inline]
2877+
#[unstable(feature = "allocator_api", issue = "32838")]
2878+
pub fn allocator(&self) -> &A {
2879+
&self.alloc
2880+
}
2881+
28522882
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
28532883
///
28542884
/// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -2926,42 +2956,42 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
29262956
result
29272957
}
29282958

2929-
/// Consumes the `Weak<T>` and turns it into a raw pointer.
2959+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
29302960
///
29312961
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
29322962
/// one weak reference (the weak count is not modified by this operation). It can be turned
2933-
/// back into the `Weak<T>` with [`from_raw`].
2963+
/// back into the `Weak<T>` with [`from_raw_in`].
29342964
///
29352965
/// The same restrictions of accessing the target of the pointer as with
29362966
/// [`as_ptr`] apply.
29372967
///
29382968
/// # Examples
29392969
///
29402970
/// ```
2971+
/// #![feature(allocator_api)]
29412972
/// use std::rc::{Rc, Weak};
2973+
/// use std::alloc::System;
29422974
///
2943-
/// let strong = Rc::new("hello".to_owned());
2975+
/// let strong = Rc::new_in("hello".to_owned(), System);
29442976
/// let weak = Rc::downgrade(&strong);
2945-
/// let raw = weak.into_raw();
2977+
/// let (raw, alloc) = weak.into_raw_with_allocator();
29462978
///
29472979
/// assert_eq!(1, Rc::weak_count(&strong));
29482980
/// assert_eq!("hello", unsafe { &*raw });
29492981
///
2950-
/// drop(unsafe { Weak::from_raw(raw) });
2982+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
29512983
/// assert_eq!(0, Rc::weak_count(&strong));
29522984
/// ```
29532985
///
2954-
/// [`from_raw`]: Weak::from_raw
2986+
/// [`from_raw_in`]: Weak::from_raw_in
29552987
/// [`as_ptr`]: Weak::as_ptr
29562988
#[inline]
29572989
#[unstable(feature = "allocator_api", issue = "32838")]
2958-
pub fn into_raw_and_alloc(self) -> (*const T, A)
2959-
where
2960-
A: Clone,
2961-
{
2962-
let result = self.as_ptr();
2963-
let alloc = self.alloc.clone();
2964-
mem::forget(self);
2990+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
2991+
let this = mem::ManuallyDrop::new(self);
2992+
let result = this.as_ptr();
2993+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
2994+
let alloc = unsafe { ptr::read(this.allocator()) };
29652995
(result, alloc)
29662996
}
29672997

0 commit comments

Comments
 (0)