commonlibsse_ng\re\h/
hkRefPtr.rs

1//! # hkRefPtr
2//!
3//! This module defines the `hkRefPtr` smart pointer, which is a reference-counted
4//! pointer used in the Havok engine. It mimics C++ `hkRefPtr` behavior with
5//! reference counting and smart pointer functionality.
6
7use std::marker::PhantomData;
8use std::ops::{Deref, DerefMut};
9use std::ptr;
10
11use crate::re::hkaMirroredSkeleton;
12
13/// A smart pointer with reference counting, modeled after Havok's `hkRefPtr`.
14#[repr(C)]
15pub struct hkRefPtr<T>
16where
17    T: hkRefPtrCounted,
18{
19    /// The raw pointer to the referenced object.
20    /// - Offset: `0x0`
21    _ptr: *mut T,
22    /// Phantom type marker for the template type.
23    _marker: PhantomData<T>,
24}
25
26/// Ensure the memory layout matches the C++ version.
27const _: () = {
28    assert!(core::mem::size_of::<hkRefPtr<hkaMirroredSkeleton>>() == 0x8);
29};
30
31pub trait hkRefPtrCounted {
32    fn AddReference(&self) {}
33    fn RemoveReference(&self) {}
34}
35
36impl<T> hkRefPtr<T>
37where
38    T: hkRefPtrCounted,
39{
40    /// Creates a new `hkRefPtr` with a `nullptr`.
41    #[inline]
42    pub const fn new() -> Self {
43        Self { _ptr: ptr::null_mut(), _marker: PhantomData }
44    }
45
46    /// Creates an `hkRefPtr` from a raw pointer.
47    #[inline]
48    pub fn from_raw(ptr: *mut T) -> Self {
49        let mut ref_ptr = Self { _ptr: ptr, _marker: PhantomData };
50        ref_ptr.try_attach();
51        ref_ptr
52    }
53
54    /// Resets the pointer, releasing the reference.
55    #[inline]
56    pub fn reset(&mut self) {
57        self.try_detach();
58    }
59
60    /// Replaces the current pointer with a new one.
61    #[inline]
62    pub fn reset_with(&mut self, ptr: *mut T) {
63        if self._ptr != ptr {
64            self.try_detach();
65            self._ptr = ptr;
66            self.try_attach();
67        }
68    }
69
70    /// Returns the raw pointer.
71    #[inline]
72    pub const fn get(&self) -> *mut T {
73        self._ptr
74    }
75
76    /// Checks if the pointer is not `nullptr`.
77    #[inline]
78    pub const fn is_some(&self) -> bool {
79        !self._ptr.is_null()
80    }
81
82    /// Tries to attach to the reference, increasing its count.
83    #[inline]
84    fn try_attach(&mut self) {
85        if !self._ptr.is_null() {
86            unsafe {
87                (*self._ptr).AddReference();
88            }
89        }
90    }
91
92    /// Tries to detach from the reference, decreasing its count.
93    #[inline]
94    fn try_detach(&mut self) {
95        if !self._ptr.is_null() {
96            unsafe {
97                (*self._ptr).RemoveReference();
98            }
99            self._ptr = ptr::null_mut();
100        }
101    }
102}
103
104impl<T> Default for hkRefPtr<T>
105where
106    T: hkRefPtrCounted,
107{
108    #[inline]
109    fn default() -> Self {
110        Self::new()
111    }
112}
113
114impl<T> Clone for hkRefPtr<T>
115where
116    T: hkRefPtrCounted,
117{
118    #[inline]
119    fn clone(&self) -> Self {
120        let mut ref_ptr = Self { _ptr: self._ptr, _marker: PhantomData };
121        ref_ptr.try_attach();
122        ref_ptr
123    }
124}
125
126impl<T> Drop for hkRefPtr<T>
127where
128    T: hkRefPtrCounted,
129{
130    #[inline]
131    fn drop(&mut self) {
132        self.try_detach();
133    }
134}
135
136impl<T> Deref for hkRefPtr<T>
137where
138    T: hkRefPtrCounted,
139{
140    type Target = T;
141
142    #[inline]
143    fn deref(&self) -> &Self::Target {
144        assert!(!self._ptr.is_null(), "Dereferencing a nullptr");
145        unsafe { &*self._ptr }
146    }
147}
148
149impl<T> DerefMut for hkRefPtr<T>
150where
151    T: hkRefPtrCounted,
152{
153    #[inline]
154    fn deref_mut(&mut self) -> &mut Self::Target {
155        assert!(!self._ptr.is_null(), "Dereferencing a nullptr");
156        unsafe { &mut *self._ptr }
157    }
158}
159
160impl<T> PartialEq for hkRefPtr<T>
161where
162    T: hkRefPtrCounted,
163{
164    #[inline]
165    fn eq(&self, other: &Self) -> bool {
166        self.get() == other.get()
167    }
168}
169
170impl<T> Eq for hkRefPtr<T> where T: hkRefPtrCounted {}
171
172impl<T> std::fmt::Debug for hkRefPtr<T>
173where
174    T: hkRefPtrCounted,
175{
176    #[inline]
177    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178        f.debug_struct("hkRefPtr").field("ptr", &self._ptr).finish()
179    }
180}
181
182/// Creates a new `hkRefPtr` with a constructed instance of `T`.
183#[inline]
184pub fn make_hkref<T>(value: T) -> hkRefPtr<T>
185where
186    T: hkRefPtrCounted,
187{
188    let boxed = Box::new(value);
189    hkRefPtr::from_raw(Box::into_raw(boxed))
190}
191
192/// Equality operators with `nullptr`.
193impl<T> PartialEq<std::ptr::NonNull<T>> for hkRefPtr<T>
194where
195    T: hkRefPtrCounted,
196{
197    #[inline]
198    fn eq(&self, other: &std::ptr::NonNull<T>) -> bool {
199        self.get() == other.as_ptr()
200    }
201}
202
203impl<T> PartialEq<*mut T> for hkRefPtr<T>
204where
205    T: hkRefPtrCounted,
206{
207    #[inline]
208    fn eq(&self, other: &*mut T) -> bool {
209        self.get() == *other
210    }
211}