Skip to content

Commit bf1b76a

Browse files
committed
Add into_raw_with_allocator for Rc/Arc/Weak.
1 parent 76101ee commit bf1b76a

File tree

2 files changed

+108
-13
lines changed

2 files changed

+108
-13
lines changed

library/alloc/src/rc.rs

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,33 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
13111311
ptr
13121312
}
13131313

1314+
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
1315+
///
1316+
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
1317+
/// [`Rc::from_raw_in`].
1318+
///
1319+
/// # Examples
1320+
///
1321+
/// ```
1322+
/// #![feature(allocator_api)]
1323+
/// use std::rc::Rc;
1324+
/// use std::alloc::System;
1325+
///
1326+
/// let x = Rc::new_in("hello".to_owned(), System);
1327+
/// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
1328+
/// assert_eq!(unsafe { &*x }, "hello");
1329+
/// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
1330+
/// assert_eq!(&*x, "hello");
1331+
/// ```
1332+
#[unstable(feature = "allocator_api", issue = "32838")]
1333+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1334+
let this = mem::ManuallyDrop::new(this);
1335+
let ptr = Self::as_ptr(&this);
1336+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1337+
let alloc = unsafe { ptr::read(Self::allocator(&this)) };
1338+
(ptr, alloc)
1339+
}
1340+
13141341
/// Provides a raw pointer to the data.
13151342
///
13161343
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
@@ -2917,42 +2944,42 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
29172944
result
29182945
}
29192946

2920-
/// Consumes the `Weak<T>` and turns it into a raw pointer.
2947+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
29212948
///
29222949
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
29232950
/// one weak reference (the weak count is not modified by this operation). It can be turned
2924-
/// back into the `Weak<T>` with [`from_raw`].
2951+
/// back into the `Weak<T>` with [`from_raw_in`].
29252952
///
29262953
/// The same restrictions of accessing the target of the pointer as with
29272954
/// [`as_ptr`] apply.
29282955
///
29292956
/// # Examples
29302957
///
29312958
/// ```
2959+
/// #![feature(allocator_api)]
29322960
/// use std::rc::{Rc, Weak};
2961+
/// use std::alloc::System;
29332962
///
2934-
/// let strong = Rc::new("hello".to_owned());
2963+
/// let strong = Rc::new_in("hello".to_owned(), System);
29352964
/// let weak = Rc::downgrade(&strong);
2936-
/// let raw = weak.into_raw();
2965+
/// let (raw, alloc) = weak.into_raw_with_allocator();
29372966
///
29382967
/// assert_eq!(1, Rc::weak_count(&strong));
29392968
/// assert_eq!("hello", unsafe { &*raw });
29402969
///
2941-
/// drop(unsafe { Weak::from_raw(raw) });
2970+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
29422971
/// assert_eq!(0, Rc::weak_count(&strong));
29432972
/// ```
29442973
///
2945-
/// [`from_raw`]: Weak::from_raw
2974+
/// [`from_raw_in`]: Weak::from_raw_in
29462975
/// [`as_ptr`]: Weak::as_ptr
29472976
#[inline]
29482977
#[unstable(feature = "allocator_api", issue = "32838")]
2949-
pub fn into_raw_and_alloc(self) -> (*const T, A)
2950-
where
2951-
A: Clone,
2952-
{
2953-
let result = self.as_ptr();
2954-
let alloc = self.alloc.clone();
2955-
mem::forget(self);
2978+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
2979+
let this = mem::ManuallyDrop::new(self);
2980+
let result = this.as_ptr();
2981+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
2982+
let alloc = unsafe { ptr::read(this.allocator()) };
29562983
(result, alloc)
29572984
}
29582985

library/alloc/src/sync.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,33 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
14621462
ptr
14631463
}
14641464

1465+
/// Consumes the `Arc`, returning the wrapped pointer and the allocator.
1466+
///
1467+
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
1468+
/// [`Arc::from_raw_in`].
1469+
///
1470+
/// # Examples
1471+
///
1472+
/// ```
1473+
/// #![feature(allocator_api)]
1474+
/// use std::sync::Arc;
1475+
/// use std::alloc::System;
1476+
///
1477+
/// let x = Arc::new_in("hello".to_owned(), System);
1478+
/// let (ptr, alloc) = Arc::into_raw_with_allocator(x);
1479+
/// let x = unsafe { Arc::from_raw_in(ptr, alloc) };
1480+
/// assert_eq!(&*x, "hello");
1481+
/// ```
1482+
#[must_use = "losing the pointer will leak memory"]
1483+
#[unstable(feature = "allocator_api", issue = "32838")]
1484+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1485+
let this = mem::ManuallyDrop::new(this);
1486+
let ptr = Self::as_ptr(&this);
1487+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1488+
let alloc = unsafe { ptr::read(Self::allocator(&this)) };
1489+
(ptr, alloc)
1490+
}
1491+
14651492
/// Provides a raw pointer to the data.
14661493
///
14671494
/// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
@@ -2675,6 +2702,47 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
26752702
result
26762703
}
26772704

2705+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
2706+
///
2707+
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
2708+
/// one weak reference (the weak count is not modified by this operation). It can be turned
2709+
/// back into the `Weak<T>` with [`from_raw_in`].
2710+
///
2711+
/// The same restrictions of accessing the target of the pointer as with
2712+
/// [`as_ptr`] apply.
2713+
///
2714+
/// # Examples
2715+
///
2716+
/// ```
2717+
/// #![feature(allocator_api)]
2718+
/// use std::sync::{Arc, Weak};
2719+
/// use std::alloc::System;
2720+
///
2721+
/// let strong = Arc::new_in("hello".to_owned(), System);
2722+
/// let weak = Arc::downgrade(&strong);
2723+
/// let (raw, alloc) = weak.into_raw_with_allocator();
2724+
///
2725+
/// assert_eq!(1, Arc::weak_count(&strong));
2726+
/// assert_eq!("hello", unsafe { &*raw });
2727+
///
2728+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
2729+
/// assert_eq!(0, Arc::weak_count(&strong));
2730+
/// ```
2731+
///
2732+
/// [`from_raw_in`]: Weak::from_raw_in
2733+
/// [`as_ptr`]: Weak::as_ptr
2734+
#[inline]
2735+
#[unstable(feature = "allocator_api", issue = "32838")]
2736+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
2737+
let this = mem::ManuallyDrop::new(self);
2738+
let result = this.as_ptr();
2739+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
2740+
let alloc = unsafe { ptr::read(this.allocator()) };
2741+
(result, alloc)
2742+
}
2743+
2744+
2745+
26782746
/// Converts a raw pointer previously created by [`into_raw`] back into `Weak<T>` in the provided
26792747
/// allocator.
26802748
///

0 commit comments

Comments
 (0)