rusteal_core/
reify_registry.rs1use std::collections::HashMap;
10use std::sync::{Arc, Mutex, OnceLock, RwLock};
11
12use crate::{lock_or_recover, read_or_recover, write_or_recover};
13
14pub struct ClassRegistration {
20 pub register: fn(),
21 pub finalize: fn(),
22}
23inventory::collect!(ClassRegistration);
24
25pub struct ClassFunctionRegistration {
27 pub register_functions: fn(),
28}
29inventory::collect!(ClassFunctionRegistration);
30
31pub fn register_all_from_inventory() {
33 let mut class_count = 0u32;
34 for reg in inventory::iter::<ClassRegistration> {
35 (reg.register)();
36 class_count += 1;
37 }
38 let mut func_reg_count = 0u32;
39 for freg in inventory::iter::<ClassFunctionRegistration> {
40 (freg.register_functions)();
41 func_reg_count += 1;
42 }
43 for reg in inventory::iter::<ClassRegistration> {
44 (reg.finalize)();
45 }
46
47 let total_funcs = read_or_recover(func_registry()).len();
49 let msg = format!(
50 "[Rusteal] register_all_from_inventory: {} classes, {} impl blocks, {} function callbacks",
51 class_count, func_reg_count, total_funcs,
52 );
53 let bytes = msg.as_bytes();
54 unsafe {
55 crate::ffi_dispatch::logging_log(0, bytes.as_ptr(), bytes.len() as u32);
56 }
57}
58
59use rusteal_ffi::UObjectHandle;
60
61pub struct RustTypeInfo {
63 pub name: &'static str,
65 pub construct_fn: fn() -> *mut u8,
68 pub drop_fn: unsafe fn(*mut u8),
70}
71
72use crate::ffi_dispatch::NativePtr;
73
74type ReifyFunctionCallback = Arc<dyn Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync>;
80
81static TYPE_REGISTRY: OnceLock<Mutex<HashMap<u64, RustTypeInfo>>> = OnceLock::new();
86static FUNC_REGISTRY: OnceLock<RwLock<Vec<ReifyFunctionCallback>>> = OnceLock::new();
87static INSTANCE_DATA: OnceLock<RwLock<HashMap<u64, InstanceEntry>>> = OnceLock::new();
88
89struct InstanceEntry {
90 data: *mut u8,
91 type_id: u64,
92}
93
94unsafe impl Send for InstanceEntry {}
96unsafe impl Sync for InstanceEntry {}
97
98fn type_registry() -> &'static Mutex<HashMap<u64, RustTypeInfo>> {
99 TYPE_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
100}
101
102fn func_registry() -> &'static RwLock<Vec<ReifyFunctionCallback>> {
103 FUNC_REGISTRY.get_or_init(|| RwLock::new(Vec::new()))
104}
105
106fn instance_data() -> &'static RwLock<HashMap<u64, InstanceEntry>> {
107 INSTANCE_DATA.get_or_init(|| RwLock::new(HashMap::new()))
108}
109
110pub fn register_type(type_id: u64, info: RustTypeInfo) {
116 lock_or_recover(type_registry())
117 .insert(type_id, info);
118}
119
120pub fn register_function<F>(f: F) -> u64
126where
127 F: Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync + 'static,
128{
129 let mut vec = write_or_recover(func_registry());
130 let id = vec.len() as u64;
131 vec.push(Arc::new(f));
132 id
133}
134
135pub fn construct_instance(obj: UObjectHandle, type_id: u64) {
142 let types = lock_or_recover(type_registry());
143 let Some(info) = types.get(&type_id) else {
144 if crate::api::is_api_initialized() {
146 let msg = format!("[Rusteal] construct_instance: unknown type_id {type_id}");
147 let bytes = msg.as_bytes();
148 unsafe {
149 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
150 }
151 }
152 return;
153 };
154 let data = (info.construct_fn)();
155 drop(types); let key = obj.to_addr();
158 write_or_recover(instance_data())
159 .insert(key, InstanceEntry { data, type_id });
160}
161
162pub fn drop_instance(obj: UObjectHandle, _type_id: u64) {
165 let key = obj.to_addr();
166 let entry = write_or_recover(instance_data()).remove(&key);
167
168 if let Some(entry) = entry {
169 let types = lock_or_recover(type_registry());
170 if let Some(info) = types.get(&entry.type_id) {
171 unsafe {
172 (info.drop_fn)(entry.data);
173 }
174 }
175 }
176}
177
178pub fn invoke_function(callback_id: u64, obj: UObjectHandle, params: NativePtr) {
181 let key = obj.to_addr();
182
183 let rust_data = read_or_recover(instance_data())
185 .get(&key)
186 .map(|e| e.data)
187 .unwrap_or(std::ptr::null_mut());
188
189 let func = {
193 let vec = read_or_recover(func_registry());
194 vec.get(callback_id as usize).cloned()
195 };
196
197 if let Some(func) = func {
198 func(obj, rust_data, params);
199 } else if crate::api::is_api_initialized() {
200 let vec_len = read_or_recover(func_registry()).len();
201 let msg = format!(
202 "[Rusteal] invoke_function: callback_id {} not found (registry size = {})",
203 callback_id, vec_len,
204 );
205 let bytes = msg.as_bytes();
206 unsafe {
207 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
208 }
209 }
210}
211
212pub fn clear_all() {
215 if let Some(instances) = INSTANCE_DATA.get() {
217 let mut map = write_or_recover(instances);
218 let types = lock_or_recover(type_registry());
219 for (_, entry) in map.drain() {
220 if let Some(info) = types.get(&entry.type_id) {
221 unsafe {
222 (info.drop_fn)(entry.data);
223 }
224 }
225 }
226 drop(types);
227 }
228 if let Some(funcs) = FUNC_REGISTRY.get() {
230 write_or_recover(funcs).clear();
231 }
232 if let Some(types) = TYPE_REGISTRY.get() {
234 lock_or_recover(types).clear();
235 }
236}
237
238pub fn get_instance_data(obj: UObjectHandle) -> *mut u8 {
241 let key = obj.to_addr();
242 read_or_recover(instance_data())
243 .get(&key)
244 .map(|e| e.data)
245 .unwrap_or(std::ptr::null_mut())
246}