Skip to content
Merged
7 changes: 7 additions & 0 deletions book/src/getting-started/2-our-first-cxx-qt-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ These functions then need to be implemented **outside** the bridge using `impl q
{{#include ../../../examples/qml_minimal/rust/src/cxxqt_object.rs:book_rustobj_invokable_impl}}
```

### Inlining the self receiver

If an `extern "RustQt"` block contains exactly one `QObject`, the self type of methods can be inferred.
For instance, in a block with multiple or no `QObject`s, a function like `foo(&self)` or `foo(self: Pin<&mut Self>)`
would not compile, but will compile with the `Self` type set to that blocks `QObject`.
This is how CXX [handles it](https://cxx.rs/extern-rust.html) (see the Methods heading).

This setup is a bit unusual, as the type `qobject::MyObject` is actually defined in C++.
However, it is still possible to add member functions to it in Rust and then expose them back to C++.
This is the usual workflow for `QObject`s in CXX-Qt.
Expand Down
9 changes: 6 additions & 3 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ use std::{
};

use cxx_qt_gen::{
parse_qt_file, write_cpp, write_rust, CppFragment, CxxQtItem, GeneratedCppBlocks, GeneratedOpt,
GeneratedRustBlocks, Parser,
parse_qt_file, self_inlining::qualify_self_types, write_cpp, write_rust, CppFragment,
CxxQtItem, GeneratedCppBlocks, GeneratedOpt, GeneratedRustBlocks, Parser,
};

// TODO: we need to eventually support having multiple modules defined in a single file. This
Expand Down Expand Up @@ -132,7 +132,10 @@ impl GeneratedCpp {
}
found_bridge = true;

let parser = Parser::from(*m.clone())
let mut parser = Parser::from(*m.clone())
.map_err(GeneratedError::from)
.map_err(to_diagnostic)?;
qualify_self_types(&mut parser)
.map_err(GeneratedError::from)
.map_err(to_diagnostic)?;
let generated_cpp = GeneratedCppBlocks::from(&parser, &cxx_qt_opt)
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/src/generator/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl GeneratedRustBlocks {
// Generate a type declaration for `QObject` if necessary
fn add_qobject_import(cxx_qt_data: &ParsedCxxQtData) -> Option<GeneratedRustFragment> {
let includes = cxx_qt_data
.qobjects
.qobjects()
.iter()
.any(|obj| obj.has_qobject_macro && obj.base_class.is_none());
if includes
Expand Down
10 changes: 5 additions & 5 deletions crates/cxx-qt-gen/src/generator/structuring/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ impl<'a> Structures<'a> {
/// Returns an error, if any references could not be resolved.
pub fn new(cxxqtdata: &'a ParsedCxxQtData) -> Result<Self> {
let mut qobjects: Vec<_> = cxxqtdata
.qobjects
.iter()
.qobjects()
.into_iter()
.map(StructuredQObject::from_qobject)
.collect();

Expand All @@ -92,19 +92,19 @@ impl<'a> Structures<'a> {
}

// Associate each method parsed with its appropriate qobject
for method in &cxxqtdata.methods {
for method in cxxqtdata.methods() {
let qobject = find_qobject(&mut qobjects, &method.qobject_ident)?;
qobject.methods.push(method);
}

// Associate each inherited method parsed with its appropriate qobject
for inherited_method in &cxxqtdata.inherited_methods {
for inherited_method in cxxqtdata.inherited_methods() {
let qobject = find_qobject(&mut qobjects, &inherited_method.qobject_ident)?;
qobject.inherited_methods.push(inherited_method);
}

// Associate each signal parsed with its appropriate qobject
for signal in &cxxqtdata.signals {
for signal in cxxqtdata.signals() {
let qobject = find_qobject(&mut qobjects, &signal.qobject_ident)?;
qobject.signals.push(signal);
}
Expand Down
6 changes: 5 additions & 1 deletion crates/cxx-qt-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
mod generator;
mod naming;
mod parser;
mod shorthand;
mod syntax;
mod writer;

Expand All @@ -20,6 +21,7 @@ pub use generator::{
GeneratedOpt,
};
pub use parser::Parser;
pub use shorthand::self_inlining;
pub use syntax::{parse_qt_file, CxxQtFile, CxxQtItem};
pub use writer::{cpp::write_cpp, rust::write_rust};

Expand Down Expand Up @@ -86,6 +88,7 @@ mod tests {
$(assert!($parse_fn(syn::parse_quote! $input).is_err());)*
}
}
use crate::self_inlining::qualify_self_types;
pub(crate) use assert_parse_errors;

/// Helper for formating C++ code
Expand Down Expand Up @@ -174,7 +177,8 @@ mod tests {
expected_cpp_header: &str,
expected_cpp_source: &str,
) {
let parser = Parser::from(syn::parse_str(input).unwrap()).unwrap();
let mut parser = Parser::from(syn::parse_str(input).unwrap()).unwrap();
qualify_self_types(&mut parser).unwrap();

let mut cfg_evaluator = CfgEvaluatorTest::default();
cfg_evaluator.cfgs.insert("crate", Some("cxx-qt-gen"));
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/src/naming/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use syn::{spanned::Spanned, Attribute, Error, Ident, Path, Result};
/// Naming in CXX can be rather complex.
/// The following Rules apply:
/// - If only a cxx_name **or** a rust_name is given, the identifier of the type/function will be
/// used for part that wasn't specified explicitly.
/// used for part that wasn't specified explicitly.
/// - If **both** attributes are present, the identifier itself is not used!
/// - The `rust_name` is always used to refer to the type within the bridge!.
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/src/naming/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl TypeNames {
module_ident: &Ident,
) -> Result<()> {
// Find and register the QObjects in the bridge
for qobject in cxx_qt_data.qobjects.iter() {
for qobject in cxx_qt_data.qobjects() {
self.populate_qobject(qobject)?;
}

Expand Down
Loading
Loading