nstd_sys/core/
ptr.rs

1//! A sized pointer to some arbitrary type.
2use crate::{
3    core::{
4        mem::{nstd_core_mem_copy, nstd_core_mem_is_aligned},
5        optional::{gen_optional, NSTDOptional},
6    },
7    NSTDAny, NSTDAnyMut, NSTDUInt, NSTD_INT_MAX,
8};
9use nstdapi::nstdapi;
10
11/// A sized immutable pointer to some arbitrary type.
12#[nstdapi]
13#[derive(Clone, Copy)]
14pub struct NSTDPtr {
15    /// A raw pointer to the data.
16    raw: NSTDAny,
17    /// The size of the object being pointed to.
18    size: NSTDUInt,
19    /// The alignment of the object being pointed to.
20    align: NSTDUInt,
21}
22gen_optional!(NSTDOptionalPtr, NSTDPtr);
23
24/// Creates a new instance of `NSTDPtr`.
25///
26/// # Parameters:
27///
28/// - `NSTDAny obj` - The object to point to.
29///
30/// - `NSTDUInt size` - The number of bytes that `obj`'s type occupies.
31///
32/// - `NSTDUInt align` - The alignment of the object that `obj` points to.
33///
34/// # Returns
35///
36/// `NSTDOptionalPtr ptr` - A new instance of `NSTDPtr` that points to `obj` on success, or
37/// an uninitialized "none" variant if `obj` is null or unaligned or if `size` is greater than
38/// `NSTDInt`'s max value.
39///
40/// # Panics
41///
42/// This operation will panic if `align` is not a power of two.
43#[inline]
44#[nstdapi]
45pub fn nstd_core_ptr_new(obj: NSTDAny, size: NSTDUInt, align: NSTDUInt) -> NSTDOptionalPtr {
46    match !obj.is_null() && nstd_core_mem_is_aligned(obj, align) && size <= NSTD_INT_MAX {
47        true => NSTDOptional::Some(NSTDPtr {
48            raw: obj,
49            size,
50            align,
51        }),
52        false => NSTDOptional::None,
53    }
54}
55
56/// Creates a new instance of `NSTDPtr` without checking if `obj` is null.
57///
58/// # Parameters:
59///
60/// - `NSTDAny obj` - The object to point to.
61///
62/// - `NSTDUInt size` - The number of bytes that `obj`'s type occupies.
63///
64/// - `NSTDUInt align` - The alignment of the object that `obj` points to.
65///
66/// # Returns
67///
68/// `NSTDPtr ptr` - A new instance of `NSTDPtr` that points to `obj`.
69///
70/// # Safety
71///
72/// - `obj` must be non-null.
73///
74/// - `obj` must be aligned to `align`.
75///
76/// - `align` must be a nonzero power of two.
77///
78/// - `size` must not be greater than `NSTDInt`'s max value.
79#[inline]
80#[nstdapi]
81pub const unsafe fn nstd_core_ptr_new_unchecked(
82    obj: NSTDAny,
83    size: NSTDUInt,
84    align: NSTDUInt,
85) -> NSTDPtr {
86    NSTDPtr {
87        raw: obj,
88        size,
89        align,
90    }
91}
92
93/// Returns the size of the object being pointed to.
94///
95/// # Parameters:
96///
97/// - `const NSTDPtr *ptr` - The pointer.
98///
99/// # Returns
100///
101/// `NSTDUInt size` - The size of the object pointed to by `ptr`.
102///
103/// # Examples
104///
105/// ```
106/// use core::ptr::addr_of;
107/// use nstd_sys::core::ptr::{nstd_core_ptr_new, nstd_core_ptr_size};
108///
109/// unsafe {
110///     const SIZE: usize = core::mem::size_of::<isize>();
111///     const ALIGN: usize = core::mem::align_of::<isize>();
112///     let x = 33isize;
113///     let ptr = nstd_core_ptr_new(addr_of!(x).cast(), SIZE, ALIGN).unwrap();
114///     assert!(nstd_core_ptr_size(&ptr) == SIZE);
115/// }
116/// ```
117#[inline]
118#[nstdapi]
119pub const fn nstd_core_ptr_size(ptr: &NSTDPtr) -> NSTDUInt {
120    ptr.size
121}
122
123/// Returns the alignment of the object being pointed to.
124///
125/// # Parameters:
126///
127/// - `const NSTDPtr *ptr` - The pointer.
128///
129/// # Returns
130///
131/// `NSTDUInt align` - The alignment of the object pointed to by `ptr`.
132///
133/// # Examples
134///
135/// ```
136/// use core::ptr::addr_of;
137/// use nstd_sys::core::ptr::{nstd_core_ptr_align, nstd_core_ptr_new};
138///
139/// unsafe {
140///     const SIZE: usize = core::mem::size_of::<[u8; 32]>();
141///     const ALIGN: usize = core::mem::align_of::<[u8; 32]>();
142///     let x = [33u8; 32];
143///     let ptr = nstd_core_ptr_new(addr_of!(x).cast(), SIZE, ALIGN).unwrap();
144///     assert!(nstd_core_ptr_align(&ptr) == ALIGN);
145/// }
146/// ```
147#[inline]
148#[nstdapi]
149pub const fn nstd_core_ptr_align(ptr: &NSTDPtr) -> NSTDUInt {
150    ptr.align
151}
152
153/// Returns a raw immutable pointer to the object pointed to by `ptr`.
154///
155/// # Parameters:
156///
157/// - `const NSTDPtr *ptr` - The higher level pointer.
158///
159/// # Returns
160///
161/// `NSTDAny raw` - A raw pointer to the object.
162///
163/// # Examples
164///
165/// ```
166/// use core::ptr::addr_of;
167/// use nstd_sys::core::ptr::{nstd_core_ptr_get, nstd_core_ptr_new};
168///
169/// unsafe {
170///     const SIZE: usize = core::mem::size_of::<u32>();
171///     const ALIGN: usize = core::mem::align_of::<u32>();
172///     let x = 45u32;
173///     let ptr = nstd_core_ptr_new(addr_of!(x).cast(), SIZE, ALIGN).unwrap();
174///     assert!(*nstd_core_ptr_get(&ptr).cast::<u32>() == x);
175/// }
176/// ```
177#[inline]
178#[nstdapi]
179pub const fn nstd_core_ptr_get(ptr: &NSTDPtr) -> NSTDAny {
180    ptr.raw
181}
182
183/// A sized pointer to some arbitrary type.
184#[nstdapi]
185pub struct NSTDPtrMut {
186    /// A raw pointer to the data.
187    raw: NSTDAnyMut,
188    /// The size of the object being pointed to.
189    size: NSTDUInt,
190    /// The alignment of the object being pointed to.
191    align: NSTDUInt,
192}
193gen_optional!(NSTDOptionalPtrMut, NSTDPtrMut);
194
195/// Creates a new instance of `NSTDPtrMut`.
196///
197/// # Parameters:
198///
199/// - `NSTDAnyMut obj` - The object to point to.
200///
201/// - `NSTDUInt size` - The number of bytes that `obj`'s type occupies.
202///
203/// - `NSTDUInt align` - The alignment of the object that `obj` points to.
204///
205/// # Returns
206///
207/// `NSTDOptionalPtrMut ptr` - A new instance of `NSTDPtrMut` that points to `obj` on success, or
208/// an uninitialized "none" variant if `obj` is null or unaligned or if `size` is greater than
209/// `NSTDInt`'s max value.
210///
211/// # Panics
212///
213/// This operation will panic if `align` is not a power of two.
214#[inline]
215#[nstdapi]
216pub fn nstd_core_ptr_mut_new(
217    obj: NSTDAnyMut,
218    size: NSTDUInt,
219    align: NSTDUInt,
220) -> NSTDOptionalPtrMut {
221    match !obj.is_null() && nstd_core_mem_is_aligned(obj, align) && size <= NSTD_INT_MAX {
222        true => NSTDOptional::Some(NSTDPtrMut {
223            raw: obj,
224            size,
225            align,
226        }),
227        false => NSTDOptional::None,
228    }
229}
230
231/// Creates a new instance of `NSTDPtrMut` without checking if `obj` is null.
232///
233/// # Parameters:
234///
235/// - `NSTDAnyMut obj` - The object to point to.
236///
237/// - `NSTDUInt size` - The number of bytes that `obj`'s type occupies.
238///
239/// - `NSTDUInt align` - The alignment of the object that `obj` points to.
240///
241/// # Returns
242///
243/// `NSTDPtrMut ptr` - A new instance of `NSTDPtrMut` that points to `obj`.
244///
245/// # Safety
246///
247/// - `obj` must be non-null.
248///
249/// - `obj` must be aligned to `align`.
250///
251/// - `align` must be a nonzero power of two.
252///
253/// - `size` must not be greater than `NSTDInt`'s max value.
254#[inline]
255#[nstdapi]
256pub const unsafe fn nstd_core_ptr_mut_new_unchecked(
257    obj: NSTDAnyMut,
258    size: NSTDUInt,
259    align: NSTDUInt,
260) -> NSTDPtrMut {
261    NSTDPtrMut {
262        raw: obj,
263        size,
264        align,
265    }
266}
267
268/// Creates an immutable version of a mutable pointer.
269///
270/// # Parameters:
271///
272/// - `const NSTDPtrMut *ptr` - The mutable pointer.
273///
274/// # Returns
275///
276/// `NSTDPtr ptr_const` - The immutable copy of `ptr`.
277#[inline]
278#[nstdapi]
279pub const fn nstd_core_ptr_mut_as_const(ptr: &NSTDPtrMut) -> NSTDPtr {
280    // SAFETY: `ptr.raw` is never null, `ptr.size` is never greater than `NSTDInt`'s max value.
281    unsafe { nstd_core_ptr_new_unchecked(ptr.raw, ptr.size, ptr.align) }
282}
283
284/// Returns the size of the object being pointed to.
285///
286/// # Parameters:
287///
288/// - `const NSTDPtrMut *ptr` - The pointer.
289///
290/// # Returns
291///
292/// `NSTDUInt size` - The size of the object pointed to by `ptr`.
293///
294/// # Examples
295///
296/// ```
297/// use core::ptr::addr_of_mut;
298/// use nstd_sys::core::ptr::{nstd_core_ptr_mut_new, nstd_core_ptr_mut_size};
299///
300/// unsafe {
301///     const SIZE: usize = core::mem::size_of::<isize>();
302///     const ALIGN: usize = core::mem::align_of::<isize>();
303///     let mut x = 33isize;
304///     let ptr = nstd_core_ptr_mut_new(addr_of_mut!(x).cast(), SIZE, ALIGN).unwrap();
305///     assert!(nstd_core_ptr_mut_size(&ptr) == SIZE);
306/// }
307/// ```
308#[inline]
309#[nstdapi]
310pub const fn nstd_core_ptr_mut_size(ptr: &NSTDPtrMut) -> NSTDUInt {
311    ptr.size
312}
313
314/// Returns the alignment of the object being pointed to.
315///
316/// # Parameters:
317///
318/// - `const NSTDPtrMut *ptr` - The pointer.
319///
320/// # Returns
321///
322/// `NSTDUInt align` - The alignment of the object pointed to by `ptr`.
323///
324/// # Examples
325///
326/// ```
327/// use core::ptr::addr_of_mut;
328/// use nstd_sys::core::ptr::{nstd_core_ptr_mut_align, nstd_core_ptr_mut_new};
329///
330/// unsafe {
331///     const SIZE: usize = core::mem::size_of::<[u8; 32]>();
332///     const ALIGN: usize = core::mem::align_of::<[u8; 32]>();
333///     let mut x = [33u8; 32];
334///     let ptr = nstd_core_ptr_mut_new(addr_of_mut!(x).cast(), SIZE, ALIGN).unwrap();
335///     assert!(nstd_core_ptr_mut_align(&ptr) == ALIGN);
336/// }
337/// ```
338#[inline]
339#[nstdapi]
340pub const fn nstd_core_ptr_mut_align(ptr: &NSTDPtrMut) -> NSTDUInt {
341    ptr.align
342}
343
344/// Returns a raw pointer to the object pointed to by `ptr`.
345///
346/// # Parameters:
347///
348/// - `NSTDPtrMut *ptr` - The higher level pointer.
349///
350/// # Returns
351///
352/// `NSTDAnyMut raw` - A raw pointer to the object.
353///
354/// # Examples
355///
356/// ```
357/// use core::ptr::addr_of_mut;
358/// use nstd_sys::core::ptr::{nstd_core_ptr_mut_get, nstd_core_ptr_mut_new};
359///
360/// unsafe {
361///     const SIZE: usize = core::mem::size_of::<u32>();
362///     const ALIGN: usize = core::mem::align_of::<u32>();
363///     let mut x = 8u32;
364///     let mut ptr = nstd_core_ptr_mut_new(addr_of_mut!(x).cast(), SIZE, ALIGN).unwrap();
365///     let x_ptr = nstd_core_ptr_mut_get(&mut ptr).cast();
366///     *x_ptr *= 2;
367///     assert!(x == *x_ptr);
368/// }
369/// ```
370#[inline]
371#[nstdapi]
372pub fn nstd_core_ptr_mut_get(ptr: &mut NSTDPtrMut) -> NSTDAnyMut {
373    ptr.raw
374}
375
376/// Returns a raw immutable pointer to the object pointed to by `ptr`.
377///
378/// # Parameters:
379///
380/// - `const NSTDPtrMut *ptr` - The higher level pointer.
381///
382/// # Returns
383///
384/// `NSTDAny raw` - A raw pointer to the object.
385///
386/// # Examples
387///
388/// ```
389/// use core::ptr::addr_of_mut;
390/// use nstd_sys::core::ptr::{nstd_core_ptr_mut_get_const, nstd_core_ptr_mut_new};
391///
392/// unsafe {
393///     const SIZE: usize = core::mem::size_of::<u32>();
394///     const ALIGN: usize = core::mem::align_of::<u32>();
395///     let mut x = 45u32;
396///     let ptr = nstd_core_ptr_mut_new(addr_of_mut!(x).cast(), SIZE, ALIGN).unwrap();
397///     assert!(*nstd_core_ptr_mut_get_const(&ptr).cast::<u32>() == x);
398/// }
399/// ```
400#[inline]
401#[nstdapi]
402pub const fn nstd_core_ptr_mut_get_const(ptr: &NSTDPtrMut) -> NSTDAny {
403    ptr.raw
404}
405
406/// Writes data from `obj` to `ptr`. The number of bytes written is determined by `ptr.size`.
407///
408/// # Note
409///
410/// It is up to the user of this function to ensure that `obj`'s memory buffer is at least
411/// `ptr.size` bytes wide to avoid writing garbage data to this pointer.
412///
413/// # Parameters:
414///
415/// - `NSTDPtrMut *ptr` - The pointer to write to.
416///
417/// - `NSTDAny obj` - A pointer to the object to write to `ptr`.
418///
419/// # Safety
420///
421/// This operation is highly unsafe because there is no way of knowing if `obj`'s data is valid.
422///
423/// # Examples
424///
425/// ```
426/// use core::ptr::{addr_of, addr_of_mut};
427/// use nstd_sys::core::ptr::{
428///     nstd_core_ptr_mut_get_const, nstd_core_ptr_mut_new, nstd_core_ptr_mut_write,
429/// };
430///
431/// unsafe {
432///     const SIZE: usize = core::mem::size_of::<i64>();
433///     const ALIGN: usize = core::mem::align_of::<i64>();
434///     let mut x = -69i64;
435///     let mut ptr = nstd_core_ptr_mut_new(addr_of_mut!(x).cast(), SIZE, ALIGN).unwrap();
436///     let y = 420i64;
437///     nstd_core_ptr_mut_write(&mut ptr, addr_of!(y).cast());
438///     assert!(x == y);
439/// }
440/// ```
441#[inline]
442#[nstdapi]
443pub unsafe fn nstd_core_ptr_mut_write(ptr: &mut NSTDPtrMut, obj: NSTDAny) {
444    nstd_core_mem_copy(ptr.raw.cast(), obj.cast(), ptr.size);
445}