qtbridge_runtime/
qobjectholder.rs1use std::cell::RefCell;
5use std::ptr::NonNull;
6use std::rc::Rc;
7
8use qtbridge_type_lib::{QMetaType, QObject};
9use qtbridge_type_lib::core::qobject;
10use crate::qproxies::{QCppProxy, QRustProxy, PlacementAddress, AdapterUpcast};
11use crate::registry::Owner;
12use crate::rustobjectgetter::get_rust_proxy;
13use crate::{DispatchMetaCall, DynamicMetaObjectData, QMetaInfo};
14
15pub type CppProxyOf<T> = <<T as QObjectHolder>::ProxyRust as QRustProxy>::ProxyCppType;
17
18#[doc(hidden)]
20pub unsafe trait QObjectHolder : DispatchMetaCall + QMetaInfo + Sized + 'static
21where
22 Self::ProxyRust: AdapterUpcast<Self>,
23 Self::ProxyRust: QRustProxy,
24{
25 type ProxyRust;
30
31 fn create_dynamic_meta_object_data_for_type() -> *const DynamicMetaObjectData {
35 let mut builder = crate::create_dynamic_meta_object_builder(
36 Self::class_name(),
37 <CppProxyOf<Self>>::get_static_meta_object());
38 Self::build_dynamic_meta_type(builder.pin_mut());
39 builder.pin_mut()
40 .take_dynamic_metaobject_data()
41 }
42
43 fn get_shared_dynamic_meta_object_data() -> &'static DynamicMetaObjectData {
49 dynamic_meta_object_data_for_generic::<Self>()
50 }
51
52 fn get_qobject_ptr_qmetatype() -> QMetaType {
57 let iface = crate::qmetatypeforqobject::ptr_interface_for_generic::<Self>();
58 QMetaType::new_with_interface(iface)
59 }
60
61 fn try_get_rust_proxy_ptr_from_ptr(rust_obj_ptr: *const Self) -> Option<*mut Self::ProxyRust> {
64 let proxy_ptr = crate::registry::proxy_ptr(rust_obj_ptr.cast::<u8>());
65 NonNull::new(proxy_ptr as *mut Self::ProxyRust).map(|nn| nn.as_ptr())
66 }
67
68 fn try_get_rust_proxy_ptr(&self) -> Option<*mut Self::ProxyRust> {
71 Self::try_get_rust_proxy_ptr_from_ptr(std::ptr::from_ref(self))
72 }
73
74 fn get_qobject_ptr(&self) -> *mut QObject {
76 let Some(proxy_ptr) = Self::try_get_rust_proxy_ptr(self) else {
77 return std::ptr::null_mut()
78 };
79 let rust_proxy = unsafe { &*proxy_ptr };
80 let cpp_proxy = rust_proxy.get_cpp_proxy();
81 cpp_proxy as *mut QObject
82 }
83
84 fn rc_ref_cell_to_qobject(self_obj: &Rc<RefCell<Self>>) -> *const QObject {
87 let proxy_ptr = Self::try_get_rust_proxy_ptr_from_ptr(self_obj.as_ptr())
88 .unwrap_or_else( || {
89 Self::register_instance(self_obj.clone(), Owner::RustRegistry);
90 Self::try_get_rust_proxy_ptr_from_ptr(self_obj.as_ptr())
91 .expect("Failed to attach and register a proxy")
92 }
93 );
94 let rust_proxy = unsafe { &*proxy_ptr };
95 rust_proxy.get_cpp_proxy() as *mut QObject
96 }
97
98 unsafe fn qobject_to_rc_ref_cell(qobj_ptr: *const QObject) -> Rc<RefCell<Self>>
100 {
101 let qobj_ref = unsafe { qobj_ptr.as_ref() }
102 .expect("Input QObject is null");
103 let proxy_ptr = get_rust_proxy(qobj_ref);
104 debug_assert!(!proxy_ptr.is_null());
105
106 let qobj_meta_obj = unsafe { qobject::meta_object(qobj_ref).as_ref() };
114 let self_meta_obj = unsafe {
115 Self::get_shared_dynamic_meta_object_data().get_meta_object().as_ref()
116 };
117 let inherits = match (qobj_meta_obj, self_meta_obj) {
118 (Some(d), Some(b)) => d.inherits(b),
119 _ => false,
120 };
121 if !inherits {
122 let qobj_name = qobj_meta_obj.map_or("<null>".into(), |m| m.meta_type().name());
123 let self_name = self_meta_obj.map_or("<null>".into(), |m| m.meta_type().name());
124 panic!("Value of wrong type: '{qobj_name}' is not a '{self_name}' (nor a subclass)")
125 }
126
127 let proxy = unsafe { &*(proxy_ptr as *const Self::ProxyRust) };
128 let rc_adapter = proxy.get_rust_object_rc();
129
130 crate::registry::repin(rc_adapter.as_ptr() as *const u8);
133
134 let raw_ref_cell = Rc::into_raw(rc_adapter).cast();
143 unsafe { Rc::from_raw(raw_ref_cell) }
144 }
145
146 #[doc(hidden)]
150 fn register_instance(rust_obj_rc: Rc<RefCell<Self>>, owner: Owner) {
151 unsafe { Self::register_instance_at(rust_obj_rc, owner, None) }
153 }
154
155 #[doc(hidden)]
168 unsafe fn register_instance_at(
169 rust_obj_rc: Rc<RefCell<Self>>, owner: Owner, at_address: Option<PlacementAddress>,
170 ) {
171 let key = (*rust_obj_rc).as_ptr() as *const u8;
172 let keep: Rc<RefCell<Self>> = rust_obj_rc.clone();
173 let dyn_rc = <Self::ProxyRust as AdapterUpcast<Self>>::upcast(rust_obj_rc);
174 let dynamic_meta = Self::get_shared_dynamic_meta_object_data();
175 let proxy = Self::ProxyRust::new(&dyn_rc, dynamic_meta, at_address, Box::new(move || {
176 crate::registry::unregister(key);
177 }));
178 let qobject = unsafe { &*proxy }.get_cpp_proxy() as *mut QObject;
180 crate::registry::register(key, proxy as *const u8, qobject,
181 Rc::<RefCell<Self>>::downgrade(&keep), owner);
182 }
183}
184
185pub fn dynamic_meta_object_data_for_generic<T: QObjectHolder>() -> &'static DynamicMetaObjectData
188where
189 T::ProxyRust: crate::qproxies::AdapterUpcast<T>,
190{
191 use std::any::TypeId;
192 use std::collections::HashMap;
193 thread_local!(static DYNAMIC_META_MAP: RefCell<HashMap<TypeId, *const DynamicMetaObjectData>> =
194 RefCell::new(HashMap::new()));
195
196 let type_id = TypeId::of::<T>();
197 {
198 let meta_data_ptr = DYNAMIC_META_MAP.with_borrow(|dynamic_meta_builder_map| {
199 dynamic_meta_builder_map.get(&type_id)
200 .copied()
201 .unwrap_or_default()
202 });
203 if let Some(meta_data_ref) = unsafe { meta_data_ptr.as_ref() } {
204 return meta_data_ref;
205 }
206 }
207
208 let meta_data_ptr = T::create_dynamic_meta_object_data_for_type();
209 let meta_data_ref = unsafe { meta_data_ptr.as_ref() }.unwrap();
210 DYNAMIC_META_MAP.with_borrow_mut(|dynamic_meta_builder_map| {
211 dynamic_meta_builder_map.insert(type_id, meta_data_ptr);
212 });
213
214 meta_data_ref
215}