Skip to content

Commit

Permalink
refactor: Use Name for C++ QObject generation
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonMatthesKDAB committed May 21, 2024
1 parent 2ce7481 commit b3b7725
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 79 deletions.
23 changes: 9 additions & 14 deletions crates/cxx-qt-gen/src/generator/cpp/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,24 @@ fn default_constructor(
base_class: String,
initializers: String,
) -> GeneratedCppQObjectBlocks {
let class_name = qobject.name.cxx_unqualified();
let rust_obj = qobject.rust_struct.cxx_qualified();
let constructor = if qobject.has_qobject_macro {
CppFragment::Pair {
header: format!(
"explicit {class_name}(QObject* parent = nullptr);",
class_name = qobject.ident
),
header: format!("explicit {class_name}(QObject* parent = nullptr);",),
source: formatdoc!(
r#"
{class_name}::{class_name}(QObject* parent)
: {base_class}(parent)
, ::rust::cxxqt1::CxxQtType<{rust_obj}>(::{namespace_internals}::createRs()){initializers}
{{ }}
"#,
class_name = qobject.ident,
namespace_internals = qobject.namespace_internals,
rust_obj = qobject.rust_ident,
),
}
} else {
CppFragment::Pair {
header: format!("explicit {class_name}();", class_name = qobject.ident),
header: format!("explicit {class_name}();"),
source: formatdoc!(
r#"
{class_name}::{class_name}()
Expand All @@ -52,9 +49,7 @@ fn default_constructor(
} else {
format!(": {base_class}()")
},
class_name = qobject.ident,
namespace_internals = qobject.namespace_internals,
rust_obj = qobject.rust_ident,
),
}
};
Expand Down Expand Up @@ -101,8 +96,8 @@ pub fn generate(

let mut generated = GeneratedCppQObjectBlocks::default();

let class_name = qobject.ident.as_str();
let rust_obj = qobject.rust_ident.as_str();
let class_name = qobject.name.cxx_unqualified();
let rust_obj = qobject.rust_struct.cxx_qualified();
let namespace_internals = &qobject.namespace_internals;
for (index, constructor) in constructors.iter().enumerate() {
let argument_list = expand_arguments(&constructor.arguments, type_names)?;
Expand Down Expand Up @@ -160,6 +155,7 @@ pub fn generate(
mod tests {
use super::*;

use crate::naming::Name;
use syn::parse_quote;

fn type_names_with_qobject() -> TypeNames {
Expand All @@ -170,9 +166,8 @@ mod tests {

fn qobject_for_testing() -> GeneratedCppQObject {
GeneratedCppQObject {
ident: "MyObject".to_string(),
rust_ident: "MyObjectRust".to_string(),
namespace: "".to_string(),
name: Name::mock("MyObject"),
rust_struct: Name::mock("MyObjectRust"),
namespace_internals: "rust".to_string(),
blocks: GeneratedCppQObjectBlocks::default(),
has_qobject_macro: true,
Expand Down
6 changes: 3 additions & 3 deletions crates/cxx-qt-gen/src/generator/cpp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ mod tests {
let cpp = GeneratedCppBlocks::from(&parser).unwrap();
assert_eq!(cpp.cxx_file_stem, "ffi");
assert_eq!(cpp.qobjects.len(), 1);
assert_eq!(cpp.qobjects[0].namespace, "");
assert_eq!(cpp.qobjects[0].name.namespace(), None);
}

#[test]
Expand All @@ -119,7 +119,7 @@ mod tests {
let cpp = GeneratedCppBlocks::from(&parser).unwrap();
assert_eq!(cpp.cxx_file_stem, "my_object");
assert_eq!(cpp.qobjects.len(), 1);
assert_eq!(&cpp.qobjects[0].namespace, "");
assert_eq!(cpp.qobjects[0].name.namespace(), None);
}

#[test]
Expand All @@ -136,6 +136,6 @@ mod tests {
let parser = Parser::from(module).unwrap();

let cpp = GeneratedCppBlocks::from(&parser).unwrap();
assert_eq!(cpp.qobjects[0].namespace, "cxx_qt");
assert_eq!(cpp.qobjects[0].name.namespace(), Some("cxx_qt"));
}
}
59 changes: 29 additions & 30 deletions crates/cxx-qt-gen/src/generator/cpp/qobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use crate::generator::{
cpp::{
constructor, cxxqttype, fragment::CppFragment, inherit, locking,
method::generate_cpp_methods, property::generate_cpp_properties, qenum,
signal::generate_cpp_signals, threading,
use crate::{
generator::{
cpp::{
constructor, cxxqttype, fragment::CppFragment, inherit, locking,
method::generate_cpp_methods, property::generate_cpp_properties, qenum,
signal::generate_cpp_signals, threading,
},
naming::{namespace::NamespaceName, qobject::QObjectName},
structuring::StructuredQObject,
},
naming::{namespace::NamespaceName, qobject::QObjectName},
structuring::StructuredQObject,
naming::Name,
};
use crate::{naming::TypeNames, parser::qobject::ParsedQObject};
use std::collections::BTreeSet;
Expand Down Expand Up @@ -80,15 +83,11 @@ impl GeneratedCppQObjectBlocks {
}
}

#[derive(Default)]
pub struct GeneratedCppQObject {
/// Ident of the C++ QObject
pub ident: String,
/// Ident of the Rust object
pub rust_ident: String,
/// Ident of the QObject namespace
/// If one isn't specified on the QObject, it's the same as the module.
pub namespace: String,
/// Name of the QObject, with associated namespace, cxx_name, etc.
pub name: Name,
/// Name of the Rust struct that this QObject is associated with
pub rust_struct: Name,
/// Ident of the namespace for CXX-Qt internals of the QObject
pub namespace_internals: String,
/// The blocks of the QObject
Expand All @@ -107,11 +106,9 @@ impl GeneratedCppQObject {
// Create the base object
let qobject_idents = QObjectName::from(qobject);
let namespace_idents = NamespaceName::from(qobject);
let cpp_class = qobject_idents.cpp_class.cpp.to_string();
let mut generated = GeneratedCppQObject {
ident: cpp_class.clone(),
rust_ident: qobject_idents.rust_struct.cpp.to_string(),
namespace: qobject.name.namespace().unwrap_or_default().to_owned(),
name: qobject.name.clone(),
rust_struct: type_names.lookup(&qobject.rust_type)?.clone(),
namespace_internals: namespace_idents.internal,
blocks: GeneratedCppQObjectBlocks::from(qobject),
has_qobject_macro: qobject.has_qobject_macro,
Expand Down Expand Up @@ -219,10 +216,10 @@ mod tests {
let structures = Structures::new(&parser.cxx_qt_data).unwrap();

let cpp =
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::default())
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::mock())
.unwrap();
assert_eq!(cpp.ident, "MyObject");
assert_eq!(cpp.rust_ident, "MyObjectRust");
assert_eq!(cpp.name.cxx_unqualified(), "MyObject");
assert_eq!(cpp.rust_struct.cxx_unqualified(), "MyObjectRust");
assert_eq!(cpp.namespace_internals, "cxx_qt_my_object");

assert_eq!(cpp.blocks.base_classes.len(), 3);
Expand Down Expand Up @@ -251,7 +248,7 @@ mod tests {
let structures = Structures::new(&parser.cxx_qt_data).unwrap();

let cpp =
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::default())
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::mock())
.unwrap();
assert_eq!(cpp.namespace_internals, "cxx_qt::cxx_qt_my_object");
assert_eq!(cpp.blocks.base_classes.len(), 3);
Expand Down Expand Up @@ -279,10 +276,12 @@ mod tests {
let parser = Parser::from(module).unwrap();
let structures = Structures::new(&parser.cxx_qt_data).unwrap();

let mut type_names = TypeNames::default();
type_names.mock_insert("MyNamedObject", None, None, None);
type_names.mock_insert("MyNamedObjectRust", None, None, None);
let cpp =
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::default())
.unwrap();
assert_eq!(cpp.ident, "MyNamedObject");
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &type_names).unwrap();
assert_eq!(cpp.name.cxx_unqualified(), "MyNamedObject");
assert_eq!(cpp.blocks.metaobjects.len(), 1);
assert_eq!(
cpp.blocks.metaobjects[0],
Expand All @@ -307,9 +306,9 @@ mod tests {
let structures = Structures::new(&parser.cxx_qt_data).unwrap();

let cpp =
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::default())
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::mock())
.unwrap();
assert_eq!(cpp.ident, "MyObject");
assert_eq!(cpp.name.cxx_unqualified(), "MyObject");
assert_eq!(cpp.blocks.metaobjects.len(), 2);
assert_eq!(
cpp.blocks.metaobjects[0],
Expand All @@ -335,9 +334,9 @@ mod tests {
let structures = Structures::new(&parser.cxx_qt_data).unwrap();

let cpp =
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::default())
GeneratedCppQObject::from(structures.qobjects.first().unwrap(), &TypeNames::mock())
.unwrap();
assert_eq!(cpp.ident, "MyObject");
assert_eq!(cpp.name.cxx_unqualified(), "MyObject");
assert_eq!(cpp.blocks.metaobjects.len(), 2);
assert_eq!(
cpp.blocks.metaobjects[0],
Expand Down
20 changes: 20 additions & 0 deletions crates/cxx-qt-gen/src/naming/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,24 @@ impl Name {
cxx_name
}
}

#[cfg(test)]
pub fn mock(ident: &str) -> Self {
Self {
rust: format_ident!("{ident}"),
cxx: None,
module: Some(Path::from(format_ident!("qobject"))),
namespace: None,
}
}

#[cfg(test)]
pub fn mock_namespaced(ident: &str, namespace: &str) -> Self {
Self {
rust: format_ident!("{ident}"),
cxx: None,
module: Some(Path::from(format_ident!("qobject"))),
namespace: Some(namespace.to_owned()),
}
}
}
29 changes: 24 additions & 5 deletions crates/cxx-qt-gen/src/naming/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ use syn::{
Path, Result,
};

use crate::syntax::{
attribute::attribute_find_path, expr::expr_to_string,
foreignmod::foreign_mod_to_foreign_item_types,
use crate::{
parser::qobject::ParsedQObject,
syntax::{
attribute::attribute_find_path, expr::expr_to_string,
foreignmod::foreign_mod_to_foreign_item_types,
},
};

use super::Name;
Expand Down Expand Up @@ -139,14 +142,25 @@ impl TypeNames {
Ok(())
}

fn populate_qobject(&mut self, qobject: &ParsedQObject) -> Result<()> {
self.insert(qobject.name.clone())?;
// Insert the Rust type.
self.insert(Name {
rust: qobject.rust_type.clone(),
cxx: None,
namespace: None,
module: qobject.name.module.clone(),
})
}

fn populate_from_cxx_qt_data(
&mut self,
cxx_qt_data: &ParsedCxxQtData,
bridge_namespace: Option<&str>,
module_ident: &Ident,
) -> Result<()> {
for qobject in cxx_qt_data.qobjects.values() {
self.insert(qobject.name.clone())?;
self.populate_qobject(qobject)?;
}

for qenum in &cxx_qt_data.qenums {
Expand Down Expand Up @@ -268,7 +282,10 @@ impl TypeNames {
Error::new_spanned(ident, format!("Undeclared type: `{ident}`!"))
}

fn lookup(&self, ident: &Ident) -> Result<&Name> {
/// For a given ident in the CXX bridge, return the Name struct for the type or an error if it's not found.
/// This allows access to all parts (renamed CXX name, namespace, etc.) of a given type by
/// identifier.
pub fn lookup(&self, ident: &Ident) -> Result<&Name> {
self.names
.get(ident)
.ok_or_else(|| self.unknown_type(ident))
Expand Down Expand Up @@ -381,9 +398,11 @@ impl TypeNames {

#[cfg(test)]
// Only for testing, return a TypeNames struct that contains a qobject::MyObject
// and an associated MyObjectRust
pub fn mock() -> Self {
let mut this = Self::default();
this.mock_insert("MyObject", Some(format_ident!("qobject")), None, None);
this.mock_insert("MyObjectRust", Some(format_ident!("qobject")), None, None);
this
}

Expand Down
33 changes: 31 additions & 2 deletions crates/cxx-qt-gen/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,21 @@ mod tests {
assert_eq!(parser.passthrough_module.content.unwrap().1.len(), 0);
assert_eq!(parser.cxx_qt_data.namespace, Some("cxx_qt".to_owned()));
assert_eq!(parser.cxx_qt_data.qobjects.len(), 1);
assert_eq!(parser.type_names.num_types(), 17);
assert_eq!(parser.type_names.num_types(), 18);
assert_eq!(
parser
.type_names
.rust_qualified(&format_ident!("MyObject"))
.unwrap(),
parse_quote! { ffi::MyObject }
);
assert_eq!(
parser
.type_names
.rust_qualified(&format_ident!("MyObjectRust"))
.unwrap(),
parse_quote! { ffi::MyObjectRust }
);
}

#[test]
Expand Down Expand Up @@ -316,7 +323,7 @@ mod tests {
}
};
let parser = Parser::from(module).unwrap();
assert_eq!(parser.type_names.num_types(), 19);
assert_eq!(parser.type_names.num_types(), 22);
assert_eq!(
parser
.type_names
Expand All @@ -341,5 +348,27 @@ mod tests {
.unwrap(),
"extern_namespace"
);

assert_eq!(
parser
.type_names
.namespace(&format_ident!("MyObjectARust"))
.unwrap(),
None
);
assert_eq!(
parser
.type_names
.namespace(&format_ident!("MyObjectBRust"))
.unwrap(),
None
);
assert_eq!(
parser
.type_names
.namespace(&format_ident!("MyObjectCRust"))
.unwrap(),
None
);
}
}
Loading

0 comments on commit b3b7725

Please sign in to comment.