Skip to main content

refs/
rglica.rs

1use core::ptr::from_ref;
2use std::{
3    any::type_name,
4    fmt::{Debug, Formatter},
5    ops::{Deref, DerefMut},
6    ptr::NonNull,
7};
8
9use log::error;
10
11/// `Rglica` is a thin wrapper around a raw, non-owning pointer (`NonNull<T>`).
12///
13/// This struct provides C++ style raw pointer behavior in Rust.
14///
15/// # Safety
16/// - Not safe at all.
17///
18/// # Notes
19/// - Use with caution — misuse can cause undefined behavior.
20/// - Designed for performance-sensitive code.
21///
22/// Very unsafe — avoid using unless absolutely necessary.
23pub struct Rglica<T: ?Sized> {
24    pub ptr: Option<NonNull<T>>,
25}
26
27unsafe impl<T: ?Sized> Send for Rglica<T> {}
28
29impl<T: ?Sized> Copy for Rglica<T> {}
30
31impl<T: ?Sized> Clone for Rglica<T> {
32    fn clone(&self) -> Rglica<T> {
33        *self
34    }
35}
36
37impl<T: ?Sized> Rglica<T> {
38    pub const fn const_default() -> Self {
39        Self { ptr: None }
40    }
41
42    pub fn from_ref(rf: &T) -> Rglica<T> {
43        let ptr = NonNull::new((from_ref::<T>(rf)).cast_mut());
44        debug_assert!(ptr.is_some(), "Failed to cast ref to Rglica");
45        Self {
46            ptr: ptr.unwrap().into(),
47        }
48    }
49
50    pub fn is_null(&self) -> bool {
51        self.ptr.is_none()
52    }
53
54    pub fn is_ok(&self) -> bool {
55        self.ptr.is_some()
56    }
57
58    pub fn as_ptr(&self) -> *mut T {
59        self.ptr.unwrap().as_ptr()
60    }
61
62    pub fn get(&mut self) -> Option<&mut T> {
63        if self.is_ok() {
64            self.deref_mut().into()
65        } else {
66            None
67        }
68    }
69}
70
71impl<T: ?Sized> Deref for Rglica<T> {
72    type Target = T;
73    fn deref(&self) -> &T {
74        if self.is_null() {
75            error!("Null Rglica: {}", std::any::type_name::<T>());
76            // backtrace();
77            panic!("Null Rglica: {}", std::any::type_name::<T>());
78        }
79        unsafe { self.ptr.unwrap().as_ref() }
80    }
81}
82
83impl<T: ?Sized> DerefMut for Rglica<T> {
84    fn deref_mut(&mut self) -> &mut T {
85        if self.is_null() {
86            error!("Null Rglica: {}", std::any::type_name::<T>());
87            // backtrace();
88            panic!("Null Rglica: {}", std::any::type_name::<T>());
89        }
90        unsafe { self.ptr.unwrap().as_mut() }
91    }
92}
93
94impl<T: ?Sized> Default for Rglica<T> {
95    fn default() -> Rglica<T> {
96        Self { ptr: None }
97    }
98}
99
100impl<T: ?Sized> Debug for Rglica<T> {
101    default fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102        type_name::<T>().fmt(f)
103    }
104}
105
106impl<T: ?Sized + Debug> Debug for Rglica<T> {
107    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
108        if self.is_null() {
109            return self.ptr.fmt(f);
110        }
111        self.deref().fmt(f)
112    }
113}
114
115#[cfg(test)]
116mod test {
117    use std::ops::{Deref, DerefMut};
118
119    use crate::Rglica;
120
121    struct NoDebug;
122
123    #[test]
124    #[should_panic(expected = "Null Rglica: i32")]
125    fn null_rglica() {
126        let null = Rglica::<i32>::default();
127        assert!(null.is_null());
128        assert_eq!(null.is_ok(), false);
129        _ = null.deref();
130    }
131
132    #[test]
133    #[should_panic(expected = "Null Rglica: i32")]
134    fn null_rglica_mut() {
135        let mut null = Rglica::<i32>::default();
136        assert!(null.is_null());
137        assert_eq!(null.is_ok(), false);
138        _ = null.deref_mut();
139    }
140
141    #[test]
142    fn rglica_misc() {
143        let five = 5;
144
145        let five = &five;
146
147        let mut val = Rglica::from_ref(five);
148
149        assert_eq!(val.is_null(), false);
150        assert_eq!(val.is_ok(), true);
151
152        assert_eq!("5", &format!("{val:?}"));
153
154        let cloned = val.clone();
155
156        assert_eq!(val.deref(), cloned.deref());
157
158        let get = val.get().unwrap();
159
160        *get = 10;
161
162        assert_eq!(*val.deref(), 10);
163
164        assert_eq!(
165            "\"refs::rglica::test::NoDebug\"",
166            format!("{:?}", Rglica::from_ref(&NoDebug))
167        );
168
169        assert_eq!("None", format!("{:?}", Rglica::<i32>::default()));
170
171        assert_eq!(None, Rglica::<i32>::default().get());
172    }
173}