konst/
ptr.rs

1//! Const equivalents of raw pointer and [`NonNull`](core::ptr::NonNull) methods.
2
3use core::ptr::NonNull;
4
5/// Const equivalent of `&*raw_pointer`.
6///
7///
8/// # Safety
9///
10/// This function has the safety requirements of
11/// [`<*const>::as_ref`](https://doc.rust-lang.org/1.55.0/std/primitive.pointer.html#safety),
12/// in addition to requiring that `ptr` is not null.
13///
14/// # Example
15///
16/// ```rust
17/// use konst::ptr;
18///
19/// const F: &u8 = unsafe{ ptr::deref("foo".as_ptr()) };
20/// assert_eq!(F, &b'f');
21///
22/// const BAR: &[u8; 3] = unsafe{ ptr::deref("bar".as_ptr().cast::<[u8; 3]>()) };
23/// assert_eq!(BAR, b"bar");
24///
25///
26/// ```
27#[cfg(feature = "rust_1_56")]
28#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_56")))]
29pub const unsafe fn deref<'a, T: ?Sized>(ptr: *const T) -> &'a T {
30    core::mem::transmute(ptr)
31}
32
33/// Const equivalent of `&mut *raw_pointer`.
34///
35///
36/// # Safety
37///
38/// This function has the safety requirements of
39/// [`<*const>::as_mut`](https://doc.rust-lang.org/1.55.0/std/primitive.pointer.html#safety-13),
40/// in addition to requiring that `ptr` is not null.
41///
42/// # Example
43///
44/// ```rust
45/// # #![feature(const_mut_refs)]
46/// use konst::ptr;
47///
48/// assert_eq!(ARR, [33, 35, 38]);
49///
50/// const ARR: [u8; 3] = unsafe {
51///     let mut arr = [3, 5, 8];
52///     mutate(&mut arr[0]);
53///     mutate(&mut arr[1]);
54///     mutate(&mut arr[2]);
55///     arr
56/// };
57///
58/// const unsafe fn mutate(x: *mut u8) {
59///     let mutt = ptr::deref_mut(x);
60///     *mutt += 30;
61/// }
62///
63/// ```
64#[cfg(feature = "mut_refs")]
65#[cfg_attr(feature = "docsrs", doc(cfg(feature = "mut_refs")))]
66pub const unsafe fn deref_mut<'a, T: ?Sized>(ptr: *mut T) -> &'a mut T {
67    core::mem::transmute(ptr)
68}
69
70/// Const equivalent of
71/// [`<*const>::as_ref`](https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref)
72///
73/// # Safety
74///
75/// This function has the same safety requirements as
76/// [`<*const>::as_ref`](https://doc.rust-lang.org/1.55.0/std/primitive.pointer.html#safety)
77///
78/// # Example
79///
80/// ```rust
81/// use konst::ptr;
82///
83/// use core::ptr::null;
84///
85/// const NONE: Option<&u8> = unsafe{ ptr::as_ref(null()) };
86/// const SOME: Option<&u8> = unsafe{ ptr::as_ref(&100) };
87///
88/// assert_eq!(NONE, None);
89/// assert_eq!(SOME, Some(&100));
90///
91///
92/// ```
93#[cfg(feature = "rust_1_56")]
94#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_56")))]
95pub const unsafe fn as_ref<'a, T: ?Sized>(ptr: *const T) -> Option<&'a T> {
96    core::mem::transmute(ptr)
97}
98
99/// Const equivalent of
100/// [`<*const>::as_mut`](https://doc.rust-lang.org/std/primitive.pointer.html#method.as_mut)
101///
102/// # Safety
103///
104/// This function has the same safety requirements as
105/// [`<*const>::as_mut`](https://doc.rust-lang.org/1.55.0/std/primitive.pointer.html#safety-13).
106///
107/// # Example
108///
109/// ```rust
110/// # #![feature(const_mut_refs)]
111/// use konst::ptr;
112///
113/// assert_eq!(ARR, [83, 91, 104]);
114///
115/// const ARR: [u8; 3] = unsafe {
116///     let mut arr = [13, 21, 34];
117///     mutate(&mut arr[0]);
118///     mutate(&mut arr[1]);
119///     mutate(&mut arr[2]);
120///     mutate(std::ptr::null_mut()); // no-op
121///     arr
122/// };
123///
124/// const unsafe fn mutate(x: *mut u8) {
125///     if let Some(mutt) = ptr::as_mut(x) {
126///         *mutt += 70;
127///     }
128/// }
129/// ```
130#[cfg(feature = "mut_refs")]
131#[cfg_attr(feature = "docsrs", doc(cfg(feature = "mut_refs")))]
132pub const unsafe fn as_mut<'a, T: ?Sized>(ptr: *mut T) -> Option<&'a mut T> {
133    core::mem::transmute(ptr)
134}
135
136/// Const equivalent of
137/// [`<*const>::is_null`](https://doc.rust-lang.org/std/primitive.pointer.html#method.is_null)
138///
139/// # Example
140///
141/// ```rust
142/// use konst::ptr;
143///
144/// use core::ptr::null;
145///
146/// const NULL_IS_NULL: bool = unsafe{ ptr::is_null(null::<u8>()) };
147/// const REFF_IS_NULL: bool = unsafe{ ptr::is_null(&100) };
148///
149/// assert_eq!(NULL_IS_NULL, true);
150/// assert_eq!(REFF_IS_NULL, false);
151///
152///
153/// ```
154#[cfg(feature = "rust_1_56")]
155#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_56")))]
156pub const fn is_null<'a, T: ?Sized>(ptr: *const T) -> bool {
157    unsafe {
158        matches!(
159            core::mem::transmute::<*const T, Option<NonNull<T>>>(ptr),
160            None
161        )
162    }
163}
164
165/// Const equivalents of [`NonNull`](core::ptr::NonNull) methods.
166pub mod nonnull {
167    use core::ptr::NonNull;
168
169    /// Const equivalent of [`NonNull::new`](core::ptr::NonNull::new).
170    ///
171    /// # Example
172    ///
173    /// ```rust
174    /// use konst::ptr::nonnull;
175    ///
176    /// use core::ptr::{NonNull, null_mut};
177    ///
178    /// const NONE: Option<NonNull<u8>> = unsafe{ nonnull::new(null_mut()) };
179    /// const SOME: Option<NonNull<u8>> = unsafe{ nonnull::new(&100 as *const _ as *mut _) };
180    ///
181    /// assert!(NONE.is_none());
182    /// assert_eq!(SOME.map(|x|unsafe{*x.as_ptr()}), Some(100));
183    ///
184    ///
185    /// ```
186    #[cfg(feature = "rust_1_56")]
187    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_56")))]
188    pub const fn new<T: ?Sized>(ptr: *mut T) -> Option<NonNull<T>> {
189        unsafe { core::mem::transmute(ptr) }
190    }
191
192    /// Const equivalent of [`NonNull::as_ref`](core::ptr::NonNull::as_ref).
193    ///
194    /// # Safety
195    ///
196    /// This has [the same safety requirements as `NonNull::as_ref`
197    /// ](https://doc.rust-lang.org/1.55.0/core/ptr/struct.NonNull.html#safety-3)
198    ///
199    /// # Example
200    ///
201    /// ```rust
202    /// use konst::ptr::nonnull;
203    ///
204    /// use core::{
205    ///     ptr::NonNull,
206    ///     marker::PhantomData,
207    /// };
208    ///
209    /// const A: NonNull<u8> = nonnull::from_ref(&3);
210    /// const A_REF: &u8 = unsafe{ nonnull::as_ref(A) };
211    /// assert_eq!(A_REF, &3);
212    ///
213    /// const B: NonNull<str> = nonnull::from_ref("hello");
214    /// const B_REF: &str = unsafe{ nonnull::as_ref(B) };
215    /// assert_eq!(B_REF, "hello");
216    ///
217    /// ```
218    ///
219    #[cfg(feature = "rust_1_56")]
220    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_56")))]
221    pub const unsafe fn as_ref<'a, T: ?Sized>(ptr: NonNull<T>) -> &'a T {
222        core::mem::transmute(ptr)
223    }
224
225    /// Const equivalent of [`NonNull::as_mut`](core::ptr::NonNull::as_mut).
226    ///
227    /// # Safety
228    ///
229    /// This has [the same safety requirements as `NonNull::as_mut`
230    /// ](https://doc.rust-lang.org/1.55.0/std/ptr/struct.NonNull.html#safety-4)
231    ///
232    /// # Example
233    ///
234    /// ```rust
235    /// # #![feature(const_mut_refs)]
236    /// use konst::ptr::nonnull;
237    ///
238    /// use core::ptr::NonNull;
239    ///
240    /// assert_eq!(TUP, (13, 15, 18));
241    ///
242    /// const TUP: (u8, u8, u8) = unsafe {
243    ///     let mut tuple = (3, 5, 8);
244    ///     mutate(nonnull::from_mut(&mut tuple.0));
245    ///     mutate(nonnull::from_mut(&mut tuple.1));
246    ///     mutate(nonnull::from_mut(&mut tuple.2));
247    ///     tuple
248    /// };
249    ///
250    /// const unsafe fn mutate(x: NonNull<u8>) {
251    ///     *nonnull::as_mut(x) += 10;
252    /// }
253    ///
254    /// ```
255    ///
256    #[cfg(feature = "mut_refs")]
257    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "mut_refs")))]
258    pub const unsafe fn as_mut<'a, T: ?Sized>(ptr: NonNull<T>) -> &'a mut T {
259        core::mem::transmute(ptr)
260    }
261
262    /// Const equivalent of
263    /// [`<NonNull<T> as From<&T>>::from`
264    /// ](https://doc.rust-lang.org/1.55.0/std/ptr/struct.NonNull.html#impl-From%3C%26%27_%20T%3E)
265    ///
266    /// # Example
267    ///
268    /// ```rust
269    /// use konst::ptr::nonnull;
270    ///
271    /// use core::ptr::NonNull;
272    ///
273    /// const H: NonNull<str> = unsafe{ nonnull::from_ref("hello") };
274    /// const W: NonNull<str> = unsafe{ nonnull::from_ref("world") };
275    ///
276    /// unsafe{
277    ///     assert_eq!(H.as_ref(), "hello");
278    ///     assert_eq!(W.as_ref(), "world");
279    /// }
280    /// ```
281    pub const fn from_ref<T: ?Sized>(reff: &T) -> NonNull<T> {
282        unsafe { NonNull::new_unchecked(reff as *const _ as *mut _) }
283    }
284
285    /// Const equivalent of
286    /// [`<NonNull<T> as From<&mut T>>::from`
287    /// ](https://doc.rust-lang.org/1.55.0/std/ptr/struct.NonNull.html#impl-From%3C%26%27_%20mut%20T%3E)
288    ///
289    /// # Example
290    ///
291    /// ```rust
292    /// # #![feature(const_mut_refs)]
293    /// use konst::ptr::nonnull as nn;
294    ///
295    /// use core::ptr::NonNull;
296    ///
297    /// assert_eq!(ARR, (5, 8, 3));
298    ///
299    /// const ARR: (u8, u8, u8) = unsafe {
300    ///     let mut tup = (3, 5, 8);
301    ///     swap(nn::from_mut(&mut tup.0), nn::from_mut(&mut tup.1));
302    ///     swap(nn::from_mut(&mut tup.1), nn::from_mut(&mut tup.2));
303    ///     tup
304    /// };
305    ///
306    /// const unsafe fn swap(x: NonNull<u8>, y: NonNull<u8>) {
307    ///     let xm = nn::as_mut(x);
308    ///     let ym = nn::as_mut(y);
309    ///     let tmp = *xm;
310    ///     *xm = *ym;
311    ///     *ym = tmp;
312    /// }
313    ///
314    /// ```
315    ///
316    #[cfg(feature = "mut_refs")]
317    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "mut_refs")))]
318    pub const fn from_mut<T: ?Sized>(mutt: &mut T) -> NonNull<T> {
319        unsafe { NonNull::new_unchecked(mutt) }
320    }
321}