Skip to main content

qtbridge_interfaces/
genericrustproxy.rs

1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4use crate::{RustObjAccess, call_rust_trait_impl, call_cpp_impl};
5use qtbridge_runtime::qproxies::{QRustProxy, QCppProxy, PlacementAddress};
6use qtbridge_runtime::{DispatchMetaCall, DynamicMetaObjectData};
7use qtbridge_type_lib::QVariant;
8use std::cell::RefCell;
9use std::rc::Rc;
10
11pub struct GenericRustProxy<CppProxy: QCppProxy, Adapter: ?Sized> {
12    pub(crate) cpp_proxy: *mut CppProxy,
13    pub(crate) rust_obj: RustObjAccess<Adapter>,
14    pub(crate) on_drop: Box<dyn FnOnce()>,
15}
16
17impl<CppProxy, Adapter> QRustProxy for GenericRustProxy<CppProxy, Adapter>
18where
19    CppProxy: QCppProxy<ProxyRustType = Self>,
20    Adapter: ?Sized + DispatchMetaCall,
21{
22    type ProxyCppType = CppProxy;
23    type AdapterType = Adapter;
24
25    fn new(
26        rust_obj: &Rc<RefCell<Adapter>>,
27        metatype: &'static DynamicMetaObjectData,
28        at_address: Option<PlacementAddress>,
29        on_drop: Box<dyn FnOnce() + 'static>,
30    ) -> *mut Self {
31        let boxed_self = Box::new(Self {
32            cpp_proxy: std::ptr::null_mut(),
33            rust_obj: RustObjAccess::new(rust_obj.clone()),
34            on_drop,
35        });
36        let raw_self = Box::into_raw(boxed_self);
37        unsafe {
38            (*raw_self).cpp_proxy = match at_address {
39                Some(addr) => CppProxy::create_at(raw_self, metatype, addr),
40                None => CppProxy::create(raw_self, metatype),
41            }
42        };
43        raw_self
44    }
45
46    fn get_cpp_proxy(&self) -> *const CppProxy {
47        self.cpp_proxy
48    }
49
50    fn get_cpp_proxy_mut(&self) -> *mut CppProxy {
51        self.cpp_proxy
52    }
53
54    fn emit_signal(&self, mut_ref: &mut Adapter, signal_name: &str, argv: &[*const u8]) {
55        call_cpp_impl!(mut self, mut_ref, emit_signal(signal_name, argv))
56    }
57
58    fn with_rust_ref<R, F: FnOnce(&Adapter) -> R>(&self, f: F) -> R {
59        self.rust_obj
60            .try_call_rust_with_handle(|adapter| f(adapter))
61            .expect("Failed to access Rust object via shared handle")
62    }
63
64    fn with_rust_ref_mut<R, F: FnOnce(&mut Adapter) -> R>(&self, f: F) -> R {
65        self.rust_obj
66            .try_call_rust_with_handle_mut(|adapter| f(adapter))
67            .expect("Failed to access Rust object via mutable handle")
68    }
69
70    fn get_rust_object_rc(&self) -> Rc<RefCell<Adapter>> {
71        self.rust_obj.get_rc()
72    }
73}
74
75impl<CppProxy, Adapter> GenericRustProxy<CppProxy, Adapter>
76where
77    CppProxy: QCppProxy<ProxyRustType = Self>,
78    Adapter: ?Sized + DispatchMetaCall,
79{
80    /// Drops the instance pointed to by `self_ptr`.
81    ///
82    /// Intended to be called exclusively from the paired C++ destructor.
83    ///
84    /// # Safety
85    ///
86    /// `self_ptr` must be a pointer previously returned by [`QRustProxy::new`].
87    /// It must not have been dropped already.
88    pub unsafe fn drop_self(self_ptr: *mut Self) {
89        let boxed_self = unsafe { Box::from_raw(self_ptr) };
90        (boxed_self.on_drop)();
91    }
92
93    pub fn invoke_slot(&self, slot_id: u32, inputs: &[*const u8], outputs: &[*mut u8]) {
94        call_rust_trait_impl!(unsafe self, invoke_slot(slot_id, inputs, outputs))
95    }
96
97    // `&self` deliberately: mutability of the user object is interior (`RustObjAccess`)
98    pub fn invoke_slot_mut(&self, slot_id: u32, inputs: &[*const u8], outputs: &[*mut u8]) {
99        call_rust_trait_impl!(unsafe mut self, invoke_slot_mut(slot_id, inputs, outputs))
100    }
101
102    pub fn read_property(&self, prop_id: u32) -> QVariant {
103        call_rust_trait_impl!(unsafe self, read_property(prop_id))
104    }
105
106    // `&self` deliberately: mutability of the user object is interior (`RustObjAccess`)
107    pub fn write_property(&self, prop_id: u32, value: &QVariant) {
108        call_rust_trait_impl!(unsafe mut self, write_property(prop_id, value))
109    }
110
111}
112
113#[macro_export]
114macro_rules! impl_qcpp_proxy {
115    ($cpp_proxy:ty, $rust_proxy:ty) => {
116        impl QCppProxy for $cpp_proxy {
117            type ProxyRustType = $rust_proxy;
118            fn get_static_meta_object() -> &'static QMetaObject {
119                Self::static_qmeta_object()
120            }
121            fn get_size() -> usize {
122                Self::size_of()
123            }
124            fn get_align() -> usize {
125                Self::align_of()
126            }
127            fn parser_status_cast() -> i32 {
128                Self::parser_status_cast()
129            }
130            unsafe fn create(rust_proxy: *mut Self::ProxyRustType, metaobject: &'static DynamicMetaObjectData) -> *mut Self {
131                unsafe { Self::create(rust_proxy, metaobject) }
132            }
133            unsafe fn create_at(rust_proxy: *mut Self::ProxyRustType, metaobject: &'static DynamicMetaObjectData, addr: *mut u8) -> *mut Self {
134                unsafe { Self::create_at(rust_proxy, metaobject, addr) }
135            }
136            fn emit_signal(self: std::pin::Pin<&mut Self>, signal_name: &str, argv: &[*const u8]) {
137                self.emit_signal_cpp(signal_name, argv)
138            }
139        }
140    };
141}