qtbridge_runtime/
qml_register.rs1use std::rc::Rc;
5use std::cell::RefCell;
6
7use crate::QObjectHolder;
8use crate::QMetaInfo;
9use crate::qqmllistproperty::{list_append, list_count, list_at, list_clear};
10use crate::qproxies::QCppProxy;
11use crate::qproxies::ConstructionMode;
12use qtbridge_type_lib::QObject;
13use qtbridge_type_lib::QMetaType;
14use qtbridge_type_lib::QMetaTypeGet;
15use qtbridge_type_lib::QMetaTypeInterface;
16use qtbridge_type_lib::{QVariant, list_property_to_qvariant};
17
18pub trait QmlRegister : QMetaTypeGet + QObjectHolder + Default
19{
20 const URI: &str;
21 const ELEMENT_NAME: &str;
22 const MINOR_VERSION: u8;
23 const MAJOR_VERSION: u8;
24 const IS_SINGLETON: bool;
25
26 fn get_list_qmetatype() -> QMetaType {
27 use std::collections::HashMap;
30 thread_local!(static LIST_IFACE_MAP: RefCell<HashMap<i32, *const QMetaTypeInterface>>
31 = RefCell::new(HashMap::new()));
32
33 let element = <Self as QMetaTypeGet>::get_qmetatype();
34 let key = element.id();
35
36 let existing = LIST_IFACE_MAP.with_borrow(|m| m.get(&key).copied().unwrap_or_default());
37 let iface = if existing.is_null() {
38 let leaked = std::ptr::from_ref(Box::leak(Box::new(
39 QMetaTypeInterface::qqml_list_property_for(&element)
40 )));
41 LIST_IFACE_MAP.with_borrow_mut(|m| m.insert(key, leaked));
42 leaked
43 } else {
44 existing
45 };
46 QMetaType::new_with_interface(iface)
47 }
48
49 fn list_to_qvariant<Owner, Notify>(owner: &Owner, store: &Vec<Rc<RefCell<Self>>>, _notify: Notify) -> QVariant
50 where
51 Owner: QObjectHolder,
52 Notify: Fn(&mut Owner) + 'static,
53 {
54 debug_assert_eq!(std::mem::size_of::<Notify>(), 0, "Notify must be a zero-sized type");
55 let qobject = owner.get_qobject_ptr();
56 let base = owner as *const Owner as *const u8;
57 let field = store as *const _ as *const u8;
58 let store_offset = unsafe { field.offset_from(base) } as usize;
63 unsafe { list_property_to_qvariant(
64 &Self::get_list_qmetatype(),
65 qobject,
66 store_offset as *mut u8,
67 (list_append::<Owner, Self, Notify> as *const ()).addr(),
68 (list_count::<Owner, Self> as *const ()).addr(),
69 (list_at::<Owner, Self> as *const ()).addr(),
70 (list_clear::<Owner, Self, Notify> as *const ()).addr(),
71 ) }
72 }
73
74 fn register() {
75 let meta_obj_data = <Self as QMetaInfo>::get_shared_dynamic_meta_object_data();
76 let meta_obj = unsafe {
77 meta_obj_data
78 .get_meta_object()
79 .as_ref()
80 .expect("Failed to get QMetaObject")
81 };
82
83 if Self::IS_SINGLETON {
84 qtbridge_type_lib::qml_register_singleton(
85 <Self as QMetaTypeGet>::get_qmetatype(),
86 monomorphize_singleton_ctor::<Self>(),
87 Self::URI.as_bytes(),
88 Self::MAJOR_VERSION,
89 Self::MINOR_VERSION,
90 Self::ELEMENT_NAME.as_bytes(),
91 meta_obj,
92 )
93 } else {
94 let list_metatype = Self::get_list_qmetatype();
95 list_metatype.register_type();
96
97 qtbridge_type_lib::qml_register_element(
98 <Self as QMetaTypeGet>::get_qmetatype(),
99 list_metatype,
100 <<Self as QMetaInfo>::CppProxy as QCppProxy>::get_size() as u32,
101 <<Self as QMetaInfo>::CppProxy as QCppProxy>::parser_status_cast(),
102 monomorphize_element_ctor::<Self>(),
103 Self::URI.as_bytes(),
104 Self::MAJOR_VERSION,
105 Self::MINOR_VERSION,
106 Self::ELEMENT_NAME.as_bytes(),
107 meta_obj,
108 );
109 }
110 }
111}
112
113fn element_ctor<T: QmlRegister>(addr: *mut u8, _userdata: *mut u8) {
114 let instance = std::rc::Rc::new(std::cell::RefCell::new(T::default()));
115 T::register_instance_in_map(instance.clone(), ConstructionMode::AtAddress(addr));
116}
117
118fn singleton_ctor<T: QmlRegister>() -> *mut QObject {
119 let instance = std::rc::Rc::new(std::cell::RefCell::new(T::default()));
120 T::register_instance_in_map(instance.clone(), ConstructionMode::Strong);
121 instance.borrow().get_qobject_ptr()
122}
123
124fn monomorphize_element_ctor<T: QmlRegister>() -> usize {
125 extern "C" fn default_ctor<T: QmlRegister>(addr: *mut u8, userdata: *mut u8) {
126 element_ctor::<T>(addr, userdata)
127 }
128 default_ctor::<T> as *const () as usize
129}
130
131fn monomorphize_singleton_ctor<T: QmlRegister>() -> usize {
132 extern "C" fn default_ctor<T: QmlRegister>() -> *mut QObject {
133 singleton_ctor::<T>()
134 }
135 default_ctor::<T> as *const () as usize
136}