qtbridge_interfaces/object_access/
rust_object_access.rs1use std::mem;
5use std::rc::Rc;
6use std::cell::{Cell, RefCell};
7
8#[macro_export]
9macro_rules! call_rust_trait_impl {
10 (unsafe mut $self:expr, $method:ident ( $($arg:expr),* )) => {
11 $self.rust_obj
12 .try_call_rust_with_handle_mut(|vtable| {
13 unsafe { vtable.$method($($arg),*) }
14 })
15 .expect(concat!(
16 "Failed to borrow mutably for ",
17 stringify!($method)
18 ))
19 };
20
21 (unsafe $self:expr, $method:ident ( $($arg:expr),* )) => {
22 $self.rust_obj
23 .try_call_rust_with_handle(|vtable| {
24 unsafe { vtable.$method($($arg),*) }
25 })
26 .expect(concat!(
27 "Failed to borrow for ",
28 stringify!($method)
29 ))
30 };
31
32 (mut $self:expr, $method:ident ( $($arg:expr),* )) => {
33 $self.rust_obj
34 .try_call_rust_with_handle_mut(|vtable| {
35 vtable.$method($($arg),*)
36 })
37 .expect(concat!(
38 "Failed to borrow mutably for ",
39 stringify!($method)
40 ))
41 };
42
43 ($self:expr, $method:ident ( $($arg:expr),* )) => {
44 $self.rust_obj
45 .try_call_rust_with_handle(|vtable| {
46 vtable.$method($($arg),*)
47 })
48 .expect(concat!(
49 "Failed to borrow for ",
50 stringify!($method)
51 ))
52 };
53}
54
55#[macro_export]
56macro_rules! call_cpp_impl {
57 (mut $self:expr, $mut_reference:expr, $method:ident ( $($arg:expr),* )) => {{
58 let proxy = unsafe {
59 $self.cpp_proxy
60 .as_mut()
61 .expect("cpp_proxy was null")
62 };
63 let proxy_pinned = unsafe { std::pin::Pin::new_unchecked(proxy) };
64 $self.rust_obj
65 .try_store_handle_and_call_cpp_mut($mut_reference, || proxy_pinned.$method($($arg),*))
66 .expect(concat!(
67 "Failed to borrow mutably for ",
68 stringify!($method)
69 ))
70 }};
71
72 ($self:expr, $reference:expr, $method:ident ( $($arg:expr),* )) => {{
73 let proxy = unsafe {
74 $self.cpp_proxy
75 .as_ref()
76 .expect("cpp_proxy was null")
77 };
78 $self.rust_obj
79 .try_store_handle_and_call_cpp($reference, || proxy.$method($($arg),*))
80 .expect(concat!(
81 "Failed to borrow for ",
82 stringify!($method)
83 ))
84 }};
85}
86
87pub struct RustObjAccess<T: ?Sized> {
95 shared_reference: Rc<RefCell<T>>,
98 borrow: Cell<BorrowState<T>>,
99}
100
101impl<T: ?Sized> RustObjAccess<T> {
102 pub fn new(ptr: Rc<RefCell<T>>) -> Self {
103 Self {
104 shared_reference: ptr,
105 borrow: Cell::new(BorrowState::None),
106 }
107 }
108
109 pub fn try_call_rust_with_handle<F, R>(&self, f: F) -> Result<R, RustObjAccessError>
110 where
111 F: FnOnce(&T) -> R,
112 {
113 let guard = BorrowState::consume(&self.borrow);
114
115 match guard.content() {
116 BorrowState::Immutable(ptr) => Ok(f(unsafe { &**ptr })),
117 BorrowState::Mutable(ptr) => Ok(f(unsafe { &**ptr })),
118 BorrowState::None => {
119 let rc = self.shared_reference.clone();
121 let ref_guarded = rc.try_borrow()
122 .map_err(RustObjAccessError::BorrowError)?;
123 Ok(f(&*ref_guarded))
124 }
125 }
126 }
127
128 pub fn try_call_rust_with_handle_mut<F, R>(&self, f: F) -> Result<R, RustObjAccessError>
129 where
130 F: FnOnce(&mut T) -> R,
131 {
132 let guard = BorrowState::consume(&self.borrow);
133
134 match guard.content() {
135 BorrowState::Mutable(ptr) => Ok(f(unsafe { &mut **ptr })),
136 BorrowState::Immutable(_) => Err(RustObjAccessError::BorrowConflict),
137 BorrowState::None => {
138 let rc = self.shared_reference.clone();
140 let mut ref_guarded = rc.try_borrow_mut()
141 .map_err(RustObjAccessError::BorrowMutError)?;
142 Ok(f(&mut *ref_guarded))
143 }
144 }
145 }
146
147 pub fn try_store_handle_and_call_cpp<F, R>(&self, rust_obj: &T, f: F) -> Result<R, RustObjAccessError>
148 where
149 F: FnOnce() -> R,
150 {
151 assert!(
152 self.contains(rust_obj),
153 "The rust_obj you want to call a function on does not match the shared reference."
154 );
155 let guard = BorrowState::store(&self.borrow, rust_obj);
156 if matches!(guard.content(), BorrowState::Mutable(_)) {
158 return Err(RustObjAccessError::BorrowConflict);
159 }
160 Ok(f())
161 }
162
163 pub fn try_store_handle_and_call_cpp_mut<F, R>(&self, rust_obj: &mut T, f: F) -> Result<R, RustObjAccessError>
164 where
165 F: FnOnce() -> R,
166 {
167 assert!(
168 self.contains(rust_obj),
169 "The rust_obj you want to call a function on does not match the shared reference."
170 );
171 let guard = BorrowState::store_mut(&self.borrow, rust_obj);
172 if matches!(guard.content(), BorrowState::Mutable(_)) || matches!(guard.content(), BorrowState::Immutable(_)) {
174 return Err(RustObjAccessError::BorrowConflict);
175 }
176 Ok(f())
177 }
178
179 pub fn get_rc(&self) -> Rc<RefCell<T>> {
180 self.shared_reference.clone()
181 }
182
183 fn contains(&self, obj: &T) -> bool {
184 let expected = self.shared_reference.as_ptr() as *const ();
185 let actual = obj as *const T as *const ();
186 expected == actual
187 }
188}
189
190
191enum BorrowState<T: ?Sized> {
192 None,
193 Immutable(*const T),
194 Mutable(*mut T),
195}
196
197impl<T: ?Sized> BorrowState<T> {
198 fn consume(cell: &Cell<Self>) -> BorrowGuard<'_, T> {
199 let consumed = cell.replace(BorrowState::None);
200 BorrowGuard { cell, consumed }
201 }
202
203 fn store<'a>(cell: &'a Cell<Self>, rust_obj: &T) -> BorrowGuard<'a, T> {
204 let old = cell.replace(BorrowState::Immutable(rust_obj as *const T));
205 BorrowGuard { cell, consumed: old }
206 }
207
208 fn store_mut<'a>(cell: &'a Cell<Self>, rust_obj: &mut T) -> BorrowGuard<'a, T> {
209 let old = cell.replace(BorrowState::Mutable(rust_obj as *mut T));
210 BorrowGuard { cell, consumed: old }
211 }
212}
213
214struct BorrowGuard<'a, T: ?Sized> {
215 cell: &'a Cell<BorrowState<T>>,
216 consumed: BorrowState<T>,
217}
218
219impl<T: ?Sized> BorrowGuard<'_, T> {
220 fn content(&self) -> &BorrowState<T> {
221 &self.consumed
222 }
223}
224
225impl<T: ?Sized> Drop for BorrowGuard<'_, T> {
226 fn drop(&mut self) {
227 self.cell.set(mem::replace(&mut self.consumed, BorrowState::None));
228 }
229}
230
231#[derive(Debug)]
232pub enum RustObjAccessError {
233 BorrowError(std::cell::BorrowError),
234 BorrowMutError(std::cell::BorrowMutError),
235 BorrowConflict,
236}