Skip to content

Commit f9d328d

Browse files
committed
sync::Weak::{as,from,into}_raw
Methods on the Weak to access it as raw pointer to the data.
1 parent 16e356e commit f9d328d

File tree

1 file changed

+158
-6
lines changed

1 file changed

+158
-6
lines changed

src/liballoc/sync.rs

Lines changed: 158 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use core::borrow;
1313
use core::fmt;
1414
use core::cmp::{self, Ordering};
1515
use core::intrinsics::abort;
16-
use core::mem::{self, align_of_val, size_of_val};
16+
use core::mem::{self, align_of, align_of_val, size_of_val};
1717
use core::ops::{Deref, Receiver, CoerceUnsized, DispatchFromDyn};
1818
use core::pin::Pin;
1919
use core::ptr::{self, NonNull};
@@ -397,11 +397,7 @@ impl<T: ?Sized> Arc<T> {
397397
/// ```
398398
#[stable(feature = "rc_raw", since = "1.17.0")]
399399
pub unsafe fn from_raw(ptr: *const T) -> Self {
400-
// Align the unsized value to the end of the ArcInner.
401-
// Because it is ?Sized, it will always be the last field in memory.
402-
let align = align_of_val(&*ptr);
403-
let layout = Layout::new::<ArcInner<()>>();
404-
let offset = (layout.size() + layout.padding_needed_for(align)) as isize;
400+
let offset = data_offset(ptr);
405401

406402
// Reverse the offset to find the original ArcInner.
407403
let fake_ptr = ptr as *mut ArcInner<T>;
@@ -1071,6 +1067,144 @@ impl<T> Weak<T> {
10711067
ptr: NonNull::new(usize::MAX as *mut ArcInner<T>).expect("MAX is not 0"),
10721068
}
10731069
}
1070+
1071+
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
1072+
///
1073+
/// It is up to the caller to ensure that the object is still alive when accessing it through
1074+
/// the pointer.
1075+
///
1076+
/// The pointer may be [`null`] or be dangling in case the object has already been destroyed.
1077+
///
1078+
/// # Examples
1079+
///
1080+
/// ```
1081+
/// #![feature(weak_into_raw)]
1082+
///
1083+
/// use std::sync::{Arc, Weak};
1084+
/// use std::ptr;
1085+
///
1086+
/// let strong = Arc::new(42);
1087+
/// let weak = Arc::downgrade(&strong);
1088+
/// // Both point to the same object
1089+
/// assert!(ptr::eq(&*strong, Weak::as_raw(&weak)));
1090+
/// // The strong here keeps it alive, so we can still access the object.
1091+
/// assert_eq!(42, unsafe { *Weak::as_raw(&weak) });
1092+
///
1093+
/// drop(strong);
1094+
/// // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to
1095+
/// // undefined behaviour.
1096+
/// // assert_eq!(42, unsafe { *Weak::as_raw(&weak) });
1097+
/// ```
1098+
///
1099+
/// [`null`]: ../../std/ptr/fn.null.html
1100+
#[unstable(feature = "weak_into_raw", issue = "60728")]
1101+
pub fn as_raw(this: &Self) -> *const T {
1102+
match this.inner() {
1103+
None => ptr::null(),
1104+
Some(inner) => {
1105+
let offset = data_offset_sized::<T>();
1106+
let ptr = inner as *const ArcInner<T>;
1107+
// Note: while the pointer we create may already point to dropped value, the
1108+
// allocation still lives (it must hold the weak point as long as we are alive).
1109+
// Therefore, the offset is OK to do, it won't get out of the allocation.
1110+
let ptr = unsafe { (ptr as *const u8).offset(offset) };
1111+
ptr as *const T
1112+
}
1113+
}
1114+
}
1115+
1116+
/// Consumes the `Weak<T>` and turns it into a raw pointer.
1117+
///
1118+
/// This converts the weak pointer into a raw pointer, preserving the original weak count. It
1119+
/// can be turned back into the `Weak<T>` with [`from_raw`].
1120+
///
1121+
/// The same restrictions of accessing the target of the pointer as with
1122+
/// [`as_raw`] apply.
1123+
///
1124+
/// # Examples
1125+
///
1126+
/// ```
1127+
/// #![feature(weak_into_raw)]
1128+
///
1129+
/// use std::sync::{Arc, Weak};
1130+
///
1131+
/// let strong = Arc::new(42);
1132+
/// let weak = Arc::downgrade(&strong);
1133+
/// let raw = Weak::into_raw(weak);
1134+
///
1135+
/// assert_eq!(1, Arc::weak_count(&strong));
1136+
/// assert_eq!(42, unsafe { *raw });
1137+
///
1138+
/// drop(unsafe { Weak::from_raw(raw) });
1139+
/// assert_eq!(0, Arc::weak_count(&strong));
1140+
/// ```
1141+
///
1142+
/// [`from_raw`]: struct.Weak.html#method.from_raw
1143+
/// [`as_raw`]: struct.Weak.html#method.as_raw
1144+
#[unstable(feature = "weak_into_raw", issue = "60728")]
1145+
pub fn into_raw(this: Self) -> *const T {
1146+
let result = Self::as_raw(&this);
1147+
mem::forget(this);
1148+
result
1149+
}
1150+
1151+
/// Converts a raw pointer previously created by [`into_raw`] back into
1152+
/// `Weak<T>`.
1153+
///
1154+
/// This can be used to safely get a strong reference (by calling [`upgrade`]
1155+
/// later) or to deallocate the weak count by dropping the `Weak<T>`.
1156+
///
1157+
/// It takes ownership of one weak count. In case a [`null`] is passed, a dangling [`Weak`] is
1158+
/// returned.
1159+
///
1160+
/// # Safety
1161+
///
1162+
/// The pointer must represent one valid weak count. In other words, it must point to `T` which
1163+
/// is or *was* managed by an [`Arc`] and the weak count of that [`Arc`] must not have reached
1164+
/// 0. It is allowed for the strong count to be 0.
1165+
///
1166+
/// # Examples
1167+
///
1168+
/// ```
1169+
/// #![feature(weak_into_raw)]
1170+
///
1171+
/// use std::sync::{Arc, Weak};
1172+
///
1173+
/// let strong = Arc::new(42);
1174+
///
1175+
/// let raw_1 = Weak::into_raw(Arc::downgrade(&strong));
1176+
/// let raw_2 = Weak::into_raw(Arc::downgrade(&strong));
1177+
///
1178+
/// assert_eq!(2, Arc::weak_count(&strong));
1179+
///
1180+
/// assert_eq!(42, *Weak::upgrade(&unsafe { Weak::from_raw(raw_1) }).unwrap());
1181+
/// assert_eq!(1, Arc::weak_count(&strong));
1182+
///
1183+
/// drop(strong);
1184+
///
1185+
/// // Decrement the last weak count.
1186+
/// assert!(Weak::upgrade(&unsafe { Weak::from_raw(raw_2) }).is_none());
1187+
/// ```
1188+
///
1189+
/// [`null`]: ../../std/ptr/fn.null.html
1190+
/// [`into_raw`]: struct.Weak.html#method.into_raw
1191+
/// [`upgrade`]: struct.Weak.html#method.upgrade
1192+
/// [`Weak`]: struct.Weak.html
1193+
/// [`Arc`]: struct.Arc.html
1194+
#[unstable(feature = "weak_into_raw", issue = "60728")]
1195+
pub unsafe fn from_raw(ptr: *const T) -> Self {
1196+
if ptr.is_null() {
1197+
Self::new()
1198+
} else {
1199+
// See Arc::from_raw for details
1200+
let offset = data_offset(ptr);
1201+
let fake_ptr = ptr as *mut ArcInner<T>;
1202+
let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
1203+
Weak {
1204+
ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw"),
1205+
}
1206+
}
1207+
}
10741208
}
10751209

10761210
impl<T: ?Sized> Weak<T> {
@@ -2150,3 +2284,21 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
21502284

21512285
#[stable(feature = "pin", since = "1.33.0")]
21522286
impl<T: ?Sized> Unpin for Arc<T> { }
2287+
2288+
/// Computes the offset of the data field within ArcInner.
2289+
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
2290+
// Align the unsized value to the end of the ArcInner.
2291+
// Because it is ?Sized, it will always be the last field in memory.
2292+
let align = align_of_val(&*ptr);
2293+
let layout = Layout::new::<ArcInner<()>>();
2294+
(layout.size() + layout.padding_needed_for(align)) as isize
2295+
}
2296+
2297+
/// Computes the offset of the data field within ArcInner.
2298+
///
2299+
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`.
2300+
fn data_offset_sized<T>() -> isize {
2301+
let align = align_of::<T>();
2302+
let layout = Layout::new::<ArcInner<()>>();
2303+
(layout.size() + layout.padding_needed_for(align)) as isize
2304+
}

0 commit comments

Comments
 (0)