const_util/mem.rs
1//! Functions related to [`core::mem`] and [`core::ptr`]
2
3use core::{
4 mem::ManuallyDrop,
5 ptr::{self, NonNull},
6};
7
8/// Gets a reference to the contents of a `ManuallyDrop`.
9///
10/// This function is a const version of the `Deref` implementation of `ManuallyDrop`.
11///
12/// # Example
13/// ```
14/// use const_util::mem::man_drop_ref;
15/// use core::mem::ManuallyDrop;
16/// assert_eq!(man_drop_ref(&ManuallyDrop::new(1)), &1);
17/// ```
18pub const fn man_drop_ref<T>(man: &ManuallyDrop<T>) -> &T {
19 // SAFETY: repr(transparent)
20 unsafe { &*ptr::from_ref(man).cast() }
21}
22/// Gets a reference to the contents of a `ManuallyDrop`.
23///
24/// This function is a const version of the `DerefMut` implementation of `ManuallyDrop`.
25///
26/// # Example
27/// ```
28/// use const_util::mem::man_drop_mut;
29/// use core::mem::ManuallyDrop;
30/// assert_eq!(man_drop_mut(&mut ManuallyDrop::new(1)), &mut 1);
31/// ```
32pub const fn man_drop_mut<T>(man: &mut ManuallyDrop<T>) -> &mut T {
33 // SAFETY: repr(transparent)
34 unsafe { &mut *ptr::from_mut(man).cast() }
35}
36
37/// Converts `&T` or `&mut T` into `NonNull<T>`.
38///
39/// This function is a const version of the `From<&T>` and `From<&mut T>` implementations of
40/// `NonNull<T>`. The returned pointer will have the same mutability as the argument.
41///
42/// This function is useful to avoid accidentally converting a mutable reference to an immutable
43/// one when copying around code.
44///
45/// # Example
46/// ```
47/// use const_util::mem::nonnull_from;
48/// use core::ptr::NonNull;
49///
50/// let mut x = 1;
51/// assert_eq!(
52/// nonnull_from(&x),
53/// NonNull::from(&x),
54/// );
55/// assert_eq!(
56/// nonnull_from(&mut x),
57/// NonNull::from(&mut x),
58/// );
59/// unsafe { nonnull_from(&mut x).write(2) };
60/// assert_eq!(unsafe { nonnull_from(&x).read() }, 2);
61/// ```
62pub const fn nonnull_from<T: ?Sized>(src: impl hidden::Reference<Referee = T>) -> NonNull<T> {
63 const fn doit<T: ?Sized, R: hidden::Reference<Referee = T>>(src: R) -> NonNull<R::Referee> {
64 let ptr: *mut T = {
65 let src = ManuallyDrop::new(src);
66 if R::MUTABLE {
67 // SAFETY: &'a mut T to &'b mut T transmute
68 let ptr: &mut T = unsafe { core::mem::transmute_copy(&src) };
69 ptr
70 } else {
71 // SAFETY: &'a T to &'b T transmute
72 let ptr: &T = unsafe { core::mem::transmute_copy(&src) };
73 ptr::from_ref(ptr).cast_mut()
74 }
75 };
76 // SAFETY: References are non-null
77 unsafe { NonNull::new_unchecked(ptr) }
78 }
79 doit(src)
80}
81mod hidden {
82 /// # Safety
83 /// `Self` must be `&Referee` and `MUTABLE = false` or `&mut Referee` and `MUTABLE = true`
84 pub unsafe trait Reference: Into<core::ptr::NonNull<Self::Referee>> {
85 type Referee: ?Sized;
86 const MUTABLE: bool;
87 }
88 // SAFETY: trivial
89 unsafe impl<T: ?Sized> Reference for &T {
90 type Referee = T;
91 const MUTABLE: bool = false;
92 }
93 // SAFETY: trivial
94 unsafe impl<T: ?Sized> Reference for &mut T {
95 type Referee = T;
96 const MUTABLE: bool = true;
97 }
98}