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 {
28 pub register_functions: fn(),
29 pub class_defaults: Option<fn()>,
30}
31inventory::collect!(ClassFunctionRegistration);
32
33pub trait ClassDefaultsOutcome {
36 fn report(self, class: &str);
37}
38
39impl ClassDefaultsOutcome for () {
40 fn report(self, _class: &str) {}
41}
42
43impl ClassDefaultsOutcome for crate::error::RustealResult<()> {
44 fn report(self, class: &str) {
45 if let Err(e) = self {
46 let msg = format!("[Rusteal] {class}: class defaults failed: {e}");
47 let bytes = msg.as_bytes();
48 unsafe {
49 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
50 }
51 }
52 }
53}
54
55pub fn register_all_from_inventory() {
58 let mut class_count = 0u32;
59 for reg in inventory::iter::<ClassRegistration> {
60 (reg.register)();
61 class_count += 1;
62 }
63 let mut func_reg_count = 0u32;
64 for freg in inventory::iter::<ClassFunctionRegistration> {
65 (freg.register_functions)();
66 func_reg_count += 1;
67 }
68 for reg in inventory::iter::<ClassRegistration> {
69 (reg.finalize)();
70 }
71 for freg in inventory::iter::<ClassFunctionRegistration> {
72 if let Some(class_defaults) = freg.class_defaults {
73 class_defaults();
74 }
75 }
76
77 let total_funcs = read_or_recover(func_registry()).len();
79 let msg = format!(
80 "[Rusteal] register_all_from_inventory: {} classes, {} impl blocks, {} function callbacks",
81 class_count, func_reg_count, total_funcs,
82 );
83 let bytes = msg.as_bytes();
84 unsafe {
85 crate::ffi_dispatch::logging_log(0, bytes.as_ptr(), bytes.len() as u32);
86 }
87}
88
89use rusteal_ffi::UObjectHandle;
90
91pub struct RustTypeInfo {
93 pub name: &'static str,
95 pub construct_fn: fn() -> *mut u8,
98 pub drop_fn: unsafe fn(*mut u8),
100}
101
102use crate::ffi_dispatch::NativePtr;
103
104type ReifyFunctionCallback = Arc<dyn Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync>;
110
111static TYPE_REGISTRY: OnceLock<Mutex<HashMap<u64, RustTypeInfo>>> = OnceLock::new();
116static FUNC_REGISTRY: OnceLock<RwLock<Vec<ReifyFunctionCallback>>> = OnceLock::new();
117static INSTANCE_DATA: OnceLock<RwLock<HashMap<u64, InstanceEntry>>> = OnceLock::new();
118
119struct InstanceEntry {
120 data: *mut u8,
121 type_id: u64,
122}
123
124unsafe impl Send for InstanceEntry {}
126unsafe impl Sync for InstanceEntry {}
127
128fn type_registry() -> &'static Mutex<HashMap<u64, RustTypeInfo>> {
129 TYPE_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
130}
131
132fn func_registry() -> &'static RwLock<Vec<ReifyFunctionCallback>> {
133 FUNC_REGISTRY.get_or_init(|| RwLock::new(Vec::new()))
134}
135
136fn instance_data() -> &'static RwLock<HashMap<u64, InstanceEntry>> {
137 INSTANCE_DATA.get_or_init(|| RwLock::new(HashMap::new()))
138}
139
140pub fn register_type(type_id: u64, info: RustTypeInfo) {
146 lock_or_recover(type_registry())
147 .insert(type_id, info);
148}
149
150pub fn register_function<F>(f: F) -> u64
156where
157 F: Fn(UObjectHandle, *mut u8, NativePtr) + Send + Sync + 'static,
158{
159 let mut vec = write_or_recover(func_registry());
160 let id = vec.len() as u64;
161 vec.push(Arc::new(f));
162 id
163}
164
165pub fn construct_instance(obj: UObjectHandle, type_id: u64) {
172 let types = lock_or_recover(type_registry());
173 let Some(info) = types.get(&type_id) else {
174 if crate::api::is_api_initialized() {
176 let msg = format!("[Rusteal] construct_instance: unknown type_id {type_id}");
177 let bytes = msg.as_bytes();
178 unsafe {
179 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
180 }
181 }
182 return;
183 };
184 let data = (info.construct_fn)();
185 drop(types); let key = obj.to_addr();
188 write_or_recover(instance_data())
189 .insert(key, InstanceEntry { data, type_id });
190}
191
192pub fn drop_instance(obj: UObjectHandle, _type_id: u64) {
195 let key = obj.to_addr();
196 let entry = write_or_recover(instance_data()).remove(&key);
197
198 if let Some(entry) = entry {
199 let types = lock_or_recover(type_registry());
200 if let Some(info) = types.get(&entry.type_id) {
201 unsafe {
202 (info.drop_fn)(entry.data);
203 }
204 }
205 }
206}
207
208pub fn invoke_function(callback_id: u64, obj: UObjectHandle, params: NativePtr) {
211 let key = obj.to_addr();
212
213 let rust_data = read_or_recover(instance_data())
215 .get(&key)
216 .map(|e| e.data)
217 .unwrap_or(std::ptr::null_mut());
218
219 let func = {
223 let vec = read_or_recover(func_registry());
224 vec.get(callback_id as usize).cloned()
225 };
226
227 if let Some(func) = func {
228 func(obj, rust_data, params);
229 } else if crate::api::is_api_initialized() {
230 let vec_len = read_or_recover(func_registry()).len();
231 let msg = format!(
232 "[Rusteal] invoke_function: callback_id {} not found (registry size = {})",
233 callback_id, vec_len,
234 );
235 let bytes = msg.as_bytes();
236 unsafe {
237 crate::ffi_dispatch::logging_log(1, bytes.as_ptr(), bytes.len() as u32);
238 }
239 }
240}
241
242pub fn clear_all() {
245 if let Some(instances) = INSTANCE_DATA.get() {
247 let mut map = write_or_recover(instances);
248 let types = lock_or_recover(type_registry());
249 for (_, entry) in map.drain() {
250 if let Some(info) = types.get(&entry.type_id) {
251 unsafe {
252 (info.drop_fn)(entry.data);
253 }
254 }
255 }
256 drop(types);
257 }
258 if let Some(funcs) = FUNC_REGISTRY.get() {
260 write_or_recover(funcs).clear();
261 }
262 if let Some(types) = TYPE_REGISTRY.get() {
264 lock_or_recover(types).clear();
265 }
266}
267
268pub fn get_instance_data(obj: UObjectHandle) -> *mut u8 {
271 let key = obj.to_addr();
272 read_or_recover(instance_data())
273 .get(&key)
274 .map(|e| e.data)
275 .unwrap_or(std::ptr::null_mut())
276}