Skip to content

Commit

Permalink
cxx_qt::Constructor: Add C++ generation
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonMatthesKDAB committed Jun 7, 2023
1 parent edf12cc commit 2793fc8
Show file tree
Hide file tree
Showing 19 changed files with 305 additions and 133 deletions.
128 changes: 128 additions & 0 deletions crates/cxx-qt-gen/src/generator/cpp/constructor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Leon Matthes <leon.matthes@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use super::qobject::GeneratedCppQObjectBlocks;
use crate::{
generator::cpp::{types::CppType, GeneratedCppQObject},
parser::{constructor::Constructor, cxxqtdata::ParsedCxxMappings},
CppFragment,
};

use indoc::formatdoc;
use syn::{Result, Type};

fn default_constructor(
qobject: &GeneratedCppQObject,
initializers: String,
) -> GeneratedCppQObjectBlocks {
GeneratedCppQObjectBlocks {
methods: vec![CppFragment::Pair {
header: format!(
"explicit {class_name}(QObject* parent = nullptr);",
class_name = qobject.ident
),
source: formatdoc!(
r#"
{class_name}::{class_name}(QObject* parent)
: {base_class}(parent)
, m_rustObj({namespace_internals}::createRs())
{initializers}
{{
}}
"#,
class_name = qobject.ident,
base_class = qobject.base_class,
namespace_internals = qobject.namespace_internals,
),
}],
..Default::default()
}
}

fn argument_names(arguments: &[Type]) -> Vec<String> {
arguments
.iter()
.enumerate()
.map(|(index, _)| format!("arg{index}"))
.collect()
}

fn expand_arguments(arguments: &[Type], cxx_mappings: &ParsedCxxMappings) -> Result<String> {
Ok(arguments
.iter()
.zip(argument_names(arguments).into_iter())
.map(|(ty, name)| {
CppType::from(ty, cxx_mappings).map(|ty| format!("{ty} {name}", ty = ty.as_cxx_ty()))
})
.collect::<Result<Vec<_>>>()?
.join(", "))
}

pub fn generate(
qobject: &GeneratedCppQObject,
constructors: &Vec<Constructor>,
member_initializers: &[String],
cxx_mappings: &ParsedCxxMappings,
) -> Result<GeneratedCppQObjectBlocks> {
let initializers = member_initializers
.iter()
.map(|initializer| format!(", {initializer}"))
.collect::<Vec<_>>()
.join("\n");

if constructors.is_empty() {
return Ok(default_constructor(qobject, initializers));
}

let mut generated = GeneratedCppQObjectBlocks::default();

let class_name = qobject.ident.as_str();
let namespace_internals = &qobject.namespace_internals;
let base_class = &qobject.base_class;
for (index, constructor) in constructors.iter().enumerate() {
let argument_list = expand_arguments(&constructor.arguments, cxx_mappings)?;
let constructor_argument_names = argument_names(&constructor.arguments);

generated.methods.push(CppFragment::Pair {
header: format!("explicit {class_name}({argument_list});"),
source: formatdoc! {
r#"
{class_name}::{class_name}({argument_list})
: {class_name}({namespace_internals}::routeArguments{index}({move_arguments}))
{{ }}
"#,
move_arguments = constructor_argument_names.iter().map(|arg| format!("std::move({arg})")).collect::<Vec<_>>().join(", "),
},
});

let base_args = if let Some(base_args) = &constructor.items.base_arguments {
argument_names(base_args)
.into_iter()
.map(|arg| format!("std::move(args.baseArguments.{arg})"))
.collect::<Vec<_>>()
.join(", ")
} else {
"".to_string()
};
generated.private_methods.push(CppFragment::Pair {
header: format!(
"explicit {class_name}({namespace_internals}::CxxQtConstructorArguments{index}&& args);"
),
source: formatdoc! {
r#"
{class_name}::{class_name}({namespace_internals}::CxxQtConstructorArguments{index}&& args)
: {base_class}({base_args})
, m_rustObj({namespace_internals}::newRs{index}(std::move(args.newArguments)))
{initializers}
{{
{namespace_internals}::initialize{index}(*this, std::move(args.initializeArguments));
}}
"#,
},
})
}

Ok(generated)
}
1 change: 1 addition & 0 deletions crates/cxx-qt-gen/src/generator/cpp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

mod constructor;
pub mod fragment;
pub mod inherit;
pub mod invokable;
Expand Down
25 changes: 20 additions & 5 deletions crates/cxx-qt-gen/src/generator/cpp/qobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use crate::generator::{
cpp::{
fragment::CppFragment, inherit, invokable::generate_cpp_invokables,
constructor, fragment::CppFragment, inherit, invokable::generate_cpp_invokables,
property::generate_cpp_properties, signal::generate_cpp_signals, threading,
},
naming::{namespace::NamespaceName, qobject::QObjectName},
Expand All @@ -21,8 +21,10 @@ pub struct GeneratedCppQObjectBlocks {
pub metaobjects: Vec<String>,
/// List of public methods for the QObject
pub methods: Vec<CppFragment>,
/// List of private methods for the QObject
pub private_methods: Vec<CppFragment>,
/// List of members for the QObject
pub members: Vec<CppFragment>,
pub members: Vec<String>,
/// List of deconstructor source
pub deconstructors: Vec<String>,
}
Expand All @@ -32,6 +34,7 @@ impl GeneratedCppQObjectBlocks {
self.forward_declares.append(&mut other.forward_declares);
self.metaobjects.append(&mut other.metaobjects);
self.methods.append(&mut other.methods);
self.private_methods.append(&mut other.private_methods);
self.members.append(&mut other.members);
self.deconstructors.append(&mut other.deconstructors);
}
Expand Down Expand Up @@ -130,12 +133,24 @@ impl GeneratedCppQObject {
cxx_mappings,
)?);

let mut member_initializers =
if qobject.locking {
vec!["m_rustObjMutex(::std::make_shared<::std::recursive_mutex>())".to_string()]
} else {
vec![]
};
// If this type has threading enabled then add generation
if qobject.threading {
generated
.blocks
.append(&mut threading::generate(&qobject_idents)?);
let (initializer, mut blocks) = threading::generate(&qobject_idents)?;
generated.blocks.append(&mut blocks);
member_initializers.push(initializer);
}
generated.blocks.append(&mut constructor::generate(
&generated,
&qobject.constructors,
&member_initializers,
cxx_mappings,
)?);

Ok(generated)
}
Expand Down
26 changes: 10 additions & 16 deletions crates/cxx-qt-gen/src/generator/cpp/threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::generator::{
use indoc::formatdoc;
use syn::Result;

pub fn generate(qobject_idents: &QObjectName) -> Result<GeneratedCppQObjectBlocks> {
pub fn generate(qobject_idents: &QObjectName) -> Result<(String, GeneratedCppQObjectBlocks)> {
let mut result = GeneratedCppQObjectBlocks::default();

let ident = &qobject_idents.cpp_class.cpp;
Expand All @@ -19,10 +19,10 @@ pub fn generate(qobject_idents: &QObjectName) -> Result<GeneratedCppQObjectBlock
result.forward_declares.push(format!(
"using {cxx_qt_thread_ident} = ::rust::cxxqtlib1::CxxQtThread<{ident}>;"
));
result.members.push(CppFragment::Pair {
header: format!("::std::shared_ptr<::rust::cxxqtlib1::CxxQtGuardedPointer<{ident}>> m_cxxQtThreadObj;"),
source: format!(", m_cxxQtThreadObj(::std::make_shared<::rust::cxxqtlib1::CxxQtGuardedPointer<{ident}>>(this))"),
});
result.members.push(format!(
"::std::shared_ptr<::rust::cxxqtlib1::CxxQtGuardedPointer<{ident}>> m_cxxQtThreadObj;"
));
let member_initializer = format!("m_cxxQtThreadObj(::std::make_shared<::rust::cxxqtlib1::CxxQtGuardedPointer<{ident}>>(this))");
result.methods.push(CppFragment::Pair {
header: format!("::std::unique_ptr<{cxx_qt_thread_ident}> qtThread() const;"),
source: formatdoc! {
Expand All @@ -42,7 +42,7 @@ pub fn generate(qobject_idents: &QObjectName) -> Result<GeneratedCppQObjectBlock
"#
});

Ok(result)
Ok((member_initializer, result))
}

#[cfg(test)]
Expand All @@ -57,7 +57,7 @@ mod tests {
fn test_generate_cpp_threading() {
let qobject_idents = create_qobjectname();

let generated = generate(&qobject_idents).unwrap();
let (initializer, generated) = generate(&qobject_idents).unwrap();

// forward declares
assert_eq!(generated.forward_declares.len(), 1);
Expand All @@ -69,19 +69,13 @@ mod tests {

// members
assert_eq!(generated.members.len(), 1);

let (header, source) = if let CppFragment::Pair { header, source } = &generated.members[0] {
(header, source)
} else {
panic!("Expected pair")
};
assert_str_eq!(
header,
&generated.members[0],
"::std::shared_ptr<::rust::cxxqtlib1::CxxQtGuardedPointer<MyObject>> m_cxxQtThreadObj;"
);
assert_str_eq!(
source,
", m_cxxQtThreadObj(::std::make_shared<::rust::cxxqtlib1::CxxQtGuardedPointer<MyObject>>(this))"
initializer,
"m_cxxQtThreadObj(::std::make_shared<::rust::cxxqtlib1::CxxQtGuardedPointer<MyObject>>(this))"
);

// methods
Expand Down
10 changes: 6 additions & 4 deletions crates/cxx-qt-gen/src/parser/qobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use crate::syntax::{
attribute::{attribute_find_path, attribute_tokens_to_map, AttributeDefault},
fields::fields_to_named_fields_mut,
use crate::{
parser::{
constructor::Constructor,
inherit::ParsedInheritedMethod,
invokable::ParsedQInvokable,
property::{ParsedQProperty, ParsedRustField},
signals::ParsedSignalsEnum,
},
syntax::path::path_compare_str,
syntax::{
path::path_compare_str,
attribute::{attribute_find_path, attribute_tokens_to_map, AttributeDefault},
fields::fields_to_named_fields_mut,
},
};
use syn::{
spanned::Spanned, Error, Fields, Ident, ImplItem, ImplItemFn, Item, ItemImpl, ItemStruct,
Expand Down
9 changes: 5 additions & 4 deletions crates/cxx-qt-gen/src/writer/cpp/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ fn qobjects_header(generated: &GeneratedCppBlocks) -> Vec<String> {
{metaobjects}
public:
explicit {ident}(QObject* parent = nullptr);
~{ident}();
{rust_ident} const& unsafeRust() const;
{rust_ident}& unsafeRustMut();
{methods}
{public_methods}
{private_methods}
private:
{members}
}};
Expand All @@ -94,7 +94,8 @@ fn qobjects_header(generated: &GeneratedCppBlocks) -> Vec<String> {
rust_ident = qobject.rust_ident,
base_class = qobject.base_class,
metaobjects = qobject.blocks.metaobjects.join("\n "),
methods = create_block("public", &qobject.blocks.methods.iter().filter_map(pair_as_header).collect::<Vec<String>>()),
public_methods = create_block("public", &qobject.blocks.methods.iter().filter_map(pair_as_header).collect::<Vec<String>>()),
private_methods = create_block("private", &qobject.blocks.private_methods.iter().filter_map(pair_as_header).collect::<Vec<String>>()),
members = {
let mut members = vec![
format!("::rust::Box<{rust_ident}> m_rustObj;", rust_ident = qobject.rust_ident),
Expand All @@ -106,7 +107,7 @@ fn qobjects_header(generated: &GeneratedCppBlocks) -> Vec<String> {
]);
}

members.extend(qobject.blocks.members.iter().filter_map(pair_as_header).collect::<Vec<String>>());
members.extend(qobject.blocks.members.iter().cloned());
members.join("\n ")
},
metatype = if generated.namespace.is_empty() {
Expand Down
Loading

0 comments on commit 2793fc8

Please sign in to comment.