Skip to content

Commit 4843bb2

Browse files
committed
cxx-qt-gen: add support for multiple QObjects in writer/cpp
1 parent c4821da commit 4843bb2

File tree

6 files changed

+633
-231
lines changed

6 files changed

+633
-231
lines changed

cxx-qt-gen/src/gen_cpp.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use proc_macro2::TokenStream;
1010
use syn::Ident;
1111

1212
use crate::extract::{Invokable, Parameter, ParameterType, Property, QObject, QtTypes, Signal};
13-
use crate::generator::cpp::{fragment::CppFragmentPair, GeneratedCppBlocks};
13+
use crate::generator::cpp::{
14+
fragment::CppFragmentPair, qobject::GeneratedCppQObjectBlocks, GeneratedCppBlocks,
15+
};
1416
use crate::writer::cpp::write_cpp;
1517

1618
/// A trait which we implement on QtTypes allowing retrieval of attributes of the enum value.
@@ -849,12 +851,10 @@ pub fn generate_qobject_cpp(obj: &QObject) -> Result<CppObject, TokenStream> {
849851
obj.ident.to_string().to_case(Case::Snake)
850852
));
851853

852-
// For now convert our gen_cpp code into the GeneratedCppBlocks struct
853-
let generated = GeneratedCppBlocks {
854-
cxx_stem: struct_ident_str.to_case(Case::Snake),
855-
ident: struct_ident_str,
854+
// For now we only create a single QObject
855+
let qobjects = vec![GeneratedCppQObjectBlocks {
856+
ident: struct_ident_str.clone(),
856857
rust_ident: rust_struct_ident,
857-
namespace: obj.namespace.clone(),
858858
namespace_internals: namespace_internals.join("::"),
859859
base_class: obj
860860
.base_class
@@ -865,6 +865,13 @@ pub fn generate_qobject_cpp(obj: &QObject) -> Result<CppObject, TokenStream> {
865865
slots,
866866
signals,
867867
members,
868+
}];
869+
870+
// For now convert our gen_cpp code into the GeneratedCppBlocks struct
871+
let generated = GeneratedCppBlocks {
872+
cxx_stem: struct_ident_str.to_case(Case::Snake),
873+
namespace: obj.namespace.clone(),
874+
qobjects,
868875
};
869876

870877
// Use our writer phase to convert to a string

cxx-qt-gen/src/generator/cpp/mod.rs

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,14 @@
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

66
pub mod fragment;
7+
pub mod qobject;
78

8-
use fragment::CppFragmentPair;
9-
10-
/// Representation of the generated C++ code for a QObject
9+
/// Representation of the generated C++ code for a group of QObjects
1110
pub struct GeneratedCppBlocks {
1211
/// Stem of the CXX header to include
1312
pub cxx_stem: String,
14-
/// Ident of the C++ QObject
15-
pub ident: String,
16-
/// Ident of the Rust object
17-
pub rust_ident: String,
18-
/// Ident of the namespace of the QObject
13+
/// Ident of the common namespace of the QObjects
1914
pub namespace: String,
20-
/// Ident of the namespace for CXX-Qt internals of the QObject
21-
pub namespace_internals: String,
22-
/// Base class of the QObject
23-
pub base_class: String,
24-
/// List of Qt Meta Object items (eg Q_PROPERTY)
25-
pub metaobjects: Vec<String>,
26-
/// List of public methods for the QObject
27-
pub methods: Vec<CppFragmentPair>,
28-
/// List of public Q_SLOTS for the QObject
29-
pub slots: Vec<CppFragmentPair>,
30-
/// List of public Q_SIGNALS for the QObject
31-
pub signals: Vec<String>,
32-
/// List of private members for the QObject
33-
pub members: Vec<String>,
15+
/// Generated QObject blocks
16+
pub qobjects: Vec<qobject::GeneratedCppQObjectBlocks>,
3417
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
2+
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
3+
//
4+
// SPDX-License-Identifier: MIT OR Apache-2.0
5+
6+
use crate::generator::cpp::fragment::CppFragmentPair;
7+
8+
pub struct GeneratedCppQObjectBlocks {
9+
/// Ident of the C++ QObject
10+
pub ident: String,
11+
/// Ident of the Rust object
12+
pub rust_ident: String,
13+
/// Ident of the namespace for CXX-Qt internals of the QObject
14+
pub namespace_internals: String,
15+
/// Base class of the QObject
16+
pub base_class: String,
17+
/// List of Qt Meta Object items (eg Q_PROPERTY)
18+
pub metaobjects: Vec<String>,
19+
/// List of public methods for the QObject
20+
pub methods: Vec<CppFragmentPair>,
21+
/// List of public Q_SLOTS for the QObject
22+
pub slots: Vec<CppFragmentPair>,
23+
/// List of public Q_SIGNALS for the QObject
24+
pub signals: Vec<String>,
25+
/// List of private members for the QObject
26+
pub members: Vec<String>,
27+
}

cxx-qt-gen/src/writer/cpp/header.rs

Lines changed: 94 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

66
use crate::generator::cpp::{fragment::CppFragmentPair, GeneratedCppBlocks};
7+
use crate::writer::cpp::namespace_pair;
78
use indoc::formatdoc;
89

910
/// Extract the header from a given CppFragmentPair
@@ -33,80 +34,104 @@ fn create_block(block: &str, items: &[&str]) -> String {
3334
}
3435
}
3536

36-
/// For a given GeneratedCppBlocks write this into a C++ header
37-
pub fn write_cpp_header(generated: &GeneratedCppBlocks) -> String {
38-
formatdoc! {r#"
39-
#pragma once
37+
/// For a given GeneratedCppBlocks write the forward declare
38+
fn forward_declare(generated: &GeneratedCppBlocks) -> Vec<String> {
39+
let (namespace_start, namespace_end) = namespace_pair(generated);
40+
41+
generated
42+
.qobjects
43+
.iter()
44+
.map(|qobject| {
45+
formatdoc! { r#"
46+
{namespace_start}
47+
class {ident};
48+
{namespace_end}
49+
"#,
50+
ident = qobject.ident,
51+
namespace_start = namespace_start,
52+
namespace_end = namespace_end,
53+
}
54+
})
55+
.collect::<Vec<String>>()
56+
}
4057

41-
#include <memory>
42-
#include <mutex>
58+
/// For a given GeneratedCppBlocks write the classes
59+
fn qobjects_header(generated: &GeneratedCppBlocks) -> Vec<String> {
60+
let (namespace_start, namespace_end) = namespace_pair(generated);
4361

44-
{namespace_start}
45-
class {ident};
46-
{namespace_end}
62+
generated.qobjects.iter().map(|qobject| {
63+
formatdoc! { r#"
64+
{namespace_start}
4765
48-
#include "cxx-qt-gen/include/{cxx_stem}.cxx.h"
66+
class {ident} : public {base_class}
67+
{{
68+
Q_OBJECT
69+
{metaobjects}
4970
50-
{namespace_start}
71+
public:
72+
explicit {ident}(QObject* parent = nullptr);
73+
~{ident}();
74+
const {rust_ident}& unsafeRust() const;
75+
{rust_ident}& unsafeRustMut();
5176
52-
class {ident} : public {base_class}
53-
{{
54-
Q_OBJECT
55-
{metaobjects}
77+
{methods}
78+
{slots}
79+
{signals}
80+
private:
81+
rust::Box<{rust_ident}> m_rustObj;
82+
std::mutex m_rustObjMutex;
83+
bool m_initialised = false;
5684
57-
public:
58-
explicit {ident}(QObject* parent = nullptr);
59-
~{ident}();
60-
const {rust_ident}& unsafeRust() const;
61-
{rust_ident}& unsafeRustMut();
85+
{members}
86+
}};
6287
63-
{methods}
64-
{slots}
65-
{signals}
66-
private:
67-
rust::Box<{rust_ident}> m_rustObj;
68-
std::mutex m_rustObjMutex;
69-
bool m_initialised = false;
88+
static_assert(std::is_base_of<QObject, {ident}>::value, "{ident} must inherit from QObject");
7089
71-
{members}
72-
}};
90+
{namespace_end}
7391
74-
static_assert(std::is_base_of<QObject, {ident}>::value, "{ident} must inherit from QObject");
92+
namespace {namespace_internals} {{
93+
std::unique_ptr<{ident}>
94+
newCppObject();
95+
}} // namespace {namespace_internals}
7596
76-
{namespace_end}
97+
Q_DECLARE_METATYPE({metatype}*)
98+
"#,
99+
ident = qobject.ident,
100+
namespace_start = namespace_start,
101+
namespace_end = namespace_end,
102+
namespace_internals = qobject.namespace_internals,
103+
rust_ident = qobject.rust_ident,
104+
base_class = qobject.base_class,
105+
metaobjects = qobject.metaobjects.join("\n "),
106+
methods = create_block("public", &qobject.methods.iter().map(pair_as_header).collect::<Vec<&str>>()),
107+
slots = create_block("public Q_SLOTS", &qobject.slots.iter().map(pair_as_header).collect::<Vec<&str>>()),
108+
signals = create_block("Q_SIGNALS", &qobject.signals.iter().map(AsRef::as_ref).collect::<Vec<&str>>()),
109+
members = qobject.members.join("\n "),
110+
metatype = if generated.namespace.is_empty() {
111+
qobject.ident.clone()
112+
} else {
113+
format!("{namespace}::{ident}", namespace = generated.namespace, ident = qobject.ident)
114+
},
115+
}
116+
}).collect::<Vec<String>>()
117+
}
77118

78-
namespace {namespace_internals} {{
79-
std::unique_ptr<{ident}>
80-
newCppObject();
81-
}} // namespace {namespace_internals}
119+
/// For a given GeneratedCppBlocks write this into a C++ header
120+
pub fn write_cpp_header(generated: &GeneratedCppBlocks) -> String {
121+
formatdoc! {r#"
122+
#pragma once
82123
83-
Q_DECLARE_METATYPE({metatype}*)
124+
#include <memory>
125+
#include <mutex>
126+
127+
{forward_declare}
128+
#include "cxx-qt-gen/include/{cxx_stem}.cxx.h"
129+
130+
{qobjects}
84131
"#,
85132
cxx_stem = generated.cxx_stem,
86-
ident = generated.ident,
87-
namespace_start = if generated.namespace.is_empty() {
88-
"".to_owned()
89-
} else {
90-
format!("namespace {namespace} {{", namespace = generated.namespace)
91-
},
92-
namespace_end = if generated.namespace.is_empty() {
93-
"".to_owned()
94-
} else {
95-
format!("}} // namespace {namespace}", namespace = generated.namespace)
96-
},
97-
namespace_internals = generated.namespace_internals,
98-
rust_ident = generated.rust_ident,
99-
base_class = generated.base_class,
100-
metaobjects = generated.metaobjects.join("\n "),
101-
methods = create_block("public", &generated.methods.iter().map(pair_as_header).collect::<Vec<&str>>()),
102-
slots = create_block("public Q_SLOTS", &generated.slots.iter().map(pair_as_header).collect::<Vec<&str>>()),
103-
signals = create_block("Q_SIGNALS", &generated.signals.iter().map(AsRef::as_ref).collect::<Vec<&str>>()),
104-
members = generated.members.join("\n "),
105-
metatype = if generated.namespace.is_empty() {
106-
generated.ident.clone()
107-
} else {
108-
format!("{namespace}::{ident}", namespace = generated.namespace, ident = generated.ident)
109-
},
133+
forward_declare = forward_declare(generated).join("\n"),
134+
qobjects = qobjects_header(generated).join("\n"),
110135
}
111136
}
112137

@@ -115,7 +140,8 @@ mod tests {
115140
use super::*;
116141

117142
use crate::writer::cpp::tests::{
118-
create_generated_cpp, create_generated_cpp_no_namespace, expected_header,
143+
create_generated_cpp, create_generated_cpp_multi_qobjects,
144+
create_generated_cpp_no_namespace, expected_header, expected_header_multi_qobjects,
119145
expected_header_no_namespace,
120146
};
121147
use indoc::indoc;
@@ -150,6 +176,13 @@ mod tests {
150176
assert_str_eq!(output, expected_header());
151177
}
152178

179+
#[test]
180+
fn test_write_cpp_header_multi_qobjects() {
181+
let generated = create_generated_cpp_multi_qobjects();
182+
let output = write_cpp_header(&generated);
183+
assert_str_eq!(output, expected_header_multi_qobjects());
184+
}
185+
153186
#[test]
154187
fn test_write_cpp_header_no_namespace() {
155188
let generated = create_generated_cpp_no_namespace();

0 commit comments

Comments
 (0)