rune_alloc/
ptr.rs

1//! This module contains (hopefully sound) re-implementations of unstable
2//! `core::ptr` APIs.
3
4pub(crate) use self::unique::Unique;
5mod unique;
6
7use core::mem;
8pub(crate) use core::ptr::NonNull;
9
10// Stable re-exports.
11pub(crate) use core::ptr::{
12    addr_of, addr_of_mut, copy, copy_nonoverlapping, drop_in_place, read, slice_from_raw_parts_mut,
13    write,
14};
15
16pub(crate) const unsafe fn nonnull_add<T>(this: NonNull<T>, delta: usize) -> NonNull<T>
17where
18    T: Sized,
19{
20    // SAFETY: We require that the delta stays in-bounds of the object, and
21    // thus it cannot become null, as that would require wrapping the
22    // address space, which no legal objects are allowed to do.
23    // And the caller promised the `delta` is sound to add.
24    let pointer = this.as_ptr();
25    unsafe { NonNull::new_unchecked(pointer.add(delta)) }
26}
27
28pub(crate) const unsafe fn nonnull_sub<T>(this: NonNull<T>, delta: usize) -> NonNull<T>
29where
30    T: Sized,
31{
32    // SAFETY: We require that the delta stays in-bounds of the object, and
33    // thus it cannot become null, as that would require wrapping the
34    // address space, which no legal objects are allowed to do.
35    // And the caller promised the `delta` is sound to add.
36    let pointer = this.as_ptr();
37    unsafe { NonNull::new_unchecked(pointer.sub(delta)) }
38}
39
40#[inline(always)]
41#[allow(clippy::useless_transmute)]
42pub const fn invalid<T>(addr: usize) -> *const T {
43    // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
44    // We use transmute rather than a cast so tools like Miri can tell that this
45    // is *not* the same as from_exposed_addr.
46    // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
47    // pointer).
48    unsafe { mem::transmute(addr) }
49}
50
51#[inline(always)]
52#[allow(clippy::useless_transmute)]
53pub const fn invalid_mut<T>(addr: usize) -> *mut T {
54    // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
55    // We use transmute rather than a cast so tools like Miri can tell that this
56    // is *not* the same as from_exposed_addr.
57    // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
58    // pointer).
59    unsafe { mem::transmute(addr) }
60}
61
62cfg_if! {
63    if #[cfg(rune_nightly)] {
64        #[inline(always)]
65        pub(crate) unsafe fn sub_ptr<T>(from: *const T, to: *const T) -> usize {
66            from.offset_from_unsigned(to)
67        }
68    } else {
69        #[inline(always)]
70        pub(crate) unsafe fn sub_ptr<T>(from: *const T, to: *const T) -> usize {
71            const {
72                let pointee_size = mem::size_of::<T>();
73                assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
74            }
75
76            debug_assert!(addr(from) >= addr(to));
77            addr(from).wrapping_sub(addr(to)).saturating_div(mem::size_of::<T>())
78        }
79    }
80}
81
82cfg_if! {
83    if #[cfg(rune_nightly)] {
84        #[inline(always)]
85        pub(crate) fn addr<T>(from: *const T) -> usize {
86            from.addr()
87        }
88    } else {
89        #[inline(always)]
90        pub(crate) fn addr<T>(from: *const T) -> usize {
91            from as usize
92        }
93    }
94}
95
96cfg_if! {
97    if #[cfg(rune_nightly)] {
98        #[inline(always)]
99        pub(crate) fn slice_len<T>(from: *const [T]) -> usize {
100            from.len()
101        }
102    } else {
103        #[inline(always)]
104        pub(crate) fn slice_len<T>(from: *const [T]) -> usize {
105            // SAFETY: This is *a bit* tricky, but the raw pointer contains the
106            // length and *should* be safe to dereference like this. However,
107            // walking through the dereferenced `[T]` is not necessarily
108            // correct.
109            unsafe { (*from).len() }
110        }
111    }
112}