1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Provides useful utilities for working with raw pointers.
use crate::{NSTDAny, NSTDAnyMut, NSTDBool, NSTDUInt};
use nstdapi::nstdapi;

/// The default alignment suitable for any scalar type.
///
/// Corresponds to `alignof(max_align_t)`.
/// The C/C++ standards specify that this value should be at least 8 or 16, I'm going with 16 for
/// safety but of course this is platform dependent so if you (the reader) know of a platform that
/// this value is smaller (or larger for that matter) on, please submit an issue/pull request.
pub(crate) const MAX_ALIGN: usize = 16;

/// Checks if `align` is a power of 2.
#[inline]
const fn is_power_of_two(align: NSTDUInt) -> NSTDBool {
    (align != 0) && ((align & (align - 1)) == 0)
}

/// Creates a new dangling immutable pointer with valid alignment for any scalar type.
///
/// # Returns
///
/// `NSTDAny dangling` - The new dangling raw pointer.
///
/// # Example
///
/// ```
/// use nstd_sys::core::{ptr::raw::nstd_core_ptr_raw_dangling, slice::nstd_core_slice_new};
///
/// let slice = nstd_core_slice_new(nstd_core_ptr_raw_dangling(), 1, 0).unwrap();
/// ```
#[inline]
#[nstdapi]
pub const fn nstd_core_ptr_raw_dangling() -> NSTDAny {
    MAX_ALIGN as NSTDAny
}

/// Creates a new dangling mutable pointer with valid alignment for any scalar type.
///
/// # Returns
///
/// `NSTDAnyMut dangling` - The new dangling raw pointer.
///
/// # Example
///
/// ```
/// use nstd_sys::core::{ptr::raw::nstd_core_ptr_raw_dangling_mut, slice::nstd_core_slice_mut_new};
///
/// let slice = nstd_core_slice_mut_new(nstd_core_ptr_raw_dangling_mut(), 1, 0).unwrap();
/// ```
#[inline]
#[nstdapi]
pub const fn nstd_core_ptr_raw_dangling_mut() -> NSTDAnyMut {
    MAX_ALIGN as NSTDAnyMut
}

/// Returns a pointer that is properly aligned to `align` based on the offset `ptr`.
///
/// # Parameters:
///
/// - `NSTDAny ptr` - The pointer to align.
///
/// - `NSTDUInt align` - The alignment requirement. This must be a power of two.
///
/// # Returns
///
/// `NSTDAny aligned` - The properly aligned pointer.
///
/// # Panics
///
/// This operation will panic if `align` is not a power of two or overflow occurs.
///
/// # Safety
///
/// Both `ptr` and the resulting pointer must be either in bounds or one byte past the end of the
/// same allocated object.
///
/// # Example
///
/// ```
/// use nstd_sys::core::ptr::raw::{nstd_core_ptr_raw_align, nstd_core_ptr_raw_is_aligned};
///
/// unsafe {
///     let ptr = 2 as _;
///     let aligned = nstd_core_ptr_raw_align(ptr, 16);
///     assert!(nstd_core_ptr_raw_is_aligned(aligned, 16));
/// }
/// ```
#[nstdapi]
pub unsafe fn nstd_core_ptr_raw_align(ptr: NSTDAny, align: NSTDUInt) -> NSTDAny {
    assert!(is_power_of_two(align));
    ((ptr as NSTDUInt)
        .checked_add(align - 1)
        .expect("pointer arithmetic should not overflow")
        & !(align - 1)) as NSTDAny
}

/// Returns a pointer that is properly aligned to `align` based on the offset `ptr`.
///
/// # Parameters:
///
/// - `NSTDAnyMut ptr` - The pointer to align.
///
/// - `NSTDUInt align` - The alignment requirement. This must be a power of two.
///
/// # Returns
///
/// `NSTDAnyMut aligned` - The properly aligned pointer.
///
/// # Panics
///
/// This operation will panic if `align` is not a power of two or overflow occurs.
///
/// # Safety
///
/// Both `ptr` and the resulting pointer must be either in bounds or one byte past the end of the
/// same allocated object.
///
/// # Example
///
/// ```
/// use nstd_sys::core::ptr::raw::{nstd_core_ptr_raw_align_mut, nstd_core_ptr_raw_is_aligned};
///
/// unsafe {
///     let ptr = 2 as _;
///     let aligned = nstd_core_ptr_raw_align_mut(ptr, 16);
///     assert!(nstd_core_ptr_raw_is_aligned(aligned, 16));
/// }
/// ```
#[inline]
#[nstdapi]
pub unsafe fn nstd_core_ptr_raw_align_mut(ptr: NSTDAnyMut, align: NSTDUInt) -> NSTDAnyMut {
    nstd_core_ptr_raw_align(ptr, align) as NSTDAnyMut
}

/// Checks if `ptr` is aligned to `align`.
///
/// # Parameters:
///
/// - `NSTDAny ptr` - The pointer to check.
///
/// - `NSTDUInt align` - The alignment to check for. This must be a power of two.
///
/// # Returns
///
/// `NSTDBool is_aligned` - `NSTD_TRUE` if the pointer is aligned to `align`.
///
/// # Panics
///
/// This operation will panic if `align` is not a power of two.
///
/// # Example
///
/// ```
/// use nstd_sys::{
///     core::ptr::raw::{nstd_core_ptr_raw_align, nstd_core_ptr_raw_is_aligned},
///     NSTDAny,
/// };
///
/// unsafe {
///     let mut a = 1usize as NSTDAny;
///     a = nstd_core_ptr_raw_align(a, 8);
///     assert!(!nstd_core_ptr_raw_is_aligned(a, 16));
///     a = nstd_core_ptr_raw_align(a, 16);
///     assert!(nstd_core_ptr_raw_is_aligned(a, 16));
/// }
/// ```
#[inline]
#[nstdapi]
pub fn nstd_core_ptr_raw_is_aligned(ptr: NSTDAny, align: NSTDUInt) -> NSTDBool {
    assert!(is_power_of_two(align));
    ptr as NSTDUInt & (align - 1) == 0
}