cxx_qt_gen/generator/rust/
threading.rs1use crate::{
7 generator::{
8 naming::{
9 namespace::{namespace_combine_ident, NamespaceName},
10 qobject::QObjectNames,
11 },
12 rust::fragment::GeneratedRustFragment,
13 },
14 naming::TypeNames,
15};
16use quote::quote;
17use syn::Result;
18
19use super::fragment::RustFragmentPair;
20
21pub fn generate(
22 qobject_names: &QObjectNames,
23 namespace_ident: &NamespaceName,
24 type_names: &TypeNames,
25) -> Result<GeneratedRustFragment> {
26 let mut blocks = GeneratedRustFragment::default();
27
28 let module_ident = qobject_names.name.require_module()?;
29
30 let cpp_struct_ident = qobject_names.name.rust_unqualified();
31 let cxx_qt_thread_ident = &qobject_names.cxx_qt_thread_class;
32 let cxx_qt_thread_queued_fn_ident = &qobject_names.cxx_qt_thread_queued_fn_struct;
33
34 let (thread_queue_name, thread_queue_attrs, thread_queue_qualified) = qobject_names
35 .cxx_qt_ffi_method("cxxQtThreadQueue")
36 .into_cxx_parts();
37 let (thread_clone_name, thread_clone_attrs, thread_clone_qualified) = qobject_names
38 .cxx_qt_ffi_method("cxxQtThreadClone")
39 .into_cxx_parts();
40 let (thread_drop_name, thread_drop_attrs, thread_drop_qualified) = qobject_names
41 .cxx_qt_ffi_method("cxxQtThreadDrop")
42 .into_cxx_parts();
43 let (thread_fn_name, thread_fn_attrs, thread_fn_qualified) =
44 qobject_names.cxx_qt_ffi_method("qtThread").into_cxx_parts();
45 let (thread_is_destroyed_name, thread_is_destroyed_attrs, thread_is_destroyed_qualified) =
46 qobject_names
47 .cxx_qt_ffi_method("cxxQtThreadIsDestroyed")
48 .into_cxx_parts();
49
50 let cxx_qt_thread_namespace = &namespace_ident.namespace;
51 let namespace_internals = &namespace_ident.internal;
52 let cxx_qt_thread_ident_type_id_str =
53 namespace_combine_ident(&namespace_ident.namespace, cxx_qt_thread_ident);
54 let qualified_impl = type_names.rust_qualified(cpp_struct_ident)?;
55
56 let fragment = RustFragmentPair {
57 cxx_bridge: vec![
58 quote! {
59 unsafe extern "C++" {
60 #[doc(hidden)]
67 #[namespace = #cxx_qt_thread_namespace]
68 type #cxx_qt_thread_ident = cxx_qt::CxxQtThread<#cpp_struct_ident>;
69 include!("cxx-qt/thread.h");
70
71 #[doc(hidden)]
72 #(#thread_fn_attrs)*
73 fn #thread_fn_name(qobject: &#cpp_struct_ident) -> #cxx_qt_thread_ident;
74
75 #[doc(hidden)]
79 #(#thread_queue_attrs)*
80 fn #thread_queue_name(
81 cxx_qt_thread: &#cxx_qt_thread_ident,
82 func: fn(Pin<&mut #cpp_struct_ident>, Box<#cxx_qt_thread_queued_fn_ident>),
83 arg: Box<#cxx_qt_thread_queued_fn_ident>,
84 ) -> u8;
85
86 #[doc(hidden)]
87 #(#thread_clone_attrs)*
88 fn #thread_clone_name(cxx_qt_thread: &#cxx_qt_thread_ident) -> #cxx_qt_thread_ident;
89
90 #[doc(hidden)]
91 #(#thread_drop_attrs)*
92 fn #thread_drop_name(cxx_qt_thread: Pin<&mut #cxx_qt_thread_ident>);
93
94 #[doc(hidden)]
95 #(#thread_is_destroyed_attrs)*
96 fn #thread_is_destroyed_name(cxx_qt_thread: &#cxx_qt_thread_ident) -> bool;
97 }
98 },
99 quote! {
100 extern "Rust" {
101 #[namespace = #namespace_internals]
102 type #cxx_qt_thread_queued_fn_ident;
103 }
104 },
105 ],
106 implementation: vec![
107 quote! {
108 impl cxx_qt::Threading for #qualified_impl {
109 type BoxedQueuedFn = #cxx_qt_thread_queued_fn_ident;
110 type ThreadingTypeId = cxx::type_id!(#cxx_qt_thread_ident_type_id_str);
111
112 fn qt_thread(&self) -> #module_ident::#cxx_qt_thread_ident
113 {
114 #thread_fn_qualified(self)
115 }
116
117 #[doc(hidden)]
118 fn is_destroyed(cxx_qt_thread: &#module_ident::#cxx_qt_thread_ident) -> bool
119 {
120 #thread_is_destroyed_qualified(cxx_qt_thread)
121 }
122
123 #[doc(hidden)]
124 fn queue<F>(cxx_qt_thread: &#module_ident::#cxx_qt_thread_ident, f: F) -> std::result::Result<(), cxx_qt::ThreadingQueueError>
125 where
126 F: FnOnce(core::pin::Pin<&mut #qualified_impl>),
127 F: Send + 'static,
128 {
129 #[allow(clippy::boxed_local)]
133 #[doc(hidden)]
134 fn func(
135 obj: core::pin::Pin<&mut #qualified_impl>,
136 arg: std::boxed::Box<#cxx_qt_thread_queued_fn_ident>,
137 ) {
138 (arg.inner)(obj)
139 }
140 let arg = #cxx_qt_thread_queued_fn_ident { inner: std::boxed::Box::new(f) };
141 match #thread_queue_qualified(cxx_qt_thread, func, std::boxed::Box::new(arg)) {
142 0 => Ok(()),
143 others => Err(others.into()),
144 }
145 }
146
147 #[doc(hidden)]
148 fn threading_clone(cxx_qt_thread: &#module_ident::#cxx_qt_thread_ident) -> #module_ident::#cxx_qt_thread_ident
149 {
150 #thread_clone_qualified(cxx_qt_thread)
151 }
152
153 #[doc(hidden)]
154 fn threading_drop(cxx_qt_thread: Pin<&mut #module_ident::#cxx_qt_thread_ident>)
155 {
156 #thread_drop_qualified(cxx_qt_thread);
157 }
158 }
159 },
160 quote! {
161 #[doc(hidden)]
162 pub struct #cxx_qt_thread_queued_fn_ident {
163 inner: std::boxed::Box<dyn FnOnce(core::pin::Pin<&mut #qualified_impl>) + Send>,
166 }
167 },
168 ],
169 };
170
171 blocks
172 .cxx_mod_contents
173 .append(&mut fragment.cxx_bridge_as_items()?);
174 blocks
175 .cxx_qt_mod_contents
176 .append(&mut fragment.implementation_as_items()?);
177
178 Ok(blocks)
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 use crate::naming::TypeNames;
186 use crate::tests::assert_tokens_eq;
187
188 use crate::parser::qobject::tests::create_parsed_qobject;
189
190 #[test]
191 fn test_generate_rust_threading() {
192 let qobject = create_parsed_qobject();
193 let qobject_names = QObjectNames::from_qobject(&qobject, &TypeNames::mock()).unwrap();
194 let namespace_ident = NamespaceName::from(&qobject);
195
196 let generated = generate(&qobject_names, &namespace_ident, &TypeNames::mock()).unwrap();
197
198 assert_eq!(generated.cxx_mod_contents.len(), 2);
199 assert_eq!(generated.cxx_qt_mod_contents.len(), 2);
200
201 assert_tokens_eq(
204 &generated.cxx_mod_contents[0],
205 quote! {
206 unsafe extern "C++" {
207 #[doc(hidden)]
208 #[namespace = ""]
209 type MyObjectCxxQtThread = cxx_qt::CxxQtThread<MyObject>;
210 include!("cxx-qt/thread.h");
211
212 #[doc(hidden)]
213 #[cxx_name = "qtThread"]
214 #[namespace = "rust::cxxqt1"]
215 fn cxx_qt_ffi_MyObject_qtThread(qobject: &MyObject) -> MyObjectCxxQtThread;
216
217 #[doc(hidden)]
221 #[cxx_name = "cxxQtThreadQueue"]
222 #[namespace = "rust::cxxqt1"]
223 fn cxx_qt_ffi_MyObject_cxxQtThreadQueue(
224 cxx_qt_thread: &MyObjectCxxQtThread,
225 func: fn(Pin<&mut MyObject>, Box<MyObjectCxxQtThreadQueuedFn>),
226 arg: Box<MyObjectCxxQtThreadQueuedFn>,
227 ) -> u8;
228
229 #[doc(hidden)]
230 #[cxx_name = "cxxQtThreadClone"]
231 #[namespace = "rust::cxxqt1"]
232 fn cxx_qt_ffi_MyObject_cxxQtThreadClone(cxx_qt_thread: &MyObjectCxxQtThread) -> MyObjectCxxQtThread;
233
234 #[doc(hidden)]
235 #[cxx_name = "cxxQtThreadDrop"]
236 #[namespace = "rust::cxxqt1"]
237 fn cxx_qt_ffi_MyObject_cxxQtThreadDrop(cxx_qt_thread: Pin<&mut MyObjectCxxQtThread>);
238
239 #[doc(hidden)]
240 #[cxx_name = "cxxQtThreadIsDestroyed"]
241 #[namespace = "rust::cxxqt1"]
242 fn cxx_qt_ffi_MyObject_cxxQtThreadIsDestroyed(cxx_qt_thread: &MyObjectCxxQtThread) -> bool;
243 }
244 },
245 );
246 assert_tokens_eq(
247 &generated.cxx_mod_contents[1],
248 quote! {
249 extern "Rust" {
250 #[namespace = "cxx_qt_MyObject"]
251 type MyObjectCxxQtThreadQueuedFn;
252 }
253 },
254 );
255
256 assert_tokens_eq(
258 &generated.cxx_qt_mod_contents[0],
259 quote! {
260 impl cxx_qt::Threading for qobject::MyObject {
261 type BoxedQueuedFn = MyObjectCxxQtThreadQueuedFn;
262 type ThreadingTypeId = cxx::type_id!("MyObjectCxxQtThread");
263
264 fn qt_thread(&self) -> qobject::MyObjectCxxQtThread
265 {
266 qobject::cxx_qt_ffi_MyObject_qtThread(self)
267 }
268
269 #[doc(hidden)]
270 fn is_destroyed(cxx_qt_thread: &qobject::MyObjectCxxQtThread) -> bool {
271 qobject::cxx_qt_ffi_MyObject_cxxQtThreadIsDestroyed(cxx_qt_thread)
272 }
273
274 #[doc(hidden)]
275 fn queue<F>(cxx_qt_thread: &qobject::MyObjectCxxQtThread, f: F) -> std::result::Result<(), cxx_qt::ThreadingQueueError>
276 where
277 F: FnOnce(core::pin::Pin<&mut qobject::MyObject>),
278 F: Send + 'static,
279 {
280 #[allow(clippy::boxed_local)]
284 #[doc(hidden)]
285 fn func(
286 obj: core::pin::Pin<&mut qobject::MyObject>,
287 arg: std::boxed::Box<MyObjectCxxQtThreadQueuedFn>,
288 ) {
289 (arg.inner)(obj)
290 }
291 let arg = MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box::new(f) };
292 match qobject::cxx_qt_ffi_MyObject_cxxQtThreadQueue(cxx_qt_thread, func, std::boxed::Box::new(arg)) {
293 0 => Ok(()),
294 others => Err(others.into()),
295 }
296 }
297
298 #[doc(hidden)]
299 fn threading_clone(cxx_qt_thread: &qobject::MyObjectCxxQtThread) -> qobject::MyObjectCxxQtThread
300 {
301 qobject::cxx_qt_ffi_MyObject_cxxQtThreadClone(cxx_qt_thread)
302 }
303
304 #[doc(hidden)]
305 fn threading_drop(cxx_qt_thread: Pin<&mut qobject::MyObjectCxxQtThread>)
306 {
307 qobject::cxx_qt_ffi_MyObject_cxxQtThreadDrop(cxx_qt_thread);
308 }
309 }
310 },
311 );
312 assert_tokens_eq(
313 &generated.cxx_qt_mod_contents[1],
314 quote! {
315 #[doc(hidden)]
316 pub struct MyObjectCxxQtThreadQueuedFn {
317 inner: std::boxed::Box<dyn FnOnce(core::pin::Pin<&mut qobject::MyObject>) + Send>,
320 }
321 },
322 );
323 }
324}