Skip to content

Commit 5f331c0

Browse files
authored
Rollup merge of rust-lang#74774 - oliver-giersch:set_data_ptr, r=dtolnay
adds [*mut|*const] ptr::set_ptr_value I propose the addition of these two functions to `*mut T` and `*const T`, respectively. The motivation for this is primarily byte-wise pointer arithmetic on (potentially) fat pointers, i.e. for types with a `T: ?Sized` bound. A concrete use-case has been discussed in [this](https://internals.rust-lang.org/t/byte-wise-fat-pointer-arithmetic/12739) thread. TL;DR: Currently, byte-wise pointer arithmetic with potentially fat pointers in not possible in either stable or nightly Rust without making assumptions about the layout of fat pointers, which is currently still an implementation detail and not formally stabilized. This PR adds one function to `*mut T` and `*const T` each, allowing to circumvent this restriction without exposing any internal implementation details. One possible alternative would be to add specific byte-wise pointer arithmetic functions to the two pointer types in addition to the already existing count-wise functions. However, I feel this fairly niche use case does not warrant adding a whole set of new functions like `add_bytes`, `offset_bytes`, `wrapping_offset_bytes`, etc. (times two, one for each pointer type) to `libcore`.
2 parents 63e3442 + 6c81556 commit 5f331c0

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

library/core/src/ptr/const_ptr.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,38 @@ impl<T: ?Sized> *const T {
656656
self.wrapping_offset((count as isize).wrapping_neg())
657657
}
658658

659+
/// Sets the pointer value to `ptr`.
660+
///
661+
/// In case `self` is a (fat) pointer to an unsized type, this operation
662+
/// will only affect the pointer part, whereas for (thin) pointers to
663+
/// sized types, this has the same effect as a simple assignment.
664+
///
665+
/// # Examples
666+
///
667+
/// This function is primarily useful for allowing byte-wise pointer
668+
/// arithmetic on potentially fat pointers:
669+
///
670+
/// ```
671+
/// #![feature(set_ptr_value)]
672+
/// # use core::fmt::Debug;
673+
/// let arr: [i32; 3] = [1, 2, 3];
674+
/// let mut ptr = &arr[0] as *const dyn Debug;
675+
/// let thin = ptr as *const u8;
676+
/// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
677+
/// assert_eq!(unsafe { *(ptr as *const i32) }, 3);
678+
/// ```
679+
#[unstable(feature = "set_ptr_value", issue = "75091")]
680+
#[inline]
681+
pub fn set_ptr_value(mut self, val: *const ()) -> Self {
682+
let thin = &mut self as *mut *const T as *mut *const ();
683+
// SAFETY: In case of a thin pointer, this operations is identical
684+
// to a simple assignment. In case of a fat pointer, with the current
685+
// fat pointer layout implementation, the first field of such a
686+
// pointer is always the data pointer, which is likewise assigned.
687+
unsafe { *thin = val };
688+
self
689+
}
690+
659691
/// Reads the value from `self` without moving it. This leaves the
660692
/// memory in `self` unchanged.
661693
///

library/core/src/ptr/mut_ptr.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,38 @@ impl<T: ?Sized> *mut T {
712712
self.wrapping_offset((count as isize).wrapping_neg())
713713
}
714714

715+
/// Sets the pointer value to `ptr`.
716+
///
717+
/// In case `self` is a (fat) pointer to an unsized type, this operation
718+
/// will only affect the pointer part, whereas for (thin) pointers to
719+
/// sized types, this has the same effect as a simple assignment.
720+
///
721+
/// # Examples
722+
///
723+
/// This function is primarily useful for allowing byte-wise pointer
724+
/// arithmetic on potentially fat pointers:
725+
///
726+
/// ```
727+
/// #![feature(set_ptr_value)]
728+
/// # use core::fmt::Debug;
729+
/// let mut arr: [i32; 3] = [1, 2, 3];
730+
/// let mut ptr = &mut arr[0] as *mut dyn Debug;
731+
/// let thin = ptr as *mut u8;
732+
/// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
733+
/// assert_eq!(unsafe { *(ptr as *mut i32) }, 3);
734+
/// ```
735+
#[unstable(feature = "set_ptr_value", issue = "75091")]
736+
#[inline]
737+
pub fn set_ptr_value(mut self, val: *mut ()) -> Self {
738+
let thin = &mut self as *mut *mut T as *mut *mut ();
739+
// SAFETY: In case of a thin pointer, this operations is identical
740+
// to a simple assignment. In case of a fat pointer, with the current
741+
// fat pointer layout implementation, the first field of such a
742+
// pointer is always the data pointer, which is likewise assigned.
743+
unsafe { *thin = val };
744+
self
745+
}
746+
715747
/// Reads the value from `self` without moving it. This leaves the
716748
/// memory in `self` unchanged.
717749
///

0 commit comments

Comments
 (0)