mvutils/
unsafe_utils.rs

1use std::alloc::Layout;
2use std::cell::UnsafeCell;
3use std::ffi::c_void;
4use std::fmt::{Debug, Display, Formatter};
5use std::marker::PhantomData;
6use std::ops::{Deref, DerefMut};
7use std::sync::atomic::{AtomicUsize, Ordering};
8use std::sync::Arc;
9
10pub union UnsafeRef<T> {
11    ptr: *mut c_void,
12    phantom: PhantomData<T>,
13}
14
15impl<T> UnsafeRef<T> {
16    /// Initialize an [`UnsafeRef<T>`] with a pointer value.
17    ///
18    /// # Safety
19    ///
20    /// It is up to the user to ensure that the pointed to value lives long enough, and that this
21    /// struct is dropped when the pointee is.
22    pub unsafe fn new(data: &T) -> Self {
23        Self {
24            ptr: data as *const T as *mut c_void,
25        }
26    }
27
28    /// Initialize an [`UnsafeRef<T>`] as null.
29    ///
30    /// # Safety
31    ///
32    /// This function sets the value to null. It is up to the user to check whether the pointer is
33    /// null using [`UnsafeRef::is_null`] before calling functions on the dereferenced value.
34    pub unsafe fn null() -> Self {
35        Self {
36            ptr: std::ptr::null_mut(),
37        }
38    }
39
40    /// Check whether the pointer is null or not
41    ///
42    /// NOTE: This does not verify whether the pointee has been dropped, there is no way to
43    /// do that, which is why this is unsafe
44    ///
45    /// It does **not** check if the memory is valid, aligned, or initialized.
46    pub fn is_null(&self) -> bool {
47        unsafe {
48            !self.ptr.is_null()
49        }
50    }
51
52    /// Reinterpret the value at this pointer as another type. This does not cast, it just assumes
53    /// the bytes at the pointer are the same type and same length and alignment.
54    ///
55    /// # Safety
56    ///
57    /// It is entirely up to the user to ensure that the pointer is valid, and that both types [`T`]
58    /// and [`R`] have the same size and alignment, and that no type-specific layout constraints are
59    /// violated (e.g., invalid enum tags, misalignment)
60    pub unsafe fn cast_bytes<R>(&self) -> UnsafeRef<R> {
61        UnsafeRef {
62            ptr: self.ptr,
63        }
64    }
65
66    /// Compare the pointers
67    ///
68    /// This compares the raw pointers, not the pointee values, true will only be returned if both
69    /// refs point to the same memory address
70    pub fn same_as<R>(&self, other: &UnsafeRef<R>) -> bool {
71        unsafe {
72            self.ptr == other.ptr
73        }
74    }
75
76    /// Reinterpret the bytes at this pointer as a reference. This does not change the bytes at the
77    /// reference, nor does it prevent them from being dropped.
78    ///
79    /// Do not call this unless you know the pointer is not null or have checked using [`is_null`].
80    ///
81    /// # Safety
82    /// It is entirely up to the user to ensure that the pointer is valid.
83    #[must_use]
84    pub unsafe fn as_ref<'a>(&self) -> &'a T {
85        (self.ptr as *const T)
86            .as_ref()
87            .expect("Failed to dereference UnsafeRef.")
88    }
89
90    /// Reinterpret the bytes at this pointer as a mutable reference. This does not change the bytes at the
91    /// reference, nor does it prevent them from being dropped.
92    ///
93    /// Do not call this unless you know the pointer is not null or have checked using [`is_null`].
94    ///
95    /// # Safety
96    /// It is entirely up to the user to ensure that the pointer is valid.
97    #[must_use]
98    pub unsafe fn as_mut<'a>(&mut self) -> &'a mut T {
99        (self.ptr as *mut T)
100            .as_mut()
101            .expect("Failed to dereference UnsafeRef.")
102    }
103}
104
105unsafe impl<T> UnsafeFrom<&T> for UnsafeRef<T> {
106    unsafe fn unsafe_from(value: &T) -> Self {
107        Self::new(value)
108    }
109}
110
111impl<T> Clone for UnsafeRef<T> {
112    fn clone(&self) -> Self {
113        unsafe {
114            Self {
115                ptr: self.ptr,
116            }
117        }
118    }
119}
120
121pub struct Unsafe;
122
123impl Unsafe {
124    /// Reinterpret the bytes at this pointer as another type. This does not change the bytes at the
125    /// reference.
126    ///
127    /// # Safety
128    /// It is entirely up to the user to ensure that the pointer is valid, and that both types [`T`]
129    /// and [`R`] are of the same size and alignment.
130    #[track_caller]
131    #[must_use]
132    pub unsafe fn cast_ref<T: Sized, R: Sized>(value: &T) -> &R {
133        (value as *const T as *const R).as_ref().unwrap()
134    }
135
136    /// Reinterpret the bytes at this mutable pointer as another type. This does not change the bytes at the
137    /// reference.
138    ///
139    /// # Safety
140    /// It is entirely up to the user to ensure that the pointer is valid, and that both types [`T`]
141    /// and [`R`] are of the same size and alignment. Additionally, the user must gurantee that
142    /// the original reference is not aliased after this is called.
143    #[track_caller]
144    #[must_use]
145    pub unsafe fn cast_mut<T: Sized, R: Sized>(value: &mut T) -> &mut R {
146        (value as *mut T as *mut R).as_mut().unwrap()
147    }
148
149    /// Reinterpret the bytes at this pointer as static reference. This does not change the bytes at the
150    /// reference, nor does it prevent them from being dropped.
151    ///
152    /// # Safety
153    /// It is entirely up to the user to ensure that the pointer is valid, and will remain valid for
154    /// the duration of the new lifetime.
155    #[track_caller]
156    #[must_use]
157    pub unsafe fn cast_lifetime<'a, 'b, T>(value: &'a T) -> &'b T {
158        (value as *const T).as_ref().unwrap()
159    }
160
161    /// Reinterpret the bytes at this mutable pointer as static reference. This does not change the bytes at the
162    /// reference, nor does it prevent them from being dropped.
163    ///
164    /// # Safety
165    /// It is entirely up to the user to ensure that the pointer is valid, and will remain valid for
166    /// the duration of the new lifetime.
167    #[track_caller]
168    #[must_use]
169    pub unsafe fn cast_lifetime_mut<'a, 'b, T>(value: &'a mut T) -> &'b mut T {
170        (value as *mut T).as_mut().unwrap()
171    }
172
173    /// Reinterpret the bytes at this pointer as static reference. This does not change the bytes at the
174    /// reference, nor does it prevent them from being dropped.
175    ///
176    /// # Safety
177    /// It is entirely up to the user to ensure that the pointer is valid , and will remain valid for
178    /// the rest of the program.
179    pub unsafe fn cast_static<T>(value: &T) -> &'static T {
180        (value as *const T).as_ref().unwrap()
181    }
182
183    /// Reinterpret the bytes at this mutable pointer as static reference. This does not change the bytes at the
184    /// reference, nor does it prevent them from being dropped.
185    ///
186    /// # Safety
187    /// It is entirely up to the user to ensure that the pointer is valid , and will remain valid for
188    /// the rest of the program.
189    pub unsafe fn cast_mut_static<T>(value: &mut T) -> &'static mut T {
190        (value as *mut T).as_mut().unwrap()
191    }
192
193    /// Move the value to the heap and keep it alive for the rest of the program. Returning a reference
194    /// to the value.
195    pub fn leak<T>(value: T) -> &'static T {
196        Box::leak(Box::new(value))
197    }
198
199    /// Move the value to the heap and keep it alive for the rest of the program. Returning a mutable reference
200    /// to the value.
201    pub fn leak_mut<T>(value: T) -> &'static mut T {
202        Box::leak(Box::new(value))
203    }
204
205    /// Allocate a zeroed value on the heap and return a reference to it of type [`T`].
206    ///
207    /// # Safety
208    /// It is entirely up to the user to ensure that the type [`T`] is valid with the zeroed data,
209    /// or that the data is added before handing this reference to other parts of the program.
210    #[track_caller]
211    pub unsafe fn leak_zeroed<T>() -> &'static T {
212        Box::leak(Box::new(std::mem::MaybeUninit::<T>::zeroed().assume_init()))
213    }
214
215    /// Allocate a zeroed value on the heap and return a mutable reference to it of type [`T`].
216    ///
217    /// # Safety
218    /// It is entirely up to the user to ensure that the type [`T`] is valid with the zeroed data,
219    /// or that the data is added before handing this reference to other parts of the program.
220    #[track_caller]
221    pub unsafe fn leak_zeroed_mut<T>() -> &'static mut T {
222        Box::leak(Box::new(std::mem::MaybeUninit::<T>::zeroed().assume_init()))
223    }
224}
225
226#[repr(transparent)]
227pub struct DangerousCell<T> {
228    inner: UnsafeCell<T>,
229}
230
231impl<T> DangerousCell<T> {
232    #[inline(always)]
233    pub fn new(value: T) -> Self {
234        DangerousCell {
235            inner: UnsafeCell::new(value),
236        }
237    }
238
239    #[inline(always)]
240    pub fn get(&self) -> &T {
241        unsafe { self.inner.get().as_ref().unwrap() }
242    }
243
244    #[allow(clippy::mut_from_ref)]
245    #[inline(always)]
246    pub fn get_mut(&self) -> &mut T {
247        unsafe { self.inner.get().as_mut().unwrap() }
248    }
249
250    #[inline(always)]
251    pub fn replace(&self, value: T) {
252        unsafe {
253            self.inner.get().write(value);
254        }
255    }
256}
257
258impl<T: Copy> DangerousCell<T> {
259    #[inline(always)]
260    pub fn get_val(&self) -> T {
261        unsafe { *self.inner.get() }
262    }
263}
264
265impl<T> From<T> for DangerousCell<T> {
266    fn from(value: T) -> Self {
267        Self::new(value)
268    }
269}
270
271
272// TODO: same macroize needed as thread safe here plz asap when v22 is not rushing me
273// also a lot of traits missing
274impl<T: Debug> Debug for DangerousCell<T> {
275    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
276        Debug::fmt(self.get(), f)
277    }
278}
279
280impl<T: Display> Display for DangerousCell<T> {
281    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
282        Display::fmt(self.get(), f)
283    }
284}
285
286impl<T: Clone> Clone for DangerousCell<T> {
287    fn clone(&self) -> Self {
288        DangerousCell::new(self.get().clone())
289    }
290}
291
292impl<T: Default> Default for DangerousCell<T> {
293    fn default() -> Self {
294        DangerousCell::new(Default::default())
295    }
296}
297
298/// A copy of the [`From<T>`] trait, but for types where this operation is unsafe.
299///
300/// # Safety
301/// It is up to the user to ensure that when using this, safety checks are implemented.
302pub unsafe trait UnsafeFrom<T>: Sized {
303    /// Converts to this type from the input type.
304    #[must_use]
305    unsafe fn unsafe_from(value: T) -> Self;
306}
307
308/// A copy of the [`Into<T>`] trait, but for types where this operation is unsafe.
309///
310/// # Safety
311/// It is up to the user to ensure that when using this, safety checks are implemented.
312pub unsafe trait UnsafeInto<T>: Sized {
313    /// Converts this type into the (usually inferred) input type.
314    #[must_use]
315    unsafe fn unsafe_into(self) -> T;
316}
317
318unsafe impl<T, U> UnsafeInto<U> for T
319where
320    U: UnsafeFrom<T>,
321{
322    /// Calls `U::from(self)`.
323    ///
324    /// That is, this conversion is whatever the implementation of
325    /// <code>[UnsafeFrom]&lt;T&gt; for U</code> chooses to do.
326    #[inline]
327    unsafe fn unsafe_into(self) -> U {
328        U::unsafe_from(self)
329    }
330}
331
332#[macro_export]
333macro_rules! unsafe_cast {
334    ($val:ident, $to:ty) => {
335        unsafe { (($val as *const _) as *const $to).as_ref().unwrap() }
336    };
337}
338#[macro_export]
339macro_rules! unsafe_multi_borrow {
340    ($val:ident, $t:ty) => {
341        unsafe { (&$val as *const $t).as_ref().unwrap() }
342    };
343}
344
345#[macro_export]
346macro_rules! unsafe_multi_borrow_mut {
347    ($val:ident, $t:ty) => {
348        unsafe { (&mut $val as *mut $t).as_mut().unwrap() }
349    };
350}