1use std::collections::HashMap;
2use std::marker::PhantomData;
3use std::ops::Deref;
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::{Arc, Mutex, OnceLock};
6
7use crate::lock_or_recover;
8
9use rusteal_ffi::UObjectHandle;
10
11use crate::error::{RustealError, RustealResult};
12use crate::ffi_dispatch;
13use crate::object_ref::{Checked, UObjectRef};
14use crate::traits::{HasParent, UeClass, UeHandle, ValidHandle};
15
16fn alive_registry() -> &'static Mutex<HashMap<u64, Arc<AtomicBool>>> {
17 static REGISTRY: OnceLock<Mutex<HashMap<u64, Arc<AtomicBool>>>> = OnceLock::new();
18 REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
19}
20
21pub fn notify_pinned_destroyed(handle: UObjectHandle) {
22 if let Ok(registry) = alive_registry().lock()
23 && let Some(flag) = registry.get(&handle.to_addr())
24 {
25 flag.store(false, Ordering::Relaxed);
26 }
27}
28
29pub fn clear_all() {
30 if let Ok(mut registry) = alive_registry().lock() {
31 registry.clear();
32 }
33}
34
35#[repr(C)]
36pub struct Pinned<T: UeClass> {
37 handle: UObjectHandle,
38 alive: Arc<AtomicBool>,
39 _marker: PhantomData<*const T>,
40}
41
42unsafe impl<T: UeClass> Send for Pinned<T> {}
43
44impl<T: UeClass> Pinned<T> {
45 pub fn new(obj: UObjectRef<T>) -> RustealResult<Self> {
46 if !obj.is_valid() {
47 return Err(RustealError::ObjectDestroyed);
48 }
49
50 let alive = Arc::new(AtomicBool::new(true));
51
52 lock_or_recover(alive_registry()).insert(obj.raw().to_addr(), alive.clone());
53
54 unsafe {
55 ffi_dispatch::lifecycle_add_gc_root(obj.raw());
56 ffi_dispatch::lifecycle_register_pinned(obj.raw());
57 }
58
59 Ok(Pinned {
60 handle: obj.raw(),
61 alive,
62 _marker: PhantomData,
63 })
64 }
65
66 #[inline]
67 pub fn is_alive(&self) -> bool {
68 self.alive.load(Ordering::Relaxed)
69 }
70
71 #[inline]
72 pub fn handle(&self) -> UObjectHandle {
73 self.handle
74 }
75
76 #[inline]
77 pub fn as_ref(&self) -> UObjectRef<T> {
78 unsafe { UObjectRef::from_raw(self.handle) }
79 }
80
81 #[inline]
82 pub fn as_checked(&self) -> Checked<T> {
83 debug_assert!(self.is_alive(), "Pinned object has been destroyed");
84
85 Checked::new_unchecked(self.handle)
86 }
87}
88
89impl<T: UeClass> Drop for Pinned<T> {
90 fn drop(&mut self) {
91 lock_or_recover(alive_registry()).remove(&self.handle.to_addr());
92
93 unsafe {
94 ffi_dispatch::lifecycle_unregister_pinned(self.handle);
95 ffi_dispatch::lifecycle_remove_gc_root(self.handle);
96 }
97 }
98}
99
100impl<T: UeClass> ValidHandle for Pinned<T> {
101 #[inline]
102 fn handle(&self) -> UObjectHandle {
103 debug_assert!(self.is_alive(), "Pinned object has been destroyed");
104
105 self.handle
106 }
107}
108
109impl<T: UeClass> UeHandle for Pinned<T> {
110 #[inline]
111 fn checked_handle(&self) -> RustealResult<UObjectHandle> {
112 if self.alive.load(Ordering::Relaxed) {
113 Ok(self.handle)
114 } else {
115 Err(RustealError::ObjectDestroyed)
116 }
117 }
118
119 #[inline]
120 fn raw_handle(&self) -> UObjectHandle {
121 self.handle
122 }
123}
124
125impl<T: UeClass> std::fmt::Debug for Pinned<T> {
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 f.debug_struct("Pinned")
128 .field("handle", &self.handle)
129 .field("alive", &self.is_alive())
130 .finish()
131 }
132}
133
134impl<T: HasParent> Deref for Pinned<T> {
135 type Target = Pinned<T::Parent>;
136 #[inline]
137 fn deref(&self) -> &Pinned<T::Parent> {
138 unsafe { &*(self as *const _ as *const Pinned<T::Parent>) }
139 }
140}