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}