Skip to content

Commit 0805af7

Browse files
committed
cxx-qt-gen: remove wrapper method for C++ -> Rust invokables
This then avoids us needing to generate Rust methods with fully qualified types on the Rust side and removes a load of generation. Related to #404
1 parent a9c1b4e commit 0805af7

14 files changed

+164
-236
lines changed

crates/cxx-qt-gen/src/generator/cpp/invokable.rs

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ pub fn generate_cpp_invokables(
6767
.collect::<Result<Vec<CppNamedType>>>()?;
6868

6969
let body = format!(
70-
"m_rustObj->{ident}({parameter_names})",
70+
"{ident}({parameter_names})",
7171
ident = idents.wrapper.cpp,
72-
parameter_names = vec!["*this"]
73-
.into_iter()
74-
.chain(parameters.iter().map(|parameter| parameter.ident.as_str()))
72+
parameter_names = parameters
73+
.iter()
74+
.map(|parameter| parameter.ident.as_str())
7575
.collect::<Vec<&str>>()
7676
.join(", "),
7777
);
@@ -140,6 +140,23 @@ pub fn generate_cpp_invokables(
140140
},
141141
},
142142
});
143+
144+
// Note that we are generating a header to match the extern "Rust" method
145+
// in Rust for our invokable.
146+
//
147+
// CXX generates the source and we just need the matching header.
148+
//
149+
// TODO: will this always be noexcept ? If the return type is Result is this then removed?
150+
generated.private_methods.push(CppFragment::Header(format!(
151+
"{return_cxx_ty} {ident}({parameter_types}){is_const} noexcept;",
152+
return_cxx_ty = if let Some(return_cxx_ty) = &return_cxx_ty {
153+
return_cxx_ty.as_cxx_ty()
154+
} else {
155+
"void"
156+
},
157+
ident = idents.wrapper.cpp,
158+
parameter_types = parameter_types,
159+
)));
143160
}
144161

145162
Ok(generated)
@@ -234,7 +251,7 @@ mod tests {
234251
MyObject::voidInvokable() const
235252
{
236253
// ::std::lock_guard
237-
m_rustObj->voidInvokableWrapper(*this);
254+
voidInvokableWrapper();
238255
}
239256
"#}
240257
);
@@ -255,7 +272,7 @@ mod tests {
255272
MyObject::trivialInvokable(::std::int32_t param) const
256273
{
257274
// ::std::lock_guard
258-
return m_rustObj->trivialInvokableWrapper(*this, param);
275+
return trivialInvokableWrapper(param);
259276
}
260277
"#}
261278
);
@@ -276,7 +293,7 @@ mod tests {
276293
MyObject::opaqueInvokable(QColor const& param)
277294
{
278295
// ::std::lock_guard
279-
return m_rustObj->opaqueInvokableWrapper(*this, param);
296+
return opaqueInvokableWrapper(param);
280297
}
281298
"#}
282299
);
@@ -297,10 +314,50 @@ mod tests {
297314
MyObject::specifiersInvokable(::std::int32_t param) const
298315
{
299316
// ::std::lock_guard
300-
return m_rustObj->specifiersInvokableWrapper(*this, param);
317+
return specifiersInvokableWrapper(param);
301318
}
302319
"#}
303320
);
321+
322+
// private methods
323+
assert_eq!(generated.private_methods.len(), 4);
324+
325+
let header = if let CppFragment::Header(header) = &generated.private_methods[0] {
326+
header
327+
} else {
328+
panic!("Expected header")
329+
};
330+
assert_str_eq!(header, "void voidInvokableWrapper() const noexcept;");
331+
332+
let header = if let CppFragment::Header(header) = &generated.private_methods[1] {
333+
header
334+
} else {
335+
panic!("Expected header")
336+
};
337+
assert_str_eq!(
338+
header,
339+
"::std::int32_t trivialInvokableWrapper(::std::int32_t param) const noexcept;"
340+
);
341+
342+
let header = if let CppFragment::Header(header) = &generated.private_methods[2] {
343+
header
344+
} else {
345+
panic!("Expected header")
346+
};
347+
assert_str_eq!(
348+
header,
349+
"::std::unique_ptr<QColor> opaqueInvokableWrapper(QColor const& param) noexcept;"
350+
);
351+
352+
let header = if let CppFragment::Header(header) = &generated.private_methods[3] {
353+
header
354+
} else {
355+
panic!("Expected header")
356+
};
357+
assert_str_eq!(
358+
header,
359+
"::std::int32_t specifiersInvokableWrapper(::std::int32_t param) const noexcept;"
360+
);
304361
}
305362

306363
#[test]
@@ -350,9 +407,22 @@ mod tests {
350407
MyObject::trivialInvokable(A1 param) const
351408
{
352409
// ::std::lock_guard
353-
return m_rustObj->trivialInvokableWrapper(*this, param);
410+
return trivialInvokableWrapper(param);
354411
}
355412
"#}
356413
);
414+
415+
// private methods
416+
assert_eq!(generated.private_methods.len(), 1);
417+
418+
let header = if let CppFragment::Header(header) = &generated.private_methods[0] {
419+
header
420+
} else {
421+
panic!("Expected header")
422+
};
423+
assert_str_eq!(
424+
header,
425+
"B2 trivialInvokableWrapper(A1 param) const noexcept;"
426+
);
357427
}
358428
}

crates/cxx-qt-gen/src/generator/rust/invokable.rs

Lines changed: 22 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,29 @@ use crate::{
1212
};
1313
use proc_macro2::TokenStream;
1414
use quote::quote;
15-
use syn::{Ident, Result, ReturnType};
15+
use syn::Result;
1616

1717
pub fn generate_rust_invokables(
1818
invokables: &Vec<ParsedQInvokable>,
1919
qobject_idents: &QObjectName,
2020
) -> Result<GeneratedRustQObjectBlocks> {
2121
let mut generated = GeneratedRustQObjectBlocks::default();
2222
let cpp_class_name_rust = &qobject_idents.cpp_class.rust;
23-
let rust_struct_name_rust = &qobject_idents.rust_struct.rust;
2423

2524
for invokable in invokables {
2625
let idents = QInvokableName::from(invokable);
2726
let wrapper_ident_cpp = idents.wrapper.cpp.to_string();
28-
let wrapper_ident_rust = &idents.wrapper.rust;
2927
let invokable_ident_rust = &idents.name.rust;
3028

29+
// TODO: once we aren't using qobject::T in the extern "RustQt"
30+
// we can just pass through the original ExternFn block and add the attribute?
3131
let cpp_struct = if invokable.mutable {
32-
quote! { Pin<&mut #cpp_class_name_rust> }
32+
quote! { Pin<&mut #cpp_class_name_rust> }
3333
} else {
3434
quote! { &#cpp_class_name_rust }
3535
};
36-
let rust_struct = if invokable.mutable {
37-
quote! { &mut #rust_struct_name_rust }
38-
} else {
39-
quote! { &#rust_struct_name_rust }
40-
};
4136
let parameter_signatures = if invokable.parameters.is_empty() {
42-
quote! { self: #rust_struct, cpp: #cpp_struct }
37+
quote! { self: #cpp_struct }
4338
} else {
4439
let parameters = invokable
4540
.parameters
@@ -50,46 +45,29 @@ pub fn generate_rust_invokables(
5045
quote! { #ident: #ty }
5146
})
5247
.collect::<Vec<TokenStream>>();
53-
quote! { self: #rust_struct, cpp: #cpp_struct, #(#parameters),* }
48+
quote! { self: #cpp_struct, #(#parameters),* }
5449
};
5550
let return_type = &invokable.method.sig.output;
56-
let has_return = if matches!(invokable.method.sig.output, ReturnType::Default) {
57-
quote! {}
58-
} else {
59-
quote! { return }
60-
};
6151

6252
let mut unsafe_block = None;
6353
let mut unsafe_call = Some(quote! { unsafe });
6454
if invokable.safe {
6555
std::mem::swap(&mut unsafe_call, &mut unsafe_block);
6656
}
6757

68-
let parameter_names = invokable
69-
.parameters
70-
.iter()
71-
.map(|parameter| parameter.ident.clone())
72-
.collect::<Vec<Ident>>();
73-
7458
let fragment = RustFragmentPair {
7559
cxx_bridge: vec![quote! {
76-
// TODO: is an unsafe block valid?
60+
// Note: extern "Rust" block does not need to be unsafe
7761
extern "Rust" {
62+
// Note that we are exposing a Rust method on the C++ type to C++
63+
//
64+
// CXX ends up generating the source, then we generate the matching header.
65+
#[doc(hidden)]
7866
#[cxx_name = #wrapper_ident_cpp]
79-
#unsafe_call fn #wrapper_ident_rust(#parameter_signatures) #return_type;
67+
#unsafe_call fn #invokable_ident_rust(#parameter_signatures) #return_type;
8068
}
8169
}],
82-
implementation: vec![
83-
// TODO: not all methods have a wrapper
84-
quote! {
85-
impl #rust_struct_name_rust {
86-
#[doc(hidden)]
87-
pub #unsafe_call fn #wrapper_ident_rust(#parameter_signatures) #return_type {
88-
#has_return cpp.#invokable_ident_rust(#(#parameter_names),*);
89-
}
90-
}
91-
},
92-
],
70+
implementation: vec![],
9371
};
9472

9573
generated
@@ -164,26 +142,16 @@ mod tests {
164142
let generated = generate_rust_invokables(&invokables, &qobject_idents).unwrap();
165143

166144
assert_eq!(generated.cxx_mod_contents.len(), 4);
167-
assert_eq!(generated.cxx_qt_mod_contents.len(), 4);
145+
assert_eq!(generated.cxx_qt_mod_contents.len(), 0);
168146

169147
// void_invokable
170148
assert_tokens_eq(
171149
&generated.cxx_mod_contents[0],
172150
quote! {
173151
extern "Rust" {
174-
#[cxx_name = "voidInvokableWrapper"]
175-
fn void_invokable_wrapper(self: &MyObjectRust, cpp: &MyObject);
176-
}
177-
},
178-
);
179-
assert_tokens_eq(
180-
&generated.cxx_qt_mod_contents[0],
181-
quote! {
182-
impl MyObjectRust {
183152
#[doc(hidden)]
184-
pub fn void_invokable_wrapper(self: &MyObjectRust, cpp: &MyObject) {
185-
cpp.void_invokable();
186-
}
153+
#[cxx_name = "voidInvokableWrapper"]
154+
fn void_invokable(self: &MyObject);
187155
}
188156
},
189157
);
@@ -193,19 +161,9 @@ mod tests {
193161
&generated.cxx_mod_contents[1],
194162
quote! {
195163
extern "Rust" {
196-
#[cxx_name = "trivialInvokableWrapper"]
197-
fn trivial_invokable_wrapper(self: &MyObjectRust, cpp: &MyObject, param: i32) -> i32;
198-
}
199-
},
200-
);
201-
assert_tokens_eq(
202-
&generated.cxx_qt_mod_contents[1],
203-
quote! {
204-
impl MyObjectRust {
205164
#[doc(hidden)]
206-
pub fn trivial_invokable_wrapper(self: &MyObjectRust, cpp: &MyObject, param: i32) -> i32 {
207-
return cpp.trivial_invokable(param);
208-
}
165+
#[cxx_name = "trivialInvokableWrapper"]
166+
fn trivial_invokable(self: &MyObject, param: i32) -> i32;
209167
}
210168
},
211169
);
@@ -215,19 +173,9 @@ mod tests {
215173
&generated.cxx_mod_contents[2],
216174
quote! {
217175
extern "Rust" {
218-
#[cxx_name = "opaqueInvokableWrapper"]
219-
fn opaque_invokable_wrapper(self: &mut MyObjectRust, cpp: Pin<&mut MyObject>, param: &QColor) -> UniquePtr<QColor>;
220-
}
221-
},
222-
);
223-
assert_tokens_eq(
224-
&generated.cxx_qt_mod_contents[2],
225-
quote! {
226-
impl MyObjectRust {
227176
#[doc(hidden)]
228-
pub fn opaque_invokable_wrapper(self: &mut MyObjectRust, cpp: Pin<&mut MyObject>, param: &QColor) -> UniquePtr<QColor> {
229-
return cpp.opaque_invokable(param);
230-
}
177+
#[cxx_name = "opaqueInvokableWrapper"]
178+
fn opaque_invokable(self: Pin<&mut MyObject>, param: &QColor) -> UniquePtr<QColor>;
231179
}
232180
},
233181
);
@@ -237,19 +185,9 @@ mod tests {
237185
&generated.cxx_mod_contents[3],
238186
quote! {
239187
extern "Rust" {
240-
#[cxx_name = "unsafeInvokableWrapper"]
241-
unsafe fn unsafe_invokable_wrapper(self: &MyObjectRust, cpp: &MyObject, param: *mut T) -> *mut T;
242-
}
243-
},
244-
);
245-
assert_tokens_eq(
246-
&generated.cxx_qt_mod_contents[3],
247-
quote! {
248-
impl MyObjectRust {
249188
#[doc(hidden)]
250-
pub unsafe fn unsafe_invokable_wrapper(self: &MyObjectRust, cpp: &MyObject, param: *mut T) -> *mut T {
251-
return cpp.unsafe_invokable(param);
252-
}
189+
#[cxx_name = "unsafeInvokableWrapper"]
190+
unsafe fn unsafe_invokable(self:&MyObject, param: *mut T) -> *mut T;
253191
}
254192
},
255193
);

crates/cxx-qt-gen/test_outputs/inheritance.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ QVariant
1818
MyObject::data(QModelIndex const& _index, ::std::int32_t _role) const
1919
{
2020
const ::std::lock_guard<::std::recursive_mutex> guard(*m_rustObjMutex);
21-
return m_rustObj->dataWrapper(*this, _index, _role);
21+
return dataWrapper(_index, _role);
2222
}
2323

2424
bool
2525
MyObject::hasChildren(QModelIndex const& _parent) const
2626
{
2727
const ::std::lock_guard<::std::recursive_mutex> guard(*m_rustObjMutex);
28-
return m_rustObj->hasChildrenWrapper(*this, _parent);
28+
return hasChildrenWrapper(_parent);
2929
}
3030

3131
MyObject::MyObject(QObject* parent)

crates/cxx-qt-gen/test_outputs/inheritance.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ class MyObject : public QAbstractItemModel
3737
}
3838
explicit MyObject(QObject* parent = nullptr);
3939

40+
private:
41+
QVariant dataWrapper(QModelIndex const& _index,
42+
::std::int32_t _role) const noexcept;
43+
bool hasChildrenWrapper(QModelIndex const& _parent) const noexcept;
44+
4045
private:
4146
::rust::Box<MyObjectRust> m_rustObj;
4247
::std::shared_ptr<::std::recursive_mutex> m_rustObjMutex;

0 commit comments

Comments
 (0)