Rollup merge of #125093 - zachs18:rc-into-raw-with-allocator-only, r=Mark-Simulacrum
Add `fn into_raw_with_allocator` to Rc/Arc/Weak. Split out from #119761 Add `fn into_raw_with_allocator` for `Rc`/`rc::Weak`[^1]/`Arc`/`sync::Weak`. * Pairs with `from_raw_in` (which already exists on all 4 types). * Name matches `Box::into_raw_with_allocator`. * Associated fns on `Rc`/`Arc`, methods on `Weak`s. <details> <summary>Future PR/ACP</summary> As a follow-on to this PR, I plan to make a PR/ACP later to move `into_raw(_parts)` from `Container<_, A: Allocator>` to only `Container<_, Global>` (where `Container` = `Vec`/`Box`/`Rc`/`rc::Weak`/`Arc`/`sync::Weak`) so that users of non-`Global` allocators have to explicitly handle the allocator when using `into_raw`-like APIs. The current behaviors of stdlib containers are inconsistent with respect to what happens to the allocator when `into_raw` is called (which does not return the allocator) | Type | `into_raw` currently callable with | behavior of `into_raw`| | --- | --- | --- | | `Box` | any allocator | allocator is [dropped](https://doc.rust-lang.org/nightly/src/alloc/boxed.rs.html#1060) | | `Vec` | any allocator | allocator is [forgotten](https://doc.rust-lang.org/nightly/src/alloc/vec/mod.rs.html#884) | | `Arc`/`Rc`/`Weak` | any allocator | allocator is [forgotten](https://doc.rust-lang.org/src/alloc/sync.rs.html#1487)(Arc) [(sync::Weak)](https://doc.rust-lang.org/src/alloc/sync.rs.html#2726) [(Rc)](https://doc.rust-lang.org/src/alloc/rc.rs.html#1352) [(rc::Weak)](https://doc.rust-lang.org/src/alloc/rc.rs.html#2993) | In my opinion, neither implicitly dropping nor implicitly forgetting the allocator is ideal; dropping it could immediately invalidate the returned pointer, and forgetting it could unintentionally leak memory. My (to-be) proposed solution is to just forbid calling `into_raw(_parts)` on containers with non-`Global` allocators, and require calling `into_raw_with_allocator`(/`Vec::into_raw_parts_with_alloc`) </details> [^1]: Technically, `rc::Weak::into_raw_with_allocator` is not newly added, as it was modified and renamed from `rc::Weak::into_raw_and_alloc`.
This commit is contained in:
commit
7389416284
@ -1356,6 +1356,33 @@ pub fn into_raw(this: Self) -> *const T {
|
|||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Rc`, returning the wrapped pointer and allocator.
|
||||||
|
///
|
||||||
|
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
|
||||||
|
/// [`Rc::from_raw_in`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api)]
|
||||||
|
/// use std::rc::Rc;
|
||||||
|
/// use std::alloc::System;
|
||||||
|
///
|
||||||
|
/// let x = Rc::new_in("hello".to_owned(), System);
|
||||||
|
/// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
|
||||||
|
/// assert_eq!(unsafe { &*ptr }, "hello");
|
||||||
|
/// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
|
||||||
|
/// assert_eq!(&*x, "hello");
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
|
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
|
||||||
|
let this = mem::ManuallyDrop::new(this);
|
||||||
|
let ptr = Self::as_ptr(&this);
|
||||||
|
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
|
||||||
|
let alloc = unsafe { ptr::read(&this.alloc) };
|
||||||
|
(ptr, alloc)
|
||||||
|
}
|
||||||
|
|
||||||
/// Provides a raw pointer to the data.
|
/// Provides a raw pointer to the data.
|
||||||
///
|
///
|
||||||
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
|
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
|
||||||
@ -3024,11 +3051,11 @@ pub fn into_raw(self) -> *const T {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the `Weak<T>` and turns it into a raw pointer.
|
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
|
||||||
///
|
///
|
||||||
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
|
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
|
||||||
/// one weak reference (the weak count is not modified by this operation). It can be turned
|
/// one weak reference (the weak count is not modified by this operation). It can be turned
|
||||||
/// back into the `Weak<T>` with [`from_raw`].
|
/// back into the `Weak<T>` with [`from_raw_in`].
|
||||||
///
|
///
|
||||||
/// The same restrictions of accessing the target of the pointer as with
|
/// The same restrictions of accessing the target of the pointer as with
|
||||||
/// [`as_ptr`] apply.
|
/// [`as_ptr`] apply.
|
||||||
@ -3036,27 +3063,30 @@ pub fn into_raw(self) -> *const T {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// #![feature(allocator_api)]
|
||||||
/// use std::rc::{Rc, Weak};
|
/// use std::rc::{Rc, Weak};
|
||||||
|
/// use std::alloc::System;
|
||||||
///
|
///
|
||||||
/// let strong = Rc::new("hello".to_owned());
|
/// let strong = Rc::new_in("hello".to_owned(), System);
|
||||||
/// let weak = Rc::downgrade(&strong);
|
/// let weak = Rc::downgrade(&strong);
|
||||||
/// let raw = weak.into_raw();
|
/// let (raw, alloc) = weak.into_raw_with_allocator();
|
||||||
///
|
///
|
||||||
/// assert_eq!(1, Rc::weak_count(&strong));
|
/// assert_eq!(1, Rc::weak_count(&strong));
|
||||||
/// assert_eq!("hello", unsafe { &*raw });
|
/// assert_eq!("hello", unsafe { &*raw });
|
||||||
///
|
///
|
||||||
/// drop(unsafe { Weak::from_raw(raw) });
|
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
|
||||||
/// assert_eq!(0, Rc::weak_count(&strong));
|
/// assert_eq!(0, Rc::weak_count(&strong));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`from_raw`]: Weak::from_raw
|
/// [`from_raw_in`]: Weak::from_raw_in
|
||||||
/// [`as_ptr`]: Weak::as_ptr
|
/// [`as_ptr`]: Weak::as_ptr
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
pub fn into_raw_and_alloc(self) -> (*const T, A) {
|
pub fn into_raw_with_allocator(self) -> (*const T, A) {
|
||||||
let rc = mem::ManuallyDrop::new(self);
|
let this = mem::ManuallyDrop::new(self);
|
||||||
let result = rc.as_ptr();
|
let result = this.as_ptr();
|
||||||
let alloc = unsafe { ptr::read(&rc.alloc) };
|
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
|
||||||
|
let alloc = unsafe { ptr::read(&this.alloc) };
|
||||||
(result, alloc)
|
(result, alloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1496,6 +1496,34 @@ pub fn into_raw(this: Self) -> *const T {
|
|||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Arc`, returning the wrapped pointer and allocator.
|
||||||
|
///
|
||||||
|
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
|
||||||
|
/// [`Arc::from_raw_in`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api)]
|
||||||
|
/// use std::sync::Arc;
|
||||||
|
/// use std::alloc::System;
|
||||||
|
///
|
||||||
|
/// let x = Arc::new_in("hello".to_owned(), System);
|
||||||
|
/// let (ptr, alloc) = Arc::into_raw_with_allocator(x);
|
||||||
|
/// assert_eq!(unsafe { &*ptr }, "hello");
|
||||||
|
/// let x = unsafe { Arc::from_raw_in(ptr, alloc) };
|
||||||
|
/// assert_eq!(&*x, "hello");
|
||||||
|
/// ```
|
||||||
|
#[must_use = "losing the pointer will leak memory"]
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
|
pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
|
||||||
|
let this = mem::ManuallyDrop::new(this);
|
||||||
|
let ptr = Self::as_ptr(&this);
|
||||||
|
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
|
||||||
|
let alloc = unsafe { ptr::read(&this.alloc) };
|
||||||
|
(ptr, alloc)
|
||||||
|
}
|
||||||
|
|
||||||
/// Provides a raw pointer to the data.
|
/// Provides a raw pointer to the data.
|
||||||
///
|
///
|
||||||
/// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
|
/// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
|
||||||
@ -2740,6 +2768,45 @@ pub fn into_raw(self) -> *const T {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
|
||||||
|
///
|
||||||
|
/// This converts the weak pointer into a raw pointer, while still preserving the ownership of
|
||||||
|
/// one weak reference (the weak count is not modified by this operation). It can be turned
|
||||||
|
/// back into the `Weak<T>` with [`from_raw_in`].
|
||||||
|
///
|
||||||
|
/// The same restrictions of accessing the target of the pointer as with
|
||||||
|
/// [`as_ptr`] apply.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api)]
|
||||||
|
/// use std::sync::{Arc, Weak};
|
||||||
|
/// use std::alloc::System;
|
||||||
|
///
|
||||||
|
/// let strong = Arc::new_in("hello".to_owned(), System);
|
||||||
|
/// let weak = Arc::downgrade(&strong);
|
||||||
|
/// let (raw, alloc) = weak.into_raw_with_allocator();
|
||||||
|
///
|
||||||
|
/// assert_eq!(1, Arc::weak_count(&strong));
|
||||||
|
/// assert_eq!("hello", unsafe { &*raw });
|
||||||
|
///
|
||||||
|
/// drop(unsafe { Weak::from_raw_in(raw, alloc) });
|
||||||
|
/// assert_eq!(0, Arc::weak_count(&strong));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`from_raw_in`]: Weak::from_raw_in
|
||||||
|
/// [`as_ptr`]: Weak::as_ptr
|
||||||
|
#[must_use = "losing the pointer will leak memory"]
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
|
pub fn into_raw_with_allocator(self) -> (*const T, A) {
|
||||||
|
let this = mem::ManuallyDrop::new(self);
|
||||||
|
let result = this.as_ptr();
|
||||||
|
// Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
|
||||||
|
let alloc = unsafe { ptr::read(&this.alloc) };
|
||||||
|
(result, alloc)
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts a raw pointer previously created by [`into_raw`] back into `Weak<T>` in the provided
|
/// Converts a raw pointer previously created by [`into_raw`] back into `Weak<T>` in the provided
|
||||||
/// allocator.
|
/// allocator.
|
||||||
///
|
///
|
||||||
|
Loading…
Reference in New Issue
Block a user