Skip to content

Commit f05b63b

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 a8a1d3a commit f05b63b

File tree

1 file changed

+82
-49
lines changed

1 file changed

+82
-49
lines changed

library/alloc/src/rc.rs

Lines changed: 82 additions & 49 deletions
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
@@ -1145,12 +1135,9 @@ impl<T, A: Allocator> Rc<mem::MaybeUninit<T>, A> {
11451135
/// ```
11461136
#[unstable(feature = "new_uninit", issue = "63291")]
11471137
#[inline]
1148-
pub unsafe fn assume_init(self) -> Rc<T, A>
1149-
where
1150-
A: Clone,
1151-
{
1152-
let md_self = mem::ManuallyDrop::new(self);
1153-
unsafe { Rc::from_inner_in(md_self.ptr.cast(), md_self.alloc.clone()) }
1138+
pub unsafe fn assume_init(self) -> Rc<T, A> {
1139+
let (ptr, alloc) = Self::into_raw_with_allocator(self);
1140+
unsafe { Rc::from_raw_in(ptr.cast(), alloc) }
11541141
}
11551142
}
11561143

@@ -1189,12 +1176,9 @@ impl<T, A: Allocator> Rc<[mem::MaybeUninit<T>], A> {
11891176
/// ```
11901177
#[unstable(feature = "new_uninit", issue = "63291")]
11911178
#[inline]
1192-
pub unsafe fn assume_init(self) -> Rc<[T], A>
1193-
where
1194-
A: Clone,
1195-
{
1196-
let md_self = mem::ManuallyDrop::new(self);
1197-
unsafe { Rc::from_ptr_in(md_self.ptr.as_ptr() as _, md_self.alloc.clone()) }
1179+
pub unsafe fn assume_init(self) -> Rc<[T], A> {
1180+
let (ptr, alloc) = Self::into_raw_with_allocator(self);
1181+
unsafe { Rc::from_raw_in(ptr as *const [T], alloc) }
11981182
}
11991183
}
12001184

@@ -1333,6 +1317,17 @@ impl<T: ?Sized> Rc<T> {
13331317
}
13341318

13351319
impl<T: ?Sized, A: Allocator> Rc<T, A> {
1320+
/// Returns a reference to the underlying allocator.
1321+
///
1322+
/// Note: this is an associated function, which means that you have
1323+
/// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This
1324+
/// is so that there is no conflict with a method on the inner type.
1325+
#[inline]
1326+
#[unstable(feature = "allocator_api", issue = "32838")]
1327+
pub fn allocator(this: &Self) -> &A {
1328+
&this.alloc
1329+
}
1330+
13361331
/// Consumes the `Rc`, returning the wrapped pointer.
13371332
///
13381333
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -1356,6 +1351,33 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
13561351
ptr
13571352
}
13581353

1354+
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
1355+
///
1356+
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
1357+
/// [`Rc::from_raw_in`].
1358+
///
1359+
/// # Examples
1360+
///
1361+
/// ```
1362+
/// #![feature(allocator_api)]
1363+
/// use std::rc::Rc;
1364+
/// use std::alloc::System;
1365+
///
1366+
/// let x = Rc::new_in("hello".to_owned(), System);
1367+
/// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
1368+
/// assert_eq!(unsafe { &*ptr }, "hello");
1369+
/// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
1370+
/// assert_eq!(&*x, "hello");
1371+
/// ```
1372+
#[unstable(feature = "allocator_api", issue = "32838")]
1373+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1374+
let this = mem::ManuallyDrop::new(this);
1375+
let ptr = Self::as_ptr(&this);
1376+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1377+
let alloc = unsafe { ptr::read(Self::allocator(&this)) };
1378+
(ptr, alloc)
1379+
}
1380+
13591381
/// Provides a raw pointer to the data.
13601382
///
13611383
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
@@ -1809,7 +1831,9 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
18091831
// reference to the allocation.
18101832
unsafe { &mut this.ptr.as_mut().value }
18111833
}
1834+
}
18121835

1836+
impl<T: Clone, A: Allocator> Rc<T, A> {
18131837
/// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
18141838
/// clone.
18151839
///
@@ -1845,7 +1869,7 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
18451869
}
18461870
}
18471871

1848-
impl<A: Allocator + Clone> Rc<dyn Any, A> {
1872+
impl<A: Allocator> Rc<dyn Any, A> {
18491873
/// Attempt to downcast the `Rc<dyn Any>` to a concrete type.
18501874
///
18511875
/// # Examples
@@ -1868,12 +1892,11 @@ impl<A: Allocator + Clone> Rc<dyn Any, A> {
18681892
#[stable(feature = "rc_downcast", since = "1.29.0")]
18691893
pub fn downcast<T: Any>(self) -> Result<Rc<T, A>, Self> {
18701894
if (*self).is::<T>() {
1871-
unsafe {
1872-
let ptr = self.ptr.cast::<RcBox<T>>();
1873-
let alloc = self.alloc.clone();
1874-
forget(self);
1875-
Ok(Rc::from_inner_in(ptr, alloc))
1876-
}
1895+
let this = mem::ManuallyDrop::new(self);
1896+
let ptr = this.ptr.cast::<RcBox<T>>();
1897+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1898+
let alloc = unsafe { ptr::read(&this.alloc) };
1899+
unsafe { Ok(Rc::from_inner_in(ptr, alloc)) }
18771900
} else {
18781901
Err(self)
18791902
}
@@ -1908,12 +1931,11 @@ impl<A: Allocator + Clone> Rc<dyn Any, A> {
19081931
#[inline]
19091932
#[unstable(feature = "downcast_unchecked", issue = "90850")]
19101933
pub unsafe fn downcast_unchecked<T: Any>(self) -> Rc<T, A> {
1911-
unsafe {
1912-
let ptr = self.ptr.cast::<RcBox<T>>();
1913-
let alloc = self.alloc.clone();
1914-
mem::forget(self);
1915-
Rc::from_inner_in(ptr, alloc)
1916-
}
1934+
let this = mem::ManuallyDrop::new(self);
1935+
let ptr = this.ptr.cast::<RcBox<T>>();
1936+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1937+
let alloc = unsafe { ptr::read(&this.alloc) };
1938+
unsafe { Rc::from_inner_in(ptr, alloc) }
19171939
}
19181940
}
19191941

@@ -2661,12 +2683,13 @@ impl From<Rc<str>> for Rc<[u8]> {
26612683
}
26622684

26632685
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
2664-
impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]> {
2665-
type Error = Rc<[T]>;
2686+
impl<T, A: Allocator, const N: usize> TryFrom<Rc<[T], A>> for Rc<[T; N], A> {
2687+
type Error = Rc<[T], A>;
26662688

2667-
fn try_from(boxed_slice: Rc<[T]>) -> Result<Self, Self::Error> {
2689+
fn try_from(boxed_slice: Rc<[T], A>) -> Result<Self, Self::Error> {
26682690
if boxed_slice.len() == N {
2669-
Ok(unsafe { Rc::from_raw(Rc::into_raw(boxed_slice) as *mut [T; N]) })
2691+
let (ptr, alloc) = Rc::into_raw_with_allocator(boxed_slice);
2692+
Ok(unsafe { Rc::from_raw_in(ptr as *mut [T; N], alloc) })
26702693
} else {
26712694
Err(boxed_slice)
26722695
}
@@ -2923,6 +2946,13 @@ impl<T: ?Sized> Weak<T> {
29232946
}
29242947

29252948
impl<T: ?Sized, A: Allocator> Weak<T, A> {
2949+
/// Returns a reference to the underlying allocator.
2950+
#[inline]
2951+
#[unstable(feature = "allocator_api", issue = "32838")]
2952+
pub fn allocator(&self) -> &A {
2953+
&self.alloc
2954+
}
2955+
29262956
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
29272957
///
29282958
/// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -3000,39 +3030,42 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
30003030
result
30013031
}
30023032

3003-
/// Consumes the `Weak<T>` and turns it into a raw pointer.
3033+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
30043034
///
30053035
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
30063036
/// one weak reference (the weak count is not modified by this operation). It can be turned
3007-
/// back into the `Weak<T>` with [`from_raw`].
3037+
/// back into the `Weak<T>` with [`from_raw_in`].
30083038
///
30093039
/// The same restrictions of accessing the target of the pointer as with
30103040
/// [`as_ptr`] apply.
30113041
///
30123042
/// # Examples
30133043
///
30143044
/// ```
3045+
/// #![feature(allocator_api)]
30153046
/// use std::rc::{Rc, Weak};
3047+
/// use std::alloc::System;
30163048
///
3017-
/// let strong = Rc::new("hello".to_owned());
3049+
/// let strong = Rc::new_in("hello".to_owned(), System);
30183050
/// let weak = Rc::downgrade(&strong);
3019-
/// let raw = weak.into_raw();
3051+
/// let (raw, alloc) = weak.into_raw_with_allocator();
30203052
///
30213053
/// assert_eq!(1, Rc::weak_count(&strong));
30223054
/// assert_eq!("hello", unsafe { &*raw });
30233055
///
3024-
/// drop(unsafe { Weak::from_raw(raw) });
3056+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
30253057
/// assert_eq!(0, Rc::weak_count(&strong));
30263058
/// ```
30273059
///
3028-
/// [`from_raw`]: Weak::from_raw
3060+
/// [`from_raw_in`]: Weak::from_raw_in
30293061
/// [`as_ptr`]: Weak::as_ptr
30303062
#[inline]
30313063
#[unstable(feature = "allocator_api", issue = "32838")]
3032-
pub fn into_raw_and_alloc(self) -> (*const T, A) {
3033-
let rc = mem::ManuallyDrop::new(self);
3034-
let result = rc.as_ptr();
3035-
let alloc = unsafe { ptr::read(&rc.alloc) };
3064+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
3065+
let this = mem::ManuallyDrop::new(self);
3066+
let result = this.as_ptr();
3067+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
3068+
let alloc = unsafe { ptr::read(this.allocator()) };
30363069
(result, alloc)
30373070
}
30383071

0 commit comments

Comments
 (0)