Skip to content

Commit 28cb2d7

Browse files
committed
Add fn into_raw_with_allocator to Rc/Arc/Weak.
1 parent ab14f94 commit 28cb2d7

File tree

2 files changed

+107
-10
lines changed

2 files changed

+107
-10
lines changed

library/alloc/src/rc.rs

+40-10
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,33 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
13561356
ptr
13571357
}
13581358

1359+
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
1360+
///
1361+
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
1362+
/// [`Rc::from_raw_in`].
1363+
///
1364+
/// # Examples
1365+
///
1366+
/// ```
1367+
/// #![feature(allocator_api)]
1368+
/// use std::rc::Rc;
1369+
/// use std::alloc::System;
1370+
///
1371+
/// let x = Rc::new_in("hello".to_owned(), System);
1372+
/// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
1373+
/// assert_eq!(unsafe { &*ptr }, "hello");
1374+
/// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
1375+
/// assert_eq!(&*x, "hello");
1376+
/// ```
1377+
#[unstable(feature = "allocator_api", issue = "32838")]
1378+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1379+
let this = mem::ManuallyDrop::new(this);
1380+
let ptr = Self::as_ptr(&this);
1381+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1382+
let alloc = unsafe { ptr::read(Self::allocator(&this)) };
1383+
(ptr, alloc)
1384+
}
1385+
13591386
/// Provides a raw pointer to the data.
13601387
///
13611388
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
@@ -2999,39 +3026,42 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
29993026
result
30003027
}
30013028

3002-
/// Consumes the `Weak<T>` and turns it into a raw pointer.
3029+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
30033030
///
30043031
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
30053032
/// one weak reference (the weak count is not modified by this operation). It can be turned
3006-
/// back into the `Weak<T>` with [`from_raw`].
3033+
/// back into the `Weak<T>` with [`from_raw_in`].
30073034
///
30083035
/// The same restrictions of accessing the target of the pointer as with
30093036
/// [`as_ptr`] apply.
30103037
///
30113038
/// # Examples
30123039
///
30133040
/// ```
3041+
/// #![feature(allocator_api)]
30143042
/// use std::rc::{Rc, Weak};
3043+
/// use std::alloc::System;
30153044
///
3016-
/// let strong = Rc::new("hello".to_owned());
3045+
/// let strong = Rc::new_in("hello".to_owned(), System);
30173046
/// let weak = Rc::downgrade(&strong);
3018-
/// let raw = weak.into_raw();
3047+
/// let (raw, alloc) = weak.into_raw_with_allocator();
30193048
///
30203049
/// assert_eq!(1, Rc::weak_count(&strong));
30213050
/// assert_eq!("hello", unsafe { &*raw });
30223051
///
3023-
/// drop(unsafe { Weak::from_raw(raw) });
3052+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
30243053
/// assert_eq!(0, Rc::weak_count(&strong));
30253054
/// ```
30263055
///
3027-
/// [`from_raw`]: Weak::from_raw
3056+
/// [`from_raw_in`]: Weak::from_raw_in
30283057
/// [`as_ptr`]: Weak::as_ptr
30293058
#[inline]
30303059
#[unstable(feature = "allocator_api", issue = "32838")]
3031-
pub fn into_raw_and_alloc(self) -> (*const T, A) {
3032-
let rc = mem::ManuallyDrop::new(self);
3033-
let result = rc.as_ptr();
3034-
let alloc = unsafe { ptr::read(&rc.alloc) };
3060+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
3061+
let this = mem::ManuallyDrop::new(self);
3062+
let result = this.as_ptr();
3063+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
3064+
let alloc = unsafe { ptr::read(this.allocator()) };
30353065
(result, alloc)
30363066
}
30373067

library/alloc/src/sync.rs

+67
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,34 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
14961496
ptr
14971497
}
14981498

1499+
/// Consumes the `Arc`, returning the wrapped pointer and allocator.
1500+
///
1501+
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
1502+
/// [`Arc::from_raw_in`].
1503+
///
1504+
/// # Examples
1505+
///
1506+
/// ```
1507+
/// #![feature(allocator_api)]
1508+
/// use std::sync::Arc;
1509+
/// use std::alloc::System;
1510+
///
1511+
/// let x = Arc::new_in("hello".to_owned(), System);
1512+
/// let (ptr, alloc) = Arc::into_raw_with_allocator(x);
1513+
/// assert_eq!(unsafe { &*ptr }, "hello");
1514+
/// let x = unsafe { Arc::from_raw_in(ptr, alloc) };
1515+
/// assert_eq!(&*x, "hello");
1516+
/// ```
1517+
#[must_use = "losing the pointer will leak memory"]
1518+
#[unstable(feature = "allocator_api", issue = "32838")]
1519+
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
1520+
let this = mem::ManuallyDrop::new(this);
1521+
let ptr = Self::as_ptr(&this);
1522+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
1523+
let alloc = unsafe { ptr::read(Self::allocator(&this)) };
1524+
(ptr, alloc)
1525+
}
1526+
14991527
/// Provides a raw pointer to the data.
15001528
///
15011529
/// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
@@ -2740,6 +2768,45 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
27402768
result
27412769
}
27422770

2771+
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
2772+
///
2773+
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
2774+
/// one weak reference (the weak count is not modified by this operation). It can be turned
2775+
/// back into the `Weak<T>` with [`from_raw_in`].
2776+
///
2777+
/// The same restrictions of accessing the target of the pointer as with
2778+
/// [`as_ptr`] apply.
2779+
///
2780+
/// # Examples
2781+
///
2782+
/// ```
2783+
/// #![feature(allocator_api)]
2784+
/// use std::sync::{Arc, Weak};
2785+
/// use std::alloc::System;
2786+
///
2787+
/// let strong = Arc::new_in("hello".to_owned(), System);
2788+
/// let weak = Arc::downgrade(&strong);
2789+
/// let (raw, alloc) = weak.into_raw_with_allocator();
2790+
///
2791+
/// assert_eq!(1, Arc::weak_count(&strong));
2792+
/// assert_eq!("hello", unsafe { &*raw });
2793+
///
2794+
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
2795+
/// assert_eq!(0, Arc::weak_count(&strong));
2796+
/// ```
2797+
///
2798+
/// [`from_raw_in`]: Weak::from_raw_in
2799+
/// [`as_ptr`]: Weak::as_ptr
2800+
#[must_use = "losing the pointer will leak memory"]
2801+
#[unstable(feature = "allocator_api", issue = "32838")]
2802+
pub fn into_raw_with_allocator(self) -> (*const T, A) {
2803+
let this = mem::ManuallyDrop::new(self);
2804+
let result = this.as_ptr();
2805+
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
2806+
let alloc = unsafe { ptr::read(Self::allocator(&this)) };
2807+
(result, alloc)
2808+
}
2809+
27432810
/// Converts a raw pointer previously created by [`into_raw`] back into `Weak<T>` in the provided
27442811
/// allocator.
27452812
///

0 commit comments

Comments
 (0)