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}
32inventory::collect!(ClassRegistration);
33
34pub struct StructRegistration {
36 pub create: fn(),
38 pub register: fn(),
41 pub finalize: fn(),
43}
44inventory::collect!(StructRegistration);
45
46pub struct ClassFunctionRegistration {
49 pub type_id: u64,
51 pub register_functions: fn(),
52 pub class_defaults: Option<fn()>,
53}
54inventory::collect!(ClassFunctionRegistration);
55
56pub trait ClassDefaultsOutcome {
59 fn report(self, class: &str);
60}
61
62impl ClassDefaultsOutcome for () {
63 fn report(self, _class: &str) {}
64}
65
66impl ClassDefaultsOutcome for crate::error::RustealResult<()> {
67 fn report(self, class: &str) {
68 if let Err(e) = self {
69 let msg = format!("[Rusteal] {class}: class defaults failed: {e}");
70 let bytes = msg.as_bytes();
71 unsafe {
72 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
73 }
74 }
75 }
76}
77
78pub fn register_all_from_inventory() {
85 let mut pending: Vec<&ClassRegistration> = inventory::iter::<ClassRegistration>.into_iter().collect();
86 let class_count = pending.len() as u32;
87 let mut ordered: Vec<&ClassRegistration> = Vec::with_capacity(pending.len());
88 loop {
89 let before = pending.len();
90 pending.retain(|reg| {
91 if (reg.create)(false) {
92 ordered.push(reg);
93 false
94 } else {
95 true
96 }
97 });
98 if pending.is_empty() || pending.len() == before {
99 break;
100 }
101 }
102 for reg in pending {
104 (reg.create)(true);
105 }
106
107 for sreg in inventory::iter::<StructRegistration> {
110 (sreg.create)();
111 }
112 for sreg in inventory::iter::<StructRegistration> {
113 (sreg.register)();
114 }
115 for sreg in inventory::iter::<StructRegistration> {
116 (sreg.finalize)();
117 }
118
119 for reg in &ordered {
120 (reg.register)();
121 }
122 let mut func_reg_count = 0u32;
123 for freg in inventory::iter::<ClassFunctionRegistration> {
124 (freg.register_functions)();
125 func_reg_count += 1;
126 }
127 for reg in &ordered {
128 (reg.finalize)();
129 for freg in inventory::iter::<ClassFunctionRegistration> {
130 if freg.type_id == reg.type_id
131 && let Some(class_defaults) = freg.class_defaults
132 {
133 class_defaults();
134 }
135 }
136 }
137
138 let total_funcs = read_or_recover(func_registry()).len();
140 let msg = format!(
141 "[Rusteal] register_all_from_inventory: {} classes, {} impl blocks, {} function callbacks",
142 class_count, func_reg_count, total_funcs,
143 );
144 let bytes = msg.as_bytes();
145 unsafe {
146 crate::ffi_dispatch::logging_log(0, bytes.as_ptr(), bytes.len() as u32);
147 }
148}
149
150use rusteal_ffi::UObjectHandle;
151
152pub struct RustTypeInfo {
154 pub name: &'static str,
156 pub construct_fn: fn() -> *mut u8,
159 pub drop_fn: unsafe fn(*mut u8),
161}
162
163use crate::ffi_dispatch::NativePtr;
164
165type ReifyFunctionCallback = Arc<dyn Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync>;
171
172struct FunctionEntry {
174 callback: ReifyFunctionCallback,
175 type_id: u64,
176}
177
178static TYPE_REGISTRY: OnceLock<Mutex<HashMap<u64, RustTypeInfo>>> = OnceLock::new();
183static FUNC_REGISTRY: OnceLock<RwLock<Vec<FunctionEntry>>> = OnceLock::new();
184static INSTANCE_DATA: OnceLock<RwLock<HashMap<u64, Vec<InstanceEntry>>>> = OnceLock::new();
185
186struct InstanceEntry {
187 data: *mut u8,
188 type_id: u64,
189}
190
191unsafe impl Send for InstanceEntry {}
193unsafe impl Sync for InstanceEntry {}
194
195fn type_registry() -> &'static Mutex<HashMap<u64, RustTypeInfo>> {
196 TYPE_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
197}
198
199fn func_registry() -> &'static RwLock<Vec<FunctionEntry>> {
200 FUNC_REGISTRY.get_or_init(|| RwLock::new(Vec::new()))
201}
202
203fn instance_data() -> &'static RwLock<HashMap<u64, Vec<InstanceEntry>>> {
204 INSTANCE_DATA.get_or_init(|| RwLock::new(HashMap::new()))
205}
206
207pub fn register_type(type_id: u64, info: RustTypeInfo) {
213 lock_or_recover(type_registry())
214 .insert(type_id, info);
215}
216
217pub fn register_function<F>(type_id: u64, f: F) -> u64
224where
225 F: Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync + 'static,
226{
227 let mut vec = write_or_recover(func_registry());
228 let id = vec.len() as u64;
229 vec.push(FunctionEntry { callback: Arc::new(f), type_id });
230 id
231}
232
233pub fn construct_instance(obj: UObjectHandle, type_id: u64) {
241 let types = lock_or_recover(type_registry());
242 let Some(info) = types.get(&type_id) else {
243 if crate::api::is_api_initialized() {
245 let msg = format!("[Rusteal] construct_instance: unknown type_id {type_id}");
246 let bytes = msg.as_bytes();
247 unsafe {
248 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
249 }
250 }
251 return;
252 };
253 let data = (info.construct_fn)();
254 drop(types); let key = obj.to_addr();
257 let old = {
258 let mut map = write_or_recover(instance_data());
259 let entries = map.entry(key).or_default();
260 match entries.iter_mut().find(|e| e.type_id == type_id) {
261 Some(entry) => Some(std::mem::replace(&mut entry.data, data)),
262 None => {
263 entries.push(InstanceEntry { data, type_id });
264 None
265 }
266 }
267 };
268 if let Some(old) = old {
270 drop_data(type_id, old);
271 }
272}
273
274fn drop_data(type_id: u64, data: *mut u8) {
275 let types = lock_or_recover(type_registry());
276 if let Some(info) = types.get(&type_id) {
277 unsafe {
278 (info.drop_fn)(data);
279 }
280 }
281}
282
283pub fn drop_instance(obj: UObjectHandle, _type_id: u64) {
287 let key = obj.to_addr();
288 let entries = write_or_recover(instance_data()).remove(&key);
289 for entry in entries.into_iter().flatten() {
290 drop_data(entry.type_id, entry.data);
291 }
292}
293
294pub fn invoke_function(callback_id: u64, obj: UObjectHandle, params: NativePtr) {
297 let func = {
301 let vec = read_or_recover(func_registry());
302 vec.get(callback_id as usize)
303 .map(|entry| (entry.callback.clone(), entry.type_id))
304 };
305
306 if let Some((func, type_id)) = func {
307 let rust_data = get_instance_data(obj, type_id);
309 func(obj, rust_data, params);
310 } else if crate::api::is_api_initialized() {
311 let vec_len = read_or_recover(func_registry()).len();
312 let msg = format!(
313 "[Rusteal] invoke_function: callback_id {} not found (registry size = {})",
314 callback_id, vec_len,
315 );
316 let bytes = msg.as_bytes();
317 unsafe {
318 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
319 }
320 }
321}
322
323pub fn clear_all() {
326 if let Some(instances) = INSTANCE_DATA.get() {
328 let mut map = write_or_recover(instances);
329 let types = lock_or_recover(type_registry());
330 for entry in map.drain().flat_map(|(_, entries)| entries) {
331 if let Some(info) = types.get(&entry.type_id) {
332 unsafe {
333 (info.drop_fn)(entry.data);
334 }
335 }
336 }
337 drop(types);
338 }
339 if let Some(funcs) = FUNC_REGISTRY.get() {
341 write_or_recover(funcs).clear();
342 }
343 if let Some(types) = TYPE_REGISTRY.get() {
345 lock_or_recover(types).clear();
346 }
347}
348
349pub fn get_instance_data(obj: UObjectHandle, type_id: u64) -> *mut u8 {
352 let key = obj.to_addr();
353 read_or_recover(instance_data())
354 .get(&key)
355 .and_then(|entries| entries.iter().find(|e| e.type_id == type_id))
356 .map(|e| e.data)
357 .unwrap_or(std::ptr::null_mut())
358}