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