commonlibsse_ng\re\g/
GPtr.rs

1/// Trait for reference counting.
2pub trait RefCounted {
3    fn add_ref(&mut self);
4    fn release(&mut self);
5}
6
7/// Similar to `Arc`, but does not call `release` while the reference count is
8/// greater than or equal to zero.
9///
10/// It differs from `Arc` in that it does not have its own reference-counting field. In other words, it manipulates the pointer it holds via an external reference count and drop implementation.
11#[repr(transparent)]
12pub struct GPtr<T: RefCounted> {
13    ptr: *mut T,
14}
15
16impl<T: RefCounted> GPtr<T> {
17    #[inline]
18    pub const fn new(ptr: *mut T) -> Self {
19        Self { ptr }
20    }
21
22    #[inline]
23    pub const fn null() -> Self {
24        Self { ptr: core::ptr::null_mut() }
25    }
26
27    #[inline]
28    pub fn from_raw(ptr: *mut T) -> Self {
29        let mut g_ptr = Self { ptr };
30        g_ptr.try_attach();
31        g_ptr
32    }
33
34    #[inline]
35    pub fn reset(&mut self) {
36        self.try_detach();
37    }
38
39    #[inline]
40    pub fn reset_with(&mut self, ptr: *mut T) {
41        if self.ptr != ptr {
42            self.try_detach();
43            self.ptr = ptr;
44            self.try_attach();
45        }
46    }
47
48    #[inline]
49    pub const fn get(&self) -> *mut T {
50        self.ptr
51    }
52
53    #[inline]
54    pub const fn as_ref(&self) -> Option<&T> {
55        unsafe { self.ptr.as_ref() }
56    }
57
58    #[inline]
59    pub const fn as_mut(&mut self) -> Option<&mut T> {
60        unsafe { self.ptr.as_mut() }
61    }
62
63    #[inline]
64    pub fn cast<U>(self) -> GPtr<U>
65    where
66        U: RefCounted,
67    {
68        GPtr::<U>::new(self.ptr.cast())
69    }
70
71    fn try_attach(&mut self) {
72        if let Some(ptr) = self.as_mut() {
73            ptr.add_ref();
74        }
75    }
76
77    fn try_detach(&mut self) {
78        if let Some(ptr) = self.as_mut() {
79            ptr.release();
80        }
81        self.ptr = core::ptr::null_mut();
82    }
83}
84
85impl<T: RefCounted> Clone for GPtr<T> {
86    #[inline]
87    fn clone(&self) -> Self {
88        let mut cloned = Self { ptr: self.ptr };
89        cloned.try_attach();
90        cloned
91    }
92}
93
94impl<T: RefCounted> Drop for GPtr<T> {
95    #[inline]
96    fn drop(&mut self) {
97        self.try_detach();
98    }
99}
100
101impl<T: RefCounted> core::ops::Deref for GPtr<T> {
102    type Target = T;
103
104    #[inline]
105    fn deref(&self) -> &Self::Target {
106        self.as_ref().expect("GPtr is null")
107    }
108}
109
110impl<T: RefCounted> core::ops::DerefMut for GPtr<T> {
111    #[inline]
112    fn deref_mut(&mut self) -> &mut Self::Target {
113        self.as_mut().expect("GPtr is null")
114    }
115}
116
117impl<T: RefCounted> From<*mut T> for GPtr<T> {
118    #[inline]
119    fn from(ptr: *mut T) -> Self {
120        Self::from_raw(ptr)
121    }
122}
123
124impl<T: RefCounted> PartialEq for GPtr<T> {
125    #[inline]
126    fn eq(&self, other: &Self) -> bool {
127        self.ptr == other.ptr
128    }
129}
130
131impl<T: RefCounted> Eq for GPtr<T> {}
132
133impl<T: RefCounted> Default for GPtr<T> {
134    #[inline]
135    fn default() -> Self {
136        Self::null()
137    }
138}
139
140// impl<T: RefCounted> core::fmt::Debug for GPtr<T> {
141//     #[inline]
142//     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
143//         f.debug_struct("GPtr").field("ptr", &self.ptr).finish()
144//     }
145// }
146impl<T: RefCounted + core::fmt::Debug> core::fmt::Debug for GPtr<T> {
147    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
148        match self.as_ref() {
149            Some(value) => {
150                f.debug_struct("GPtr").field("ptr", &self.ptr).field("value", value).finish()
151            }
152            None => f.debug_struct("GPtr").field("ptr", &self.ptr).finish(),
153        }
154    }
155}
156
157/// Factory function: `make_g_ptr`
158#[inline]
159pub fn make_g_ptr<T: RefCounted>(value: T) -> GPtr<T> {
160    // FIXME: Write NiMemoryManager
161    let boxed = Box::new(value);
162    let raw = Box::into_raw(boxed);
163    let ptr = GPtr::from_raw(raw);
164    // Balance the internal AddRef with this manual release
165    unsafe {
166        (*raw).release();
167    }
168    ptr
169}