rusteal_core/
reify_registry.rs1use std::collections::HashMap;
11use std::sync::{Arc, Mutex, OnceLock, RwLock};
12
13use crate::{lock_or_recover, read_or_recover, write_or_recover};
14
15pub struct ClassRegistration {
21 pub type_id: u64,
23 pub create: fn(last_try: bool) -> bool,
27 pub register: fn(),
30 pub finalize: fn(),
31 pub after_defaults: fn(),
34}
35inventory::collect!(ClassRegistration);
36
37pub struct StructRegistration {
39 pub create: fn(),
41 pub register: fn(),
44 pub finalize: fn(),
46}
47inventory::collect!(StructRegistration);
48
49pub struct ClassFunctionRegistration {
52 pub type_id: u64,
54 pub register_functions: fn(),
55 pub class_defaults: Option<fn()>,
56}
57inventory::collect!(ClassFunctionRegistration);
58
59pub trait ClassDefaultsOutcome {
62 fn report(self, class: &str);
63}
64
65impl ClassDefaultsOutcome for () {
66 fn report(self, _class: &str) {}
67}
68
69impl ClassDefaultsOutcome for crate::error::RustealResult<()> {
70 fn report(self, class: &str) {
71 if let Err(e) = self {
72 let msg = format!("[Rusteal] {class}: class defaults failed: {e}");
73 let bytes = msg.as_bytes();
74 unsafe {
75 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
76 }
77 }
78 }
79}
80
81pub fn register_all_from_inventory() {
88 let mut pending: Vec<&ClassRegistration> = inventory::iter::<ClassRegistration>.into_iter().collect();
89 let class_count = pending.len() as u32;
90 let mut ordered: Vec<&ClassRegistration> = Vec::with_capacity(pending.len());
91 loop {
92 let before = pending.len();
93 pending.retain(|reg| {
94 if (reg.create)(false) {
95 ordered.push(reg);
96 false
97 } else {
98 true
99 }
100 });
101 if pending.is_empty() || pending.len() == before {
102 break;
103 }
104 }
105 for reg in pending {
107 (reg.create)(true);
108 }
109
110 for sreg in inventory::iter::<StructRegistration> {
113 (sreg.create)();
114 }
115 for sreg in inventory::iter::<StructRegistration> {
116 (sreg.register)();
117 }
118 for sreg in inventory::iter::<StructRegistration> {
119 (sreg.finalize)();
120 }
121
122 for reg in &ordered {
123 (reg.register)();
124 }
125 let mut func_reg_count = 0u32;
126 for freg in inventory::iter::<ClassFunctionRegistration> {
127 (freg.register_functions)();
128 func_reg_count += 1;
129 }
130 for reg in &ordered {
131 (reg.finalize)();
132 for freg in inventory::iter::<ClassFunctionRegistration> {
133 if freg.type_id == reg.type_id
134 && let Some(class_defaults) = freg.class_defaults
135 {
136 class_defaults();
137 }
138 }
139 (reg.after_defaults)();
140 }
141
142 let total_funcs = read_or_recover(func_registry()).len();
144 let msg = format!(
145 "[Rusteal] register_all_from_inventory: {} classes, {} impl blocks, {} function callbacks",
146 class_count, func_reg_count, total_funcs,
147 );
148 let bytes = msg.as_bytes();
149 unsafe {
150 crate::ffi_dispatch::logging_log(0, bytes.as_ptr(), bytes.len() as u32);
151 }
152}
153
154use rusteal_ffi::UObjectHandle;
155
156pub struct RustTypeInfo {
158 pub name: &'static str,
160 pub construct_fn: fn() -> *mut u8,
163 pub drop_fn: unsafe fn(*mut u8),
165}
166
167use crate::ffi_dispatch::NativePtr;
168
169type ReifyFunctionCallback = Arc<dyn Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync>;
175
176struct FunctionEntry {
178 callback: ReifyFunctionCallback,
179 type_id: u64,
180}
181
182static TYPE_REGISTRY: OnceLock<Mutex<HashMap<u64, RustTypeInfo>>> = OnceLock::new();
187static FUNC_REGISTRY: OnceLock<RwLock<Vec<FunctionEntry>>> = OnceLock::new();
188static INSTANCE_DATA: OnceLock<RwLock<HashMap<u64, Vec<InstanceEntry>>>> = OnceLock::new();
189
190struct InstanceEntry {
191 data: *mut u8,
192 type_id: u64,
193}
194
195unsafe impl Send for InstanceEntry {}
197unsafe impl Sync for InstanceEntry {}
198
199fn type_registry() -> &'static Mutex<HashMap<u64, RustTypeInfo>> {
200 TYPE_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
201}
202
203fn func_registry() -> &'static RwLock<Vec<FunctionEntry>> {
204 FUNC_REGISTRY.get_or_init(|| RwLock::new(Vec::new()))
205}
206
207fn instance_data() -> &'static RwLock<HashMap<u64, Vec<InstanceEntry>>> {
208 INSTANCE_DATA.get_or_init(|| RwLock::new(HashMap::new()))
209}
210
211pub fn register_type(type_id: u64, info: RustTypeInfo) {
217 lock_or_recover(type_registry())
218 .insert(type_id, info);
219}
220
221pub fn register_function<F>(type_id: u64, f: F) -> u64
228where
229 F: Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync + 'static,
230{
231 let mut vec = write_or_recover(func_registry());
232 let id = vec.len() as u64;
233 vec.push(FunctionEntry { callback: Arc::new(f), type_id });
234 id
235}
236
237pub fn construct_instance(obj: UObjectHandle, type_id: u64) {
245 let types = lock_or_recover(type_registry());
246 let Some(info) = types.get(&type_id) else {
247 if crate::api::is_api_initialized() {
249 let msg = format!("[Rusteal] construct_instance: unknown type_id {type_id}");
250 let bytes = msg.as_bytes();
251 unsafe {
252 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
253 }
254 }
255 return;
256 };
257 let data = (info.construct_fn)();
258 drop(types); let key = obj.to_addr();
261 let old = {
262 let mut map = write_or_recover(instance_data());
263 let entries = map.entry(key).or_default();
264 match entries.iter_mut().find(|e| e.type_id == type_id) {
265 Some(entry) => Some(std::mem::replace(&mut entry.data, data)),
266 None => {
267 entries.push(InstanceEntry { data, type_id });
268 None
269 }
270 }
271 };
272 if let Some(old) = old {
274 drop_data(type_id, old);
275 }
276}
277
278fn drop_data(type_id: u64, data: *mut u8) {
279 let types = lock_or_recover(type_registry());
280 if let Some(info) = types.get(&type_id) {
281 unsafe {
282 (info.drop_fn)(data);
283 }
284 }
285}
286
287pub fn drop_instance(obj: UObjectHandle, _type_id: u64) {
291 let key = obj.to_addr();
292 let entries = write_or_recover(instance_data()).remove(&key);
293 for entry in entries.into_iter().flatten() {
294 drop_data(entry.type_id, entry.data);
295 }
296}
297
298pub fn invoke_function(callback_id: u64, obj: UObjectHandle, params: NativePtr) {
301 let func = {
305 let vec = read_or_recover(func_registry());
306 vec.get(callback_id as usize)
307 .map(|entry| (entry.callback.clone(), entry.type_id))
308 };
309
310 if let Some((func, type_id)) = func {
311 let rust_data = get_instance_data(obj, type_id);
313 func(obj, rust_data, params);
314 } else if crate::api::is_api_initialized() {
315 let vec_len = read_or_recover(func_registry()).len();
316 let msg = format!(
317 "[Rusteal] invoke_function: callback_id {} not found (registry size = {})",
318 callback_id, vec_len,
319 );
320 let bytes = msg.as_bytes();
321 unsafe {
322 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
323 }
324 }
325}
326
327pub fn clear_all() {
330 if let Some(instances) = INSTANCE_DATA.get() {
332 let mut map = write_or_recover(instances);
333 let types = lock_or_recover(type_registry());
334 for entry in map.drain().flat_map(|(_, entries)| entries) {
335 if let Some(info) = types.get(&entry.type_id) {
336 unsafe {
337 (info.drop_fn)(entry.data);
338 }
339 }
340 }
341 drop(types);
342 }
343 if let Some(funcs) = FUNC_REGISTRY.get() {
345 write_or_recover(funcs).clear();
346 }
347 if let Some(types) = TYPE_REGISTRY.get() {
349 lock_or_recover(types).clear();
350 }
351}
352
353pub fn get_instance_data(obj: UObjectHandle, type_id: u64) -> *mut u8 {
356 let key = obj.to_addr();
357 read_or_recover(instance_data())
358 .get(&key)
359 .and_then(|entries| entries.iter().find(|e| e.type_id == type_id))
360 .map(|e| e.data)
361 .unwrap_or(std::ptr::null_mut())
362}