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, list_property_interface_for, list_property_to_qvariant};
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;
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)
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, &'static 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());
46 let iface = existing.unwrap_or_else(|| {
47 let leaked: &'static QMetaTypeInterface = Box::leak(Box::new(
48 list_property_interface_for(&element)
49 ));
50 LIST_IFACE_MAP.with_borrow_mut(|m| m.insert(key, leaked));
51 leaked
52 });
53 QMetaType::new_with_interface(iface)
54 }
55
56 unsafe fn list_to_qvariant<Owner, Notify>(owner: &Owner, store: &Vec<Rc<RefCell<Self>>>, _notify: Notify) -> QVariant
63 where
64 Owner: QObjectHolder,
65 Notify: Fn(&mut Owner) + 'static,
66 {
67 debug_assert_eq!(std::mem::size_of::<Notify>(), 0, "Notify must be a zero-sized type");
68 let qobject = owner.get_qobject_ptr();
69 let base = owner as *const Owner as *const u8;
70 let field = store as *const _ as *const u8;
71 let store_offset = unsafe { field.offset_from(base) } as usize;
76 unsafe { list_property_to_qvariant(
77 &Self::get_list_qmetatype(),
78 qobject,
79 store_offset as *mut u8,
80 (list_append::<Owner, Self, Notify> as *const ()).addr(),
81 (list_count::<Owner, Self> as *const ()).addr(),
82 (list_at::<Owner, Self> as *const ()).addr(),
83 (list_clear::<Owner, Self, Notify> as *const ()).addr(),
84 ) }
85 }
86
87 fn register() {
88 let meta_obj_data = <Self as QObjectHolder>::get_shared_dynamic_meta_object_data();
89 let meta_obj = unsafe {
90 meta_obj_data
91 .get_meta_object()
92 .as_ref()
93 .expect("Failed to get QMetaObject")
94 };
95
96 if Self::IS_SINGLETON {
97 unsafe { crate::qmlprivate::qml_register_singleton(
99 <Self as QObjectHolder>::get_qobject_ptr_qmetatype(),
100 monomorphize_singleton_ctor::<Self>(),
101 Self::URI.as_bytes(),
102 Self::MAJOR_VERSION,
103 Self::MINOR_VERSION,
104 Self::ELEMENT_NAME.as_bytes(),
105 meta_obj,
106 ) }
107 } else {
108 let list_metatype = Self::get_list_qmetatype();
109 list_metatype.register_type();
110
111 unsafe { crate::qmlprivate::qml_register_element(
114 <Self as QObjectHolder>::get_qobject_ptr_qmetatype(),
115 list_metatype,
116 <CppProxyOf<Self> as QCppProxy>::get_size() as u32,
117 <CppProxyOf<Self> as QCppProxy>::parser_status_cast(),
118 monomorphize_element_ctor::<Self>(),
119 Self::URI.as_bytes(),
120 Self::MAJOR_VERSION,
121 Self::MINOR_VERSION,
122 Self::ELEMENT_NAME.as_bytes(),
123 meta_obj,
124 ) };
125 }
126 }
127}
128
129unsafe fn element_ctor<T: QmlElement>(addr: *mut u8, _userdata: *mut u8) {
130 let instance = std::rc::Rc::new(std::cell::RefCell::new(T::default()));
131 unsafe { T::register_instance_at(instance.clone(), Owner::Engine, Some(addr)) };
132}
133
134fn singleton_ctor<T: QmlElement>() -> *mut QObject {
135 let instance = std::rc::Rc::new(std::cell::RefCell::new(T::default()));
136 T::register_instance(instance.clone(), Owner::Engine);
137 instance.borrow().get_qobject_ptr()
138}
139
140fn monomorphize_element_ctor<T: QmlElement>() -> usize {
141 extern "C" fn default_ctor<T: QmlElement>(addr: *mut u8, userdata: *mut u8) {
142 unsafe { element_ctor::<T>(addr, userdata) }
143 }
144 default_ctor::<T> as *const () as usize
145}
146
147fn monomorphize_singleton_ctor<T: QmlElement>() -> usize {
148 extern "C" fn default_ctor<T: QmlElement>() -> *mut QObject {
149 singleton_ctor::<T>()
150 }
151 default_ctor::<T> as *const () as usize
152}