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
11 (mut $self:expr, $method:ident ( $($arg:expr),* )) => {
12 $self.rust_obj
13 .try_call_rust_with_handle_mut(|vtable| {
14 vtable.$method($($arg),*)
15 })
16 .expect(concat!(
17 "Failed to borrow mutably for ",
18 stringify!($method)
19 ))
20 };
21
22 ($self:expr, $method:ident ( $($arg:expr),* )) => {
23 $self.rust_obj
24 .try_call_rust_with_handle(|vtable| {
25 vtable.$method($($arg),*)
26 })
27 .expect(concat!(
28 "Failed to borrow for ",
29 stringify!($method)
30 ))
31 };
32}
33
34#[macro_export]
35macro_rules! call_cpp_impl {
36 (mut $self:expr, $mut_reference:expr, $method:ident ( $($arg:expr),* )) => {{
37 let proxy_pinned = $self.cpp_proxy_pin_mut();
38 $self.rust_obj
39 .try_store_handle_and_call_cpp_mut($mut_reference, || proxy_pinned.$method($($arg),*))
40 .expect(concat!(
41 "Failed to borrow mutably for ",
42 stringify!($method)
43 ))
44 }};
45
46 ($self:expr, $reference:expr, $method:ident ( $($arg:expr),* )) => {{
47 let proxy = $self.cpp_proxy_ref();
48 $self.rust_obj
49 .try_store_handle_and_call_cpp($reference, || proxy.$method($($arg),*))
50 .expect(concat!(
51 "Failed to borrow for ",
52 stringify!($method)
53 ))
54 }};
55}
56
57pub struct RustObjAccess<T: ?Sized> {
65 shared_reference: Rc<RefCell<T>>,
68 borrow: Cell<BorrowState<T>>,
69}
70
71impl<T: ?Sized> RustObjAccess<T> {
72 pub fn new(ptr: Rc<RefCell<T>>) -> Self {
73 Self {
74 shared_reference: ptr,
75 borrow: Cell::new(BorrowState::None),
76 }
77 }
78
79 pub fn try_call_rust_with_handle<F, R>(&self, f: F) -> Result<R, RustObjAccessError>
80 where
81 F: FnOnce(&T) -> R,
82 {
83 let guard = BorrowState::consume(&self.borrow);
84
85 match guard.content() {
86 BorrowState::Immutable(ptr) => Ok(f(unsafe { &**ptr })),
87 BorrowState::Mutable(ptr) => Ok(f(unsafe { &**ptr })),
88 BorrowState::None => {
89 let rc = self.shared_reference.clone();
91 let ref_guarded = rc.try_borrow()
92 .map_err(RustObjAccessError::BorrowError)?;
93 Ok(f(&*ref_guarded))
94 }
95 }
96 }
97
98 pub fn try_call_rust_with_handle_mut<F, R>(&self, f: F) -> Result<R, RustObjAccessError>
99 where
100 F: FnOnce(&mut T) -> R,
101 {
102 let guard = BorrowState::consume(&self.borrow);
103
104 match guard.content() {
105 BorrowState::Mutable(ptr) => Ok(f(unsafe { &mut **ptr })),
106 BorrowState::Immutable(_) => Err(RustObjAccessError::BorrowConflict),
107 BorrowState::None => {
108 let rc = self.shared_reference.clone();
110 let mut ref_guarded = rc.try_borrow_mut()
111 .map_err(RustObjAccessError::BorrowMutError)?;
112 Ok(f(&mut *ref_guarded))
113 }
114 }
115 }
116
117 pub fn try_store_handle_and_call_cpp<F, R>(&self, rust_obj: &T, f: F) -> Result<R, RustObjAccessError>
118 where
119 F: FnOnce() -> R,
120 {
121 assert!(
122 self.contains(rust_obj),
123 "The rust_obj you want to call a function on does not match the shared reference."
124 );
125 let guard = BorrowState::store(&self.borrow, rust_obj);
126 if matches!(guard.content(), BorrowState::Mutable(_)) {
128 return Err(RustObjAccessError::BorrowConflict);
129 }
130 Ok(f())
131 }
132
133 pub fn try_store_handle_and_call_cpp_mut<F, R>(&self, rust_obj: &mut T, f: F) -> Result<R, RustObjAccessError>
134 where
135 F: FnOnce() -> R,
136 {
137 assert!(
138 self.contains(rust_obj),
139 "The rust_obj you want to call a function on does not match the shared reference."
140 );
141 let guard = BorrowState::store_mut(&self.borrow, rust_obj);
142 if matches!(guard.content(), BorrowState::Mutable(_)) || matches!(guard.content(), BorrowState::Immutable(_)) {
144 return Err(RustObjAccessError::BorrowConflict);
145 }
146 Ok(f())
147 }
148
149 pub fn get_rc(&self) -> Rc<RefCell<T>> {
150 self.shared_reference.clone()
151 }
152
153 fn contains(&self, obj: &T) -> bool {
154 let expected = self.shared_reference.as_ptr() as *const ();
155 let actual = obj as *const T as *const ();
156 expected == actual
157 }
158}
159
160
161enum BorrowState<T: ?Sized> {
162 None,
163 Immutable(*const T),
164 Mutable(*mut T),
165}
166
167impl<T: ?Sized> BorrowState<T> {
168 fn consume(cell: &Cell<Self>) -> BorrowGuard<'_, T> {
169 let consumed = cell.replace(BorrowState::None);
170 BorrowGuard { cell, consumed }
171 }
172
173 fn store<'a>(cell: &'a Cell<Self>, rust_obj: &T) -> BorrowGuard<'a, T> {
174 let old = cell.replace(BorrowState::Immutable(rust_obj as *const T));
175 BorrowGuard { cell, consumed: old }
176 }
177
178 fn store_mut<'a>(cell: &'a Cell<Self>, rust_obj: &mut T) -> BorrowGuard<'a, T> {
179 let old = cell.replace(BorrowState::Mutable(rust_obj as *mut T));
180 BorrowGuard { cell, consumed: old }
181 }
182}
183
184struct BorrowGuard<'a, T: ?Sized> {
185 cell: &'a Cell<BorrowState<T>>,
186 consumed: BorrowState<T>,
187}
188
189impl<T: ?Sized> BorrowGuard<'_, T> {
190 fn content(&self) -> &BorrowState<T> {
191 &self.consumed
192 }
193}
194
195impl<T: ?Sized> Drop for BorrowGuard<'_, T> {
196 fn drop(&mut self) {
197 self.cell.set(mem::replace(&mut self.consumed, BorrowState::None));
198 }
199}
200
201#[derive(Debug)]
202pub enum RustObjAccessError {
203 BorrowError(std::cell::BorrowError),
204 BorrowMutError(std::cell::BorrowMutError),
205 BorrowConflict,
206}