diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 3065169e5e2cb..881472c925d53 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -895,7 +895,7 @@ impl Rc { // Reverse the offset to find the original RcBox. let rc_ptr = - unsafe { (ptr as *mut RcBox).set_ptr_value((ptr as *mut u8).offset(-offset)) }; + unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut RcBox) }; unsafe { Self::from_ptr(rc_ptr) } } @@ -1338,7 +1338,7 @@ impl Rc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| (ptr as *mut RcBox).set_ptr_value(mem), + |mem| mem.with_metadata_of(ptr as *mut RcBox), ) } } @@ -2263,7 +2263,7 @@ impl Weak { let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. // SAFETY: the pointer originated from a Weak, so this offset is safe. - unsafe { (ptr as *mut RcBox).set_ptr_value((ptr as *mut u8).offset(-offset)) } + unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut RcBox) } }; // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 2140c3f168d1c..e302f874bfdd0 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -895,7 +895,8 @@ impl Arc { let offset = data_offset(ptr); // Reverse the offset to find the original ArcInner. - let arc_ptr = (ptr as *mut ArcInner).set_ptr_value((ptr as *mut u8).offset(-offset)); + let arc_ptr = + (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut ArcInner); Self::from_ptr(arc_ptr) } @@ -1182,7 +1183,7 @@ impl Arc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| (ptr as *mut ArcInner).set_ptr_value(mem) as *mut ArcInner, + |mem| mem.with_metadata_of(ptr as *mut ArcInner), ) } } @@ -1887,7 +1888,7 @@ impl Weak { let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. // SAFETY: the pointer originated from a Weak, so this offset is safe. - unsafe { (ptr as *mut ArcInner).set_ptr_value((ptr as *mut u8).offset(-offset)) } + unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut ArcInner) } }; // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 753220669831f..b06e94a7a689e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -48,6 +48,50 @@ impl *const T { self as _ } + /// Use the pointer value in a new pointer of another type. + /// + /// In case `val` is a (fat) pointer to an unsized type, this operation + /// will ignore the pointer part, whereas for (thin) pointers to sized + /// types, this has the same effect as a simple cast. + /// + /// The resulting pointer will have provenance of `self`, i.e., for a fat + /// pointer, this operation is semantically the same as creating a new + /// fat pointer with the data pointer value of `self` but the metadata of + /// `val`. + /// + /// # Examples + /// + /// This function is primarily useful for allowing byte-wise pointer + /// arithmetic on potentially fat pointers: + /// + /// ``` + /// #![feature(set_ptr_value)] + /// # use core::fmt::Debug; + /// let arr: [i32; 3] = [1, 2, 3]; + /// let mut ptr = arr.as_ptr() as *const dyn Debug; + /// let thin = ptr as *const u8; + /// unsafe { + /// ptr = thin.add(8).with_metadata_of(ptr); + /// # assert_eq!(*(ptr as *const i32), 3); + /// println!("{:?}", &*ptr); // will print "3" + /// } + /// ``` + #[unstable(feature = "set_ptr_value", issue = "75091")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline] + pub fn with_metadata_of(self, mut val: *const U) -> *const U + where + U: ?Sized, + { + let target = &mut val as *mut *const U as *mut *const u8; + // SAFETY: In case of a thin pointer, this operations is identical + // to a simple assignment. In case of a fat pointer, with the current + // fat pointer layout implementation, the first field of such a + // pointer is always the data pointer, which is likewise assigned. + unsafe { *target = self as *const u8 }; + val + } + /// Changes constness without changing the type. /// /// This is a bit safer than `as` because it wouldn't silently change the type if the code is @@ -764,47 +808,6 @@ impl *const T { self.wrapping_offset((count as isize).wrapping_neg()) } - /// Sets the pointer value to `ptr`. - /// - /// In case `self` is a (fat) pointer to an unsized type, this operation - /// will only affect the pointer part, whereas for (thin) pointers to - /// sized types, this has the same effect as a simple assignment. - /// - /// The resulting pointer will have provenance of `val`, i.e., for a fat - /// pointer, this operation is semantically the same as creating a new - /// fat pointer with the data pointer value of `val` but the metadata of - /// `self`. - /// - /// # Examples - /// - /// This function is primarily useful for allowing byte-wise pointer - /// arithmetic on potentially fat pointers: - /// - /// ``` - /// #![feature(set_ptr_value)] - /// # use core::fmt::Debug; - /// let arr: [i32; 3] = [1, 2, 3]; - /// let mut ptr = arr.as_ptr() as *const dyn Debug; - /// let thin = ptr as *const u8; - /// unsafe { - /// ptr = ptr.set_ptr_value(thin.add(8)); - /// # assert_eq!(*(ptr as *const i32), 3); - /// println!("{:?}", &*ptr); // will print "3" - /// } - /// ``` - #[unstable(feature = "set_ptr_value", issue = "75091")] - #[must_use = "returns a new pointer rather than modifying its argument"] - #[inline] - pub fn set_ptr_value(mut self, val: *const u8) -> Self { - let thin = &mut self as *mut *const T as *mut *const u8; - // SAFETY: In case of a thin pointer, this operations is identical - // to a simple assignment. In case of a fat pointer, with the current - // fat pointer layout implementation, the first field of such a - // pointer is always the data pointer, which is likewise assigned. - unsafe { *thin = val }; - self - } - /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 861412703d3c6..63bb22d6e0dd4 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -47,6 +47,50 @@ impl *mut T { self as _ } + /// Use the pointer value in a new pointer of another type. + /// + /// In case `val` is a (fat) pointer to an unsized type, this operation + /// will ignore the pointer part, whereas for (thin) pointers to sized + /// types, this has the same effect as a simple cast. + /// + /// The resulting pointer will have provenance of `self`, i.e., for a fat + /// pointer, this operation is semantically the same as creating a new + /// fat pointer with the data pointer value of `self` but the metadata of + /// `val`. + /// + /// # Examples + /// + /// This function is primarily useful for allowing byte-wise pointer + /// arithmetic on potentially fat pointers: + /// + /// ``` + /// #![feature(set_ptr_value)] + /// # use core::fmt::Debug; + /// let mut arr: [i32; 3] = [1, 2, 3]; + /// let mut ptr = arr.as_mut_ptr() as *mut dyn Debug; + /// let thin = ptr as *mut u8; + /// unsafe { + /// ptr = thin.add(8).with_metadata_of(ptr); + /// # assert_eq!(*(ptr as *mut i32), 3); + /// println!("{:?}", &*ptr); // will print "3" + /// } + /// ``` + #[unstable(feature = "set_ptr_value", issue = "75091")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline] + pub fn with_metadata_of(self, mut val: *mut U) -> *mut U + where + U: ?Sized, + { + let target = &mut val as *mut *mut U as *mut *mut u8; + // SAFETY: In case of a thin pointer, this operations is identical + // to a simple assignment. In case of a fat pointer, with the current + // fat pointer layout implementation, the first field of such a + // pointer is always the data pointer, which is likewise assigned. + unsafe { *target = self as *mut u8 }; + val + } + /// Changes constness without changing the type. /// /// This is a bit safer than `as` because it wouldn't silently change the type if the code is @@ -878,47 +922,6 @@ impl *mut T { self.wrapping_offset((count as isize).wrapping_neg()) } - /// Sets the pointer value to `ptr`. - /// - /// In case `self` is a (fat) pointer to an unsized type, this operation - /// will only affect the pointer part, whereas for (thin) pointers to - /// sized types, this has the same effect as a simple assignment. - /// - /// The resulting pointer will have provenance of `val`, i.e., for a fat - /// pointer, this operation is semantically the same as creating a new - /// fat pointer with the data pointer value of `val` but the metadata of - /// `self`. - /// - /// # Examples - /// - /// This function is primarily useful for allowing byte-wise pointer - /// arithmetic on potentially fat pointers: - /// - /// ``` - /// #![feature(set_ptr_value)] - /// # use core::fmt::Debug; - /// let mut arr: [i32; 3] = [1, 2, 3]; - /// let mut ptr = arr.as_mut_ptr() as *mut dyn Debug; - /// let thin = ptr as *mut u8; - /// unsafe { - /// ptr = ptr.set_ptr_value(thin.add(8)); - /// # assert_eq!(*(ptr as *mut i32), 3); - /// println!("{:?}", &*ptr); // will print "3" - /// } - /// ``` - #[unstable(feature = "set_ptr_value", issue = "75091")] - #[must_use = "returns a new pointer rather than modifying its argument"] - #[inline] - pub fn set_ptr_value(mut self, val: *mut u8) -> Self { - let thin = &mut self as *mut *mut T as *mut *mut u8; - // SAFETY: In case of a thin pointer, this operations is identical - // to a simple assignment. In case of a fat pointer, with the current - // fat pointer layout implementation, the first field of such a - // pointer is always the data pointer, which is likewise assigned. - unsafe { *thin = val }; - self - } - /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. ///