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