qtbridge_runtime/qproxies.rs
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4
5use qtbridge_type_lib::QMetaObject;
6use crate::DispatchMetaCall;
7use crate::DynamicMetaObjectData;
8use std::rc::Rc;
9use std::cell::RefCell;
10use std::pin::Pin;
11
12pub enum ConstructionMode {
13 Strong,
14 Weak,
15 AtAddress(*mut u8),
16}
17
18
19/// `QCppProxy` defines what a C++ proxy to a QObject (C++) must implement.
20///
21/// This includes access to the C++ static meta-object, which is then extended
22/// on the Rust side to create a dynamic meta-object.
23pub trait QCppProxy {
24 type ProxyRustType: QRustProxy;
25 fn get_static_meta_object() -> &'static QMetaObject;
26 fn get_size() -> usize;
27 fn get_align() -> usize;
28 fn parser_status_cast() -> i32;
29 unsafe fn create(rust_proxy: *mut Self::ProxyRustType, metaobject: &'static DynamicMetaObjectData) -> *mut Self;
30 unsafe fn create_at(rust_proxy: *mut Self::ProxyRustType, metaobject: &'static DynamicMetaObjectData, addr: *mut u8) -> *mut Self;
31 fn emit_signal(self: Pin<&mut Self>, signal_name: &str, argv: &[*const u8]);
32}
33
34/// `QRustProxy` defines the Rust-side bridge object that binds:
35///
36/// - A Rust object stored in `Rc<RefCell<dyn _>>`
37/// - A corresponding C++ QObject-based proxy
38///
39/// Implementations of this trait are the concrete glue layer between
40/// Rust and Qt, usually using Cxx.
41///
42/// # Purpose
43///
44/// A `QRustProxy` implementation:
45///
46/// - Stores a raw pointer to the C++ proxy (`cpp_proxy`)
47/// - Stores access to the Rust object through `RustObjAccess<dyn _>` (`rust_obj`)
48/// - Coordinates destruction, layout and Qt meta-object information
49/// - Forwards all foreign function calls to the C++ proxy
50///
51/// Typical structure:
52///
53/// ```rust, ignore
54/// pub struct QObjectProxyRust {
55/// cpp_proxy: *mut QObjectProxyCpp,
56/// rust_obj: RustObjAccess<dyn QObjectProxyGet>,
57/// on_drop: fn(rust_obj: *const u8),
58/// }
59/// ```
60///
61/// Where:
62///
63/// - `cpp_proxy` points to the actual C++ QObject subclass.
64/// - `rust_obj` wraps access to the users rust object.
65/// - `on_drop` cleaning up memory.
66///
67/// # Lifetime and Ownership
68///
69/// A `QRustProxy` instance is heap-allocated and owned through a raw pointer, because its
70/// lifetime is jointly managed with C++ code and the C++ side requires a stable, non-movable
71/// address.
72///
73/// Destruction is always initiated from the C++ side: the paired `CppProxy` destructor calls
74/// `GenericRustProxy::drop_self`, which converts the raw pointer back to a `Box`, invokes
75/// the stored `on_drop` callback, and then drops this instance along with its reference to the
76/// Rust object.
77///
78/// The reference held to the user's Rust object is either strong (`Rc`) or weak (`Weak`),
79/// depending on the [`ConstructionMode`] passed to [`QRustProxy::new`]:
80///
81/// - `Strong` / `AtAddress` - proxy holds a strong `Rc`; the proxy pair keeps the Rust object
82/// alive (QML-created / OwnedByQml path).
83/// - `Weak` - proxy holds only a `Weak` reference; the Rust `Rc` controls the struct's lifetime
84/// (Rust-created / OwnedByRust path).
85///
86/// # Associated Types
87///
88/// ## `ProxyCppType`
89///
90/// The concrete C++ proxy type. Has to implement [`QCppProxy`].
91///
92/// ## `AdapterType`
93///
94/// A wrapper trait for the interface trait that QtBridge users implement. This wrapper
95/// is required because not all traits can be used with dyn and are thus incompatible with
96/// `RustObjAccess` (See "object safety" or "dyn compatibility").
97///
98pub trait QRustProxy {
99 type ProxyCppType: QCppProxy<ProxyRustType = Self>;
100 type AdapterType: DispatchMetaCall + ?Sized;
101
102 /// Creates a new instance of this struct on the heap and returns a raw pointer to it.
103 ///
104 /// Initializes the proxy pair by:
105 /// - Creating a `RustObjAccess` wrapper for `rust_obj`, holding either a strong or weak
106 /// reference depending on `construction` (see [`ConstructionMode`]).
107 /// - Constructing the paired C++ proxy and binding it to this Rust-side proxy.
108 /// - Storing `on_drop` for invocation when the C++ proxy is eventually destroyed.
109 fn new(rust_obj: &Rc<RefCell<Self::AdapterType>>, metaobject: &'static DynamicMetaObjectData, construction: ConstructionMode, on_drop: Box<dyn FnOnce() + 'static>) -> *mut Self;
110 fn get_cpp_proxy(&self) -> *const Self::ProxyCppType;
111 fn get_cpp_proxy_mut(&self) -> *mut Self::ProxyCppType;
112 fn emit_signal(&self, mut_ref: &mut Self::AdapterType, signal_name: &str, argv: &[*const u8]);
113 fn with_rust_ref<R, F: FnOnce(&Self::AdapterType) -> R>(&self, f: F) -> R;
114 fn with_rust_ref_mut<R, F: FnOnce(&mut Self::AdapterType) -> R>(&self, f: F) -> R;
115
116 /// Returns an owned handle to the Rust object behind this proxy, or `None`
117 /// if it has already been dropped (the proxy may outlive a weakly-held
118 /// object). The handle is typed as the adapter trait object; recovering the
119 /// concrete type requires a checked reinterpret (see
120 /// `QObjectHolder::qobject_to_rc_ref_cell`).
121 fn get_rust_object_rc(&self) -> Option<Rc<RefCell<Self::AdapterType>>>;
122}