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]<T> 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}