devela/sys/mem/ptr/
namespace.rs

1// devela::sys::mem::ptr::namespace
2//
3//! Defines the [`Ptr`] namespace.
4//
5// WAIT: [intra-doc links to pointers](https://github.com/rust-lang/rust/issues/80896)
6
7#[allow(unused_imports, reason = "unsafe feature-gated")]
8use crate::_core::ptr::{
9    copy, copy_nonoverlapping, drop_in_place, read, read_unaligned, read_volatile, replace, swap,
10    swap_nonoverlapping, write, write_bytes, write_unaligned, write_volatile,
11};
12use crate::{
13    iif, Hasher,
14    _core::ptr::{
15        addr_eq, dangling, dangling_mut, eq, from_mut, from_ref, hash, null, null_mut,
16        slice_from_raw_parts, slice_from_raw_parts_mut, with_exposed_provenance,
17        with_exposed_provenance_mut, without_provenance, without_provenance_mut,
18    },
19};
20
21#[doc = crate::TAG_NAMESPACE!()]
22/// Pointer-related operations.
23///
24/// See also [`Mem`][crate::Mem], [`Slice`][crate::Slice].
25pub struct Ptr;
26
27/// # Safe methods
28impl Ptr {
29    /// The size of a pointer in bits, for the current platform.
30    pub const BITS: usize = usize::BITS as usize;
31    /// The size of a pointer in bytes, for the current platform.
32    pub const BYTES: usize = size_of::<usize>();
33
34    /// True if the system's architecture is little-endian.
35    pub const LITTLE_ENDIAN: bool = cfg!(target_endian = "little");
36    /// True if the system's architecture is big-endian.
37    pub const BIG_ENDIAN: bool = cfg!(target_endian = "big");
38
39    /// Compares raw pointer addresses for equality, ignoring any metadata in fat pointers.
40    ///
41    /// See `core::ptr::`[`addr_eq`].
42    ///
43    /// For functions you can use `core::ptr::`[`fn_addr_eq`][core::ptr::fn_addr_eq] directly.
44    #[must_use]
45    pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool {
46        addr_eq(p, q)
47    }
48
49    // WAIT: `fn_ptr_trait`: FnPtr requires nightly. Until then can't name FnPtr.
50    // https://github.com/rust-lang/rust/issues/129322#issuecomment-2418860738
51    // /// Compares the *addresses* of the two function pointers for equality.
52    // ///
53    // /// See `core::ptr::`[`fn_addr_eq`].
54    // #[must_use]
55    // pub fn fn_addr_eq<T: ::core::marker::FnPtr, U: ::core::marker::FnPtr>(f: T, g: U) -> bool {
56    //     fn_addr_eq(p, q)
57    // }
58
59    /// Compares raw pointers for equality.
60    ///
61    /// See `core::ptr::`[`eq`].
62    #[must_use]
63    pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
64        eq(a, b)
65    }
66
67    /// Creates a new pointer that is dangling, but non-null and well-aligned.
68    ///
69    /// See `core::ptr::`[`dangling`].
70    #[must_use]
71    pub const fn dangling<T>() -> *const T {
72        dangling()
73    }
74    /// Creates a new pointer that is dangling, but non-null and well-aligned.
75    ///
76    /// See `core::ptr::`[`dangling_mut`].
77    #[must_use]
78    pub const fn dangling_mut<T>() -> *mut T {
79        dangling_mut()
80    }
81
82    /// Returns `true` if it's probable the given `address` is in the stack, for a
83    /// given `stack_size`.
84    ///
85    /// # Stack size
86    /// - <https://doc.rust-lang.org/std/thread/#stack-size>.
87    ///
88    /// The default stack size is platform-dependent and subject to change.
89    /// Currently, it is 2 MiB on all Tier-1 platforms.
90    /// Note that the stack size of the main thread is *not* determined by Rust.
91    ///
92    /// If the address is close to a stack variable address it might be stack allocated.
93    ///
94    /// # Example
95    /// ```
96    /// # use devela::Ptr;
97    /// const STACK_SIZE: usize = 2 << 20; // assume a 2 MB stack size
98    ///
99    /// let in_stack: [i32; 10] = [0; 10];
100    /// let in_heap = vec![0; 10];
101    ///
102    /// assert_eq!(true, Ptr::in_stack(in_stack.as_ptr(), STACK_SIZE));
103    /// assert_eq!(false, Ptr::in_stack(in_heap.as_ptr(), STACK_SIZE));
104    /// ```
105    #[cfg(not(miri))] // The addresses in Miri are not real addresses
106    #[must_use]
107    pub fn in_stack<T>(address: *const T, stack_size: usize) -> bool {
108        let local_var = 0;
109        let local_addr = &local_var as *const _ as usize;
110        let obj_addr = address as *const _ as usize;
111        let addr_diff = iif![local_addr > obj_addr; local_addr - obj_addr; obj_addr - local_addr];
112        addr_diff < stack_size
113    }
114
115    /// Convert an exclusive reference to a raw pointer.
116    ///
117    /// See `core::ptr::`[`from_mut`].
118    #[must_use]
119    pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
120        from_mut(r)
121    }
122
123    /// Convert a shared reference to a raw pointer.
124    ///
125    /// See `core::ptr::`[`from_ref`].
126    #[must_use]
127    pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
128        from_ref(r)
129    }
130
131    /// Hash a raw pointer.
132    ///
133    /// See `core::ptr::`[`hash`].
134    pub fn hash<T: ?Sized, S: Hasher>(hashee: *const T, into: &mut S) {
135        hash(hashee, into);
136    }
137
138    /// Creates a null raw pointer.
139    ///
140    /// See `core::ptr::`[`null`]
141    /// and `<ptr>::`[`is_null`][pointer#method.is_null].
142    // WAIT: [ptr_metadata](https://github.com/rust-lang/rust/issues/81513)
143    // T: Thin + ?Sized https://doc.rust-lang.org/core/ptr/traitalias.Thin.html
144    #[must_use]
145    pub const fn null<T>() -> *const T {
146        null()
147    }
148
149    /// Creates a null mutable raw pointer.
150    ///
151    /// See `core::ptr::`[`null_mut`].
152    // WAIT: [ptr_metadata](https://github.com/rust-lang/rust/issues/81513)
153    // T: Thin + ?Sized https://doc.rust-lang.org/core/ptr/traitalias.Thin.html
154    #[must_use]
155    pub const fn null_mut<T>() -> *mut T {
156        null_mut()
157    }
158
159    /// Returns the ratio of a `usize` in respect to `other_size`.
160    ///
161    /// For example: the ratio will be `(1, 1)` if both sizes are equal, `(2, 1)`
162    /// if the pointer size is double the other size, and `(1, 2)` if is is half
163    /// the other byte size.
164    ///
165    /// # Examples
166    /// ```
167    /// use devela::Ptr;
168    ///
169    /// assert_eq![Ptr::size_ratio(0), [1, 0]];
170    /// assert_eq![Ptr::size_ratio(size_of::<usize>()), [1, 1]];
171    /// assert_eq![Ptr::size_ratio(size_of::<&str>()), [1, 2]];
172    /// assert_eq![Ptr::size_ratio(size_of::<String>()), [1, 3]];
173    ///
174    /// #[cfg(target_pointer_width = "64")]
175    /// assert_eq![Ptr::size_ratio(size_of::<char>()), [2,1]];
176    /// ```
177    ///
178    /// Note that when `other_size == 0` it returns `(1, 0)` which is an invalid ratio.
179    #[must_use]
180    pub const fn size_ratio(other_size: usize) -> [usize; 2] {
181        const fn gcd(m: usize, n: usize) -> usize {
182            iif![n == 0; m; gcd(n, m % n)]
183        }
184        let g = gcd(size_of::<usize>(), other_size);
185        [size_of::<usize>() / g, other_size / g]
186    }
187
188    /// Forms a raw slice from a pointer and a length.
189    ///
190    /// See `core::ptr::`[`slice_from_raw_parts`], and also
191    /// `Slice::`[`from_raw_parts`][crate::Slice::from_raw_parts].
192    #[must_use]
193    pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
194        slice_from_raw_parts(data, len)
195    }
196
197    /// Forms a mutable raw slice from a mutable pointer and a length.
198    ///
199    /// See `core::ptr::`[`slice_from_raw_parts_mut`], and also
200    /// `Slice::`[`from_raw_parts_mut`][crate::Slice::from_raw_parts_mut].
201    #[must_use]
202    pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
203        slice_from_raw_parts_mut(data, len)
204    }
205
206    /// Converts an address back to a pointer,
207    /// picking up some previously ‘exposed’ *provenance*.
208    ///
209    /// See `core::ptr::`[`with_exposed_provenance`]
210    /// and `<ptr>::`[`expose_provenance`][pointer#method.expose_provenance].
211    #[must_use]
212    pub fn with_exposed_provenance<T>(addr: usize) -> *const T {
213        with_exposed_provenance(addr)
214    }
215    /// Converts an address back to a mutable pointer,
216    /// picking up some previously ‘exposed’ *provenance*.
217    ///
218    /// See `core::ptr::`[`with_exposed_provenance_mut`]
219    /// and `<ptr>::`[`expose_provenance`][pointer#method.expose_provenance].
220    #[must_use]
221    pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
222        with_exposed_provenance_mut(addr)
223    }
224
225    /// Creates a pointer with the given address and no *provenance*.
226    ///
227    /// See `core::ptr::`[`without_provenance`]
228    /// `<ptr>::`[`with_addr`][pointer#method.with_addr],
229    /// and `<ptr>::`[`map_addr`][pointer#method.map_addr].
230    #[must_use]
231    pub fn without_provenance<T>(addr: usize) -> *const T {
232        without_provenance(addr)
233    }
234    /// Creates a pointer with the given address and no *provenance*.
235    ///
236    /// See `core::ptr::`[`without_provenance_mut`]
237    /// `<ptr>::`[`with_addr`][pointer#method.with_addr],
238    /// and `<ptr>::`[`map_addr`][pointer#method.map_addr].
239    #[must_use]
240    pub fn without_provenance_mut<T>(addr: usize) -> *mut T {
241        without_provenance_mut(addr)
242    }
243}
244
245/// # Unsafe methods
246///
247/// ## Features
248/// They depend on enabling any `unsafe*` feature, and not enabling `safe_mem`.
249#[rustfmt::skip]
250#[cfg_attr(feature = "nightly_doc", doc(cfg(unsafe··)))]
251#[cfg(all(not(feature = "safe_mem"), unsafe··))]
252impl Ptr {
253    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. Can overlap.
254    ///
255    /// # Safety
256    /// See `core::ptr::`[`copy`].
257    pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
258        // SAFETY: Caller must uphold the safety contract.
259        unsafe { copy(src, dst, count); }
260    }
261
262    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. Must *not* overlap.
263    ///
264    /// # Safety
265    /// See `core::ptr::`[`copy_nonoverlapping`].
266    pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
267        // SAFETY: Caller must uphold the safety contract.
268        unsafe { copy_nonoverlapping(src, dst, count); }
269    }
270
271    /// Executes the destructor (if any) of the pointed-to value.
272    ///
273    /// # Safety
274    /// See `core::ptr::`[`drop_in_place`].
275    pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
276        // SAFETY: Caller must uphold the safety contract.
277        unsafe { drop_in_place(to_drop); }
278    }
279
280    /// Reads the value from src without moving it.
281    ///
282    /// # Safety
283    /// See `core::ptr::`[`read`].
284    #[must_use]
285    pub const unsafe fn read<T>(src: *const T) -> T {
286        // SAFETY: Caller must uphold the safety contract.
287        unsafe { read(src) }
288    }
289
290    /// Reads the value from src without moving it.
291    ///
292    /// # Safety
293    /// See `core::ptr::`[`read_unaligned`].
294    #[must_use]
295    pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
296        // SAFETY: Caller must uphold the safety contract.
297        unsafe { read_unaligned(src) }
298    }
299
300    /// Performs a volatile read of the value from src without moving it.
301    ///
302    /// # Safety
303    /// See `core::ptr::`[`read_volatile`].
304    #[must_use]
305    pub unsafe fn read_volatile<T>(src: *const T) -> T {
306        // SAFETY: Caller must uphold the safety contract.
307        unsafe { read_volatile(src) }
308    }
309
310    /// Moves src into the pointed dst, returning the previous dst value.
311    ///
312    /// # Safety
313    /// See `core::ptr::`[`replace`].
314    #[must_use]
315    pub unsafe fn replace<T>(dst: *mut T, src: T) -> T {
316        // SAFETY: Caller must uphold the safety contract.
317        unsafe { replace(dst, src) }
318    }
319
320    /// Swaps the values at two mutable locations of the same type, without deinitializing.
321    ///
322    /// # Safety
323    /// See `core::ptr::`[`swap`].
324    pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
325        // SAFETY: Caller must uphold the safety contract.
326        unsafe { swap(x, y); }
327    }
328
329    /// Swaps the two regions of memory beginning at `x` and `y`. Must *not* overlap.
330    ///
331    /// # Safety
332    /// See `core::ptr::`[`swap_nonoverlapping`].
333    pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
334        // SAFETY: Caller must uphold the safety contract.
335        unsafe { swap_nonoverlapping(x, y, count) };
336    }
337
338    /// Overwrites a memory location with `src` without reading or dropping.
339    ///
340    /// # Safety
341    /// See `core::ptr::`[`write`][fn@write].
342    pub unsafe fn write<T>(dst: *mut T, src: T) {
343        // SAFETY: Caller must uphold the safety contract.
344        unsafe { write(dst, src); };
345    }
346
347    /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to `val`.
348    ///
349    /// # Safety
350    /// See `core::ptr::`[`write_bytes`].
351    pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
352        // SAFETY: Caller must uphold the safety contract.
353        unsafe { write_bytes(dst, val, count); };
354    }
355
356    /// Overwrites a memory location with `src` without reading or dropping.
357    ///
358    /// # Safety
359    /// See `core::ptr::`[`write_unaligned`].
360    pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
361        // SAFETY: Caller must uphold the safety contract.
362        unsafe { write_unaligned(dst, src); };
363    }
364
365    /// Performs a volatile write of a memory location with `src` without reading or dropping.
366    ///
367    /// # Safety
368    /// See `core::ptr::`[`write_volatile`].
369    pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
370        // SAFETY: Caller must uphold the safety contract.
371        unsafe { write_volatile(dst, src); };
372    }
373}