uika_runtime/
reify_registry.rs1use std::collections::HashMap;
10use std::sync::{Arc, Mutex, OnceLock, RwLock};
11
12pub struct ClassRegistration {
18 pub register: fn(&uika_ffi::UikaApiTable),
19 pub finalize: fn(&uika_ffi::UikaApiTable),
20}
21inventory::collect!(ClassRegistration);
22
23pub struct ClassFunctionRegistration {
25 pub register_functions: fn(&uika_ffi::UikaApiTable),
26}
27inventory::collect!(ClassFunctionRegistration);
28
29pub fn register_all_from_inventory(table: &uika_ffi::UikaApiTable) {
31 let mut class_count = 0u32;
32 for reg in inventory::iter::<ClassRegistration> {
33 (reg.register)(table);
34 class_count += 1;
35 }
36 let mut func_reg_count = 0u32;
37 for freg in inventory::iter::<ClassFunctionRegistration> {
38 (freg.register_functions)(table);
39 func_reg_count += 1;
40 }
41 for reg in inventory::iter::<ClassRegistration> {
42 (reg.finalize)(table);
43 }
44
45 if !table.logging.is_null() {
47 let total_funcs = func_registry().read().unwrap().len();
48 let msg = format!(
49 "[Uika] register_all_from_inventory: {} classes, {} impl blocks, {} function callbacks",
50 class_count, func_reg_count, total_funcs,
51 );
52 let bytes = msg.as_bytes();
53 unsafe {
54 ((*table.logging).log)(0, bytes.as_ptr(), bytes.len() as u32);
55 }
56 }
57}
58
59use uika_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
72type ReifyFunctionCallback = Arc<dyn Fn(UObjectHandle, *mut u8, *mut u8) + Send + Sync>;
77
78static TYPE_REGISTRY: OnceLock<Mutex<HashMap<u64, RustTypeInfo>>> = OnceLock::new();
83static FUNC_REGISTRY: OnceLock<RwLock<Vec<ReifyFunctionCallback>>> = OnceLock::new();
84static INSTANCE_DATA: OnceLock<RwLock<HashMap<usize, InstanceEntry>>> = OnceLock::new();
85
86struct InstanceEntry {
87 data: *mut u8,
88 type_id: u64,
89}
90
91unsafe impl Send for InstanceEntry {}
93unsafe impl Sync for InstanceEntry {}
94
95fn type_registry() -> &'static Mutex<HashMap<u64, RustTypeInfo>> {
96 TYPE_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
97}
98
99fn func_registry() -> &'static RwLock<Vec<ReifyFunctionCallback>> {
100 FUNC_REGISTRY.get_or_init(|| RwLock::new(Vec::new()))
101}
102
103fn instance_data() -> &'static RwLock<HashMap<usize, InstanceEntry>> {
104 INSTANCE_DATA.get_or_init(|| RwLock::new(HashMap::new()))
105}
106
107pub fn register_type(type_id: u64, info: RustTypeInfo) {
113 type_registry()
114 .lock()
115 .unwrap()
116 .insert(type_id, info);
117}
118
119pub fn register_function<F>(f: F) -> u64
125where
126 F: Fn(UObjectHandle, *mut u8, *mut u8) + Send + Sync + 'static,
127{
128 let mut vec = func_registry().write().unwrap();
129 let id = vec.len() as u64;
130 vec.push(Arc::new(f));
131 id
132}
133
134pub fn construct_instance(obj: UObjectHandle, type_id: u64) {
141 let types = type_registry().lock().unwrap();
142 let Some(info) = types.get(&type_id) else {
143 if crate::api::is_api_initialized() {
145 let msg = format!("[Uika] construct_instance: unknown type_id {type_id}");
146 let bytes = msg.as_bytes();
147 unsafe {
148 let api = crate::api::api();
149 ((*api.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.0 as usize;
158 instance_data()
159 .write()
160 .unwrap()
161 .insert(key, InstanceEntry { data, type_id });
162}
163
164pub fn drop_instance(obj: UObjectHandle, _type_id: u64) {
167 let key = obj.0 as usize;
168 let entry = instance_data().write().unwrap().remove(&key);
169
170 if let Some(entry) = entry {
171 let types = type_registry().lock().unwrap();
172 if let Some(info) = types.get(&entry.type_id) {
173 unsafe {
174 (info.drop_fn)(entry.data);
175 }
176 }
177 }
178}
179
180pub fn invoke_function(callback_id: u64, obj: UObjectHandle, params: *mut u8) {
183 let key = obj.0 as usize;
184
185 let rust_data = instance_data()
187 .read()
188 .unwrap()
189 .get(&key)
190 .map(|e| e.data)
191 .unwrap_or(std::ptr::null_mut());
192
193 let func = {
197 let vec = func_registry().read().unwrap();
198 vec.get(callback_id as usize).cloned()
199 };
200
201 if let Some(func) = func {
202 func(obj, rust_data, params);
203 } else if crate::api::is_api_initialized() {
204 let vec_len = func_registry().read().unwrap().len();
205 let msg = format!(
206 "[Uika] invoke_function: callback_id {} not found (registry size = {})",
207 callback_id, vec_len,
208 );
209 let bytes = msg.as_bytes();
210 unsafe {
211 let api = crate::api::api();
212 ((*api.logging).log)(1, bytes.as_ptr(), bytes.len() as u32);
213 }
214 }
215}
216
217pub fn clear_all() {
220 if let Some(instances) = INSTANCE_DATA.get() {
222 let mut map = instances.write().unwrap();
223 let types = type_registry().lock().unwrap();
224 for (_, entry) in map.drain() {
225 if let Some(info) = types.get(&entry.type_id) {
226 unsafe {
227 (info.drop_fn)(entry.data);
228 }
229 }
230 }
231 drop(types);
232 }
233 if let Some(funcs) = FUNC_REGISTRY.get() {
235 funcs.write().unwrap().clear();
236 }
237 if let Some(types) = TYPE_REGISTRY.get() {
239 types.lock().unwrap().clear();
240 }
241}
242
243pub fn get_instance_data(obj: UObjectHandle) -> *mut u8 {
246 let key = obj.0 as usize;
247 instance_data()
248 .read()
249 .unwrap()
250 .get(&key)
251 .map(|e| e.data)
252 .unwrap_or(std::ptr::null_mut())
253}