Skip to main content

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
12
13/// Address of engine-allocated memory in which a C++ proxy is
14/// placement-constructed. QML-created elements pass `Some`; Rust-created
15/// objects pass `None` and allocate on the C++ heap.
16pub type PlacementAddress = *mut u8;
17
18/// `QCppProxy` defines what a C++ proxy to a QObject (C++) must implement.
19///
20/// This includes access to the C++ static meta-object, which is then extended
21/// on the Rust side to create a dynamic meta-object.
22pub trait QCppProxy {
23    type ProxyRustType: QRustProxy;
24    fn get_static_meta_object() -> &'static QMetaObject;
25    fn get_size() -> usize;
26    fn get_align() -> usize;
27    fn parser_status_cast() -> i32;
28    /// # Safety
29    ///
30    /// rust_proxy must be a valid and live pointer to Self::ProxyRustType.
31    /// The QCppProxy must be droped first and will drop rust_proxy in its
32    /// destructor. Ensure that rust_proxy is not droped by anything but QCppProxy.
33    unsafe fn create(rust_proxy: *mut Self::ProxyRustType, metaobject: &'static DynamicMetaObjectData) -> *mut Self;
34    /// # Safety
35    ///
36    /// Same contract as [`QCppProxy::create`].
37    unsafe fn create_at(rust_proxy: *mut Self::ProxyRustType, metaobject: &'static DynamicMetaObjectData, addr: PlacementAddress) -> *mut Self;
38    fn emit_signal(self: Pin<&mut Self>, signal_name: &str, argv: &[*const u8]);
39}
40
41/// `QRustProxy` defines the Rust-side bridge object that binds:
42///
43/// - A Rust object stored in `Rc<RefCell<dyn _>>`
44/// - A corresponding C++ QObject-based proxy
45///
46/// Implementations of this trait are the concrete glue layer between
47/// Rust and Qt, usually using Cxx.
48///
49/// # Purpose
50///
51/// A `QRustProxy` implementation:
52///
53/// - Stores a raw pointer to the C++ proxy (`cpp_proxy`)
54/// - Stores access to the Rust object through `RustObjAccess<dyn _>` (`rust_obj`)
55/// - Coordinates destruction, layout and Qt meta-object information
56/// - Forwards all foreign function calls to the C++ proxy
57///
58/// Typical structure:
59///
60/// ```rust, ignore
61/// pub struct QObjectProxyRust {
62///     cpp_proxy: *mut QObjectProxyCpp,
63///     rust_obj: RustObjAccess<dyn QObjectProxyGet>,
64///     on_drop: fn(rust_obj: *const u8),
65/// }
66/// ```
67///
68/// Where:
69///
70/// - `cpp_proxy` points to the actual C++ QObject subclass.
71/// - `rust_obj` wraps access to the users rust object.
72/// - `on_drop` cleaning up memory.
73///
74/// # Lifetime and Ownership
75///
76/// A `QRustProxy` instance is heap-allocated and owned through a raw pointer, because its
77/// lifetime is jointly managed with C++ code and the C++ side requires a stable, non-movable
78/// address.
79///
80/// Destruction is always initiated from the C++ side: the paired `CppProxy` destructor calls
81/// `GenericRustProxy::drop_self`, which converts the raw pointer back to a `Box`, invokes
82/// the stored `on_drop` callback, and then drops this instance along with its reference to the
83/// Rust object.
84///
85/// The proxy always holds a strong `Rc` to the user's Rust object: the
86/// object lives exactly as long as its proxy pair, plus any user handles.
87///
88/// # Associated Types
89///
90/// ## `ProxyCppType`
91///
92/// The concrete C++ proxy type. Has to implement [`QCppProxy`].
93///
94/// ## `AdapterType`
95///
96/// A wrapper trait for the interface trait that QtBridge users implement. This wrapper
97/// is required because not all traits can be used with dyn and are thus incompatible with
98/// `RustObjAccess` (See "object safety" or "dyn compatibility").
99pub trait QRustProxy {
100    type ProxyCppType: QCppProxy<ProxyRustType = Self>;
101    type AdapterType: DispatchMetaCall + ?Sized;
102
103    /// Creates a new instance of this struct on the heap and returns a raw pointer to it.
104    ///
105    /// Initializes the proxy pair by:
106    /// - Creating a `RustObjAccess` wrapper holding a strong reference to `rust_obj`.
107    /// - Constructing the paired C++ proxy: with placement new at `at_address`
108    ///   if given (QML-created elements), on the heap otherwise.
109    /// - Storing `on_drop` for invocation when the C++ proxy is eventually destroyed.
110    fn new(rust_obj: &Rc<RefCell<Self::AdapterType>>, metaobject: &'static DynamicMetaObjectData, at_address: Option<PlacementAddress>, on_drop: Box<dyn FnOnce() + 'static>) -> *mut Self;
111    fn get_cpp_proxy(&self) -> *const Self::ProxyCppType;
112    fn get_cpp_proxy_mut(&self) -> *mut Self::ProxyCppType;
113    fn emit_signal(&self, mut_ref: &mut Self::AdapterType, signal_name: &str, argv: &[*const u8]);
114    fn with_rust_ref<R, F: FnOnce(&Self::AdapterType) -> R>(&self, f: F) -> R;
115    fn with_rust_ref_mut<R, F: FnOnce(&mut Self::AdapterType) -> R>(&self, f: F) -> R;
116
117    /// Returns an owned handle to the Rust object behind this proxy, or `None`
118    /// if it has already been dropped (the proxy may outlive a weakly-held
119    /// object). The handle is typed as the adapter trait object; recovering the
120    /// concrete type requires a checked reinterpret (see
121    /// `QObjectHolder::qobject_to_rc_ref_cell`).
122    fn get_rust_object_rc(&self) -> Rc<RefCell<Self::AdapterType>>;
123}
124
125/// Coerces a concrete user type into the proxy's type-erased adapter handle.
126///
127/// Implemented once per interface.
128pub trait AdapterUpcast<T>: QRustProxy {
129    fn upcast(rc: std::rc::Rc<std::cell::RefCell<T>>) -> std::rc::Rc<std::cell::RefCell<Self::AdapterType>>;
130}