Skip to main content

qtbridge_runtime/
qmetainfo.rs

1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4use std::any::TypeId;
5use std::cell::RefCell;
6use std::collections::HashMap;
7use crate::qproxies::QCppProxy;
8use crate::{DynamicMetaObjectBuilder, DynamicMetaObjectData};
9
10#[cfg(doc)]
11use qtbridge_type_lib::QMetaObject;
12
13/// Extends a C++ QObject's static meta-object with signals, slots, and properties
14/// defined on the Rust side, producing a dynamic meta-object that QMetaObject
15/// introspection system can query as if the type were a native QObject subclass.
16///
17/// The associated [`QCppProxy`] provides the parent static [`QMetaObject`] as well
18/// as some other information; implementors (usually qtbridge macros) supply
19/// [`Self::build_dynamic_meta_type`] to declare the Rust-side additions and
20/// [`Self::get_shared_dynamic_meta_object_data`]
21/// to return a cached instance of the built meta-object data. Other functions provide
22/// a reasonable default implementation
23pub trait QMetaInfo : 'static {
24    /// The CppProxy provides the static meta-object
25    type CppProxy: QCppProxy;
26
27    /// The class_name in the Qt meta-object system
28    fn class_name() -> &'static str {
29        std::any::type_name::<Self>()
30    }
31
32    /// This function takes the meta_obj_builder and builds a meta object
33    /// that contains all slots, signals and properties for the respective type.
34    /// This function is usually implemented by a macro.
35    fn build_dynamic_meta_type(meta_obj_builder: std::pin::Pin<&mut DynamicMetaObjectBuilder>);
36
37    /// Return DynamicMetaObjectData containing information
38    /// about signals/slots/properties for given Rust object.
39    fn get_shared_dynamic_meta_object_data() -> &'static DynamicMetaObjectData;
40
41    /// Creates a new `DynamicMetaObjectData` object and returns
42    /// a raw pointer to the heap-allocated object.
43    /// Ownership is not managed internally; the caller is responsible for it.
44    fn create_dynamic_meta_object_data_for_type() -> *const DynamicMetaObjectData {
45        let mut builder = crate::create_dynamic_meta_object_builder(
46            Self::class_name(),
47            Self::CppProxy::get_static_meta_object());
48        Self::build_dynamic_meta_type(builder.pin_mut());
49        builder.pin_mut()
50            .take_dynamic_metaobject_data()
51    }
52}
53
54pub fn dynamic_meta_object_data_for_generic<T: QMetaInfo + ?Sized>() -> &'static DynamicMetaObjectData {
55    thread_local!(static DYNAMIC_META_MAP: RefCell<HashMap<TypeId, *const DynamicMetaObjectData>> =
56        RefCell::new(HashMap::new()));
57
58    let type_id = TypeId::of::<T>();
59    {
60        let meta_data_ptr = DYNAMIC_META_MAP.with_borrow(|dynamic_meta_builder_map| {
61            dynamic_meta_builder_map.get(&type_id)
62                .copied()
63                .unwrap_or_default()
64        });
65        if let Some(meta_data_ref) = unsafe { meta_data_ptr.as_ref() } {
66            return meta_data_ref;
67        }
68    }
69
70    let meta_data_ptr = T::create_dynamic_meta_object_data_for_type();
71    let meta_data_ref = unsafe { meta_data_ptr.as_ref() }.unwrap();
72    DYNAMIC_META_MAP.with_borrow_mut(|dynamic_meta_builder_map| {
73        dynamic_meta_builder_map.insert(type_id, meta_data_ptr);
74    });
75
76    meta_data_ref
77}