Implement `Arc`/`Rc` raw pointer conversions for `?Sized`
* Add `T: ?Sized` bound to {`Arc`,`Rc`}::{`from_raw`,`into_raw`}
This commit is contained in:
parent
b965d55a32
commit
1cbb2b3a88
|
@ -22,7 +22,7 @@ use core::borrow;
|
|||
use core::fmt;
|
||||
use core::cmp::Ordering;
|
||||
use core::intrinsics::abort;
|
||||
use core::mem::{self, size_of_val, uninitialized};
|
||||
use core::mem::{self, align_of_val, size_of_val, uninitialized};
|
||||
use core::ops::Deref;
|
||||
use core::ops::CoerceUnsized;
|
||||
use core::ptr::{self, Shared};
|
||||
|
@ -324,7 +324,9 @@ impl<T> Arc<T> {
|
|||
Ok(elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Consumes the `Arc`, returning the wrapped pointer.
|
||||
///
|
||||
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
|
||||
|
@ -378,16 +380,21 @@ impl<T> Arc<T> {
|
|||
/// ```
|
||||
#[stable(feature = "rc_raw", since = "1.17.0")]
|
||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||
// To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the
|
||||
// `data` field from the pointer.
|
||||
let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner<T>, data));
|
||||
// Align the unsized value to the end of the ArcInner.
|
||||
// Because it is ?Sized, it will always be the last field in memory.
|
||||
let align = align_of_val(&*ptr);
|
||||
let layout = Layout::new::<ArcInner<()>>();
|
||||
let offset = (layout.size() + layout.padding_needed_for(align)) as isize;
|
||||
|
||||
// Reverse the offset to find the original ArcInner.
|
||||
let fake_ptr = ptr as *mut ArcInner<T>;
|
||||
let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
|
||||
|
||||
Arc {
|
||||
ptr: Shared::new_unchecked(ptr as *mut u8 as *mut _),
|
||||
ptr: Shared::new_unchecked(arc_ptr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Creates a new [`Weak`][weak] pointer to this value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
|
@ -1491,6 +1498,28 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_from_raw_unsized() {
|
||||
use std::fmt::Display;
|
||||
use std::string::ToString;
|
||||
|
||||
let arc: Arc<str> = Arc::from("foo");
|
||||
|
||||
let ptr = Arc::into_raw(arc.clone());
|
||||
let arc2 = unsafe { Arc::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }, "foo");
|
||||
assert_eq!(arc, arc2);
|
||||
|
||||
let arc: Arc<Display> = Arc::new(123);
|
||||
|
||||
let ptr = Arc::into_raw(arc.clone());
|
||||
let arc2 = unsafe { Arc::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }.to_string(), "123");
|
||||
assert_eq!(arc2.to_string(), "123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cowarc_clone_make_mut() {
|
||||
let mut cow0 = Arc::new(75);
|
||||
|
|
|
@ -105,22 +105,3 @@ macro_rules! vec {
|
|||
macro_rules! format {
|
||||
($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*)))
|
||||
}
|
||||
|
||||
// Private macro to get the offset of a struct field in bytes from the address of the struct.
|
||||
macro_rules! offset_of {
|
||||
($container:path, $field:ident) => {{
|
||||
// Make sure the field actually exists. This line ensures that a compile-time error is
|
||||
// generated if $field is accessed through a Deref impl.
|
||||
let $container { $field : _, .. };
|
||||
|
||||
// Create an (invalid) instance of the container and calculate the offset to its
|
||||
// field. Using a null pointer might be UB if `&(*(0 as *const T)).field` is interpreted to
|
||||
// be nullptr deref.
|
||||
let invalid: $container = ::core::mem::uninitialized();
|
||||
let offset = &invalid.$field as *const _ as usize - &invalid as *const _ as usize;
|
||||
|
||||
// Do not run destructors on the made up invalid instance.
|
||||
::core::mem::forget(invalid);
|
||||
offset as isize
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ use core::hash::{Hash, Hasher};
|
|||
use core::intrinsics::abort;
|
||||
use core::marker;
|
||||
use core::marker::Unsize;
|
||||
use core::mem::{self, forget, size_of_val, uninitialized};
|
||||
use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
|
||||
use core::ops::Deref;
|
||||
use core::ops::CoerceUnsized;
|
||||
use core::ptr::{self, Shared};
|
||||
|
@ -358,7 +358,9 @@ impl<T> Rc<T> {
|
|||
Err(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Consumes the `Rc`, returning the wrapped pointer.
|
||||
///
|
||||
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
|
||||
|
@ -412,17 +414,21 @@ impl<T> Rc<T> {
|
|||
/// ```
|
||||
#[stable(feature = "rc_raw", since = "1.17.0")]
|
||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||
// To find the corresponding pointer to the `RcBox` we need to subtract the offset of the
|
||||
// `value` field from the pointer.
|
||||
// Align the unsized value to the end of the RcBox.
|
||||
// Because it is ?Sized, it will always be the last field in memory.
|
||||
let align = align_of_val(&*ptr);
|
||||
let layout = Layout::new::<RcBox<()>>();
|
||||
let offset = (layout.size() + layout.padding_needed_for(align)) as isize;
|
||||
|
||||
// Reverse the offset to find the original RcBox.
|
||||
let fake_ptr = ptr as *mut RcBox<T>;
|
||||
let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
|
||||
|
||||
let ptr = (ptr as *const u8).offset(-offset_of!(RcBox<T>, value));
|
||||
Rc {
|
||||
ptr: Shared::new_unchecked(ptr as *mut u8 as *mut _)
|
||||
ptr: Shared::new_unchecked(rc_ptr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Creates a new [`Weak`][weak] pointer to this value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
|
@ -1481,6 +1487,28 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_from_raw_unsized() {
|
||||
use std::fmt::Display;
|
||||
use std::string::ToString;
|
||||
|
||||
let rc: Rc<str> = Rc::from("foo");
|
||||
|
||||
let ptr = Rc::into_raw(rc.clone());
|
||||
let rc2 = unsafe { Rc::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }, "foo");
|
||||
assert_eq!(rc, rc2);
|
||||
|
||||
let rc: Rc<Display> = Rc::new(123);
|
||||
|
||||
let ptr = Rc::into_raw(rc.clone());
|
||||
let rc2 = unsafe { Rc::from_raw(ptr) };
|
||||
|
||||
assert_eq!(unsafe { &*ptr }.to_string(), "123");
|
||||
assert_eq!(rc2.to_string(), "123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut x = Rc::new(3);
|
||||
|
|
Loading…
Reference in New Issue