Skip to content

Commit d752ddb

Browse files
Refactor some generation and parsing for base
1 parent 52b9f7c commit d752ddb

File tree

7 files changed

+86
-84
lines changed

7 files changed

+86
-84
lines changed

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

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

6-
use syn::Item;
6+
use syn::{parse_quote, Item};
77

88
#[derive(Default, Eq, PartialEq, Debug)]
99
pub struct GeneratedRustFragment {
@@ -19,6 +19,19 @@ impl GeneratedRustFragment {
1919
self.cxx_qt_mod_contents.extend(other.cxx_qt_mod_contents);
2020
}
2121

22+
pub fn qobject_import() -> Self {
23+
Self {
24+
cxx_mod_contents: vec![parse_quote! {
25+
extern "C++" {
26+
#[doc(hidden)]
27+
#[namespace=""]
28+
type QObject = cxx_qt::QObject;
29+
}
30+
}],
31+
cxx_qt_mod_contents: vec![],
32+
}
33+
}
34+
2235
// Create a singular GeneratedRustFragment from a Vector of multiple
2336
pub fn flatten(others: Vec<Self>) -> Self {
2437
let mut this = Self::default();
@@ -34,8 +47,4 @@ impl GeneratedRustFragment {
3447
..Default::default()
3548
}
3649
}
37-
38-
pub fn is_empty(&self) -> bool {
39-
self.cxx_mod_contents.is_empty() && self.cxx_qt_mod_contents.is_empty()
40-
}
4150
}

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

Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ pub mod signals;
1616
pub mod threading;
1717

1818
use crate::generator::{rust::fragment::GeneratedRustFragment, structuring};
19-
use crate::parser::externqobject::ParsedExternQObject;
20-
use crate::parser::{parameter::ParsedFunctionParameter, qobject::ParsedQObject, Parser};
19+
use crate::parser::cxxqtdata::ParsedCxxQtData;
20+
use crate::parser::{parameter::ParsedFunctionParameter, Parser};
2121
use proc_macro2::{Ident, TokenStream};
2222
use quote::quote;
2323
use syn::{parse_quote, Item, ItemMod, Result};
@@ -61,12 +61,7 @@ impl GeneratedRustBlocks {
6161
let namespace = parser.cxx_qt_data.namespace.clone().unwrap_or_default();
6262
let passthrough_mod = &parser.passthrough_module;
6363

64-
let qobject_import = add_qobject_import(&parser.cxx_qt_data.qobjects);
65-
if qobject_import.is_empty() {
66-
for block in &parser.cxx_qt_data.extern_cxxqt_blocks {
67-
fragments.push(add_extern_qobject_import(&block.qobjects))
68-
}
69-
} else {
64+
if let Some(qobject_import) = add_qobject_import(&parser.cxx_qt_data) {
7065
fragments.push(qobject_import);
7166
}
7267

@@ -105,48 +100,23 @@ impl GeneratedRustBlocks {
105100
}
106101
}
107102

108-
fn add_qobject_import(qobjects: &[ParsedQObject]) -> GeneratedRustFragment {
109-
let includes = qobjects
103+
// Generate a type declaration for `QObject` if necessary
104+
fn add_qobject_import(cxx_qt_data: &ParsedCxxQtData) -> Option<GeneratedRustFragment> {
105+
let includes = cxx_qt_data
106+
.qobjects
110107
.iter()
111108
.any(|obj| obj.has_qobject_macro && obj.base_class.is_none());
112-
if includes {
113-
GeneratedRustFragment {
114-
cxx_mod_contents: vec![parse_quote! {
115-
extern "C++" {
116-
#[doc(hidden)]
117-
#[namespace=""]
118-
type QObject = cxx_qt::QObject;
119-
}
120-
}],
121-
cxx_qt_mod_contents: vec![],
122-
}
123-
} else {
124-
GeneratedRustFragment {
125-
cxx_mod_contents: vec![],
126-
cxx_qt_mod_contents: vec![],
127-
}
128-
}
129-
}
130-
131-
fn add_extern_qobject_import(qobjects: &[ParsedExternQObject]) -> GeneratedRustFragment {
132-
// All extern C++Qt types must have QObject macro
133-
let includes = qobjects.iter().any(|obj| obj.base_class.is_none());
134-
if includes {
135-
GeneratedRustFragment {
136-
cxx_mod_contents: vec![parse_quote! {
137-
extern "C++" {
138-
#[doc(hidden)]
139-
#[namespace=""]
140-
type QObject = cxx_qt::QObject;
141-
}
142-
}],
143-
cxx_qt_mod_contents: vec![],
144-
}
109+
if includes
110+
|| cxx_qt_data
111+
.extern_cxxqt_blocks
112+
.iter()
113+
.filter(|block| !block.qobjects.is_empty())
114+
.count()
115+
> 0
116+
{
117+
Some(GeneratedRustFragment::qobject_import())
145118
} else {
146-
GeneratedRustFragment {
147-
cxx_mod_contents: vec![],
148-
cxx_qt_mod_contents: vec![],
149-
}
119+
None
150120
}
151121
}
152122

crates/cxx-qt-gen/src/parser/externqobject.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55
use crate::naming::Name;
6-
use crate::parser::{require_attributes, CaseConversion};
7-
use syn::{Error, Expr, ForeignItemType, Ident, Result};
6+
use crate::parser::{parse_base_type, require_attributes, CaseConversion};
7+
use syn::{ForeignItemType, Ident, Result};
88

99
/// A representation of a QObject to be generated in an extern C++ block
1010
pub struct ParsedExternQObject {
@@ -34,20 +34,7 @@ impl ParsedExternQObject {
3434
) -> Result<ParsedExternQObject> {
3535
let attributes = require_attributes(&ty.attrs, &Self::ALLOWED_ATTRS)?;
3636

37-
let base_class = attributes
38-
.get("base")
39-
.map(|attr| -> Result<Ident> {
40-
let expr = &attr.meta.require_name_value()?.value;
41-
if let Expr::Path(path_expr) = expr {
42-
Ok(path_expr.path.require_ident()?.clone())
43-
} else {
44-
Err(Error::new_spanned(
45-
expr,
46-
"Base must be a identifier and cannot be empty!",
47-
))
48-
}
49-
})
50-
.transpose()?;
37+
let base_class = parse_base_type(&attributes)?;
5138

5239
Ok(Self {
5340
name: Name::from_ident_and_attrs(

crates/cxx-qt-gen/src/parser/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,24 @@ pub fn require_attributes<'a>(
140140
Ok(output)
141141
}
142142

143+
// Extract base identifier from attribute
144+
pub fn parse_base_type(attributes: &BTreeMap<&str, &Attribute>) -> Result<Option<Ident>> {
145+
attributes
146+
.get("base")
147+
.map(|attr| -> Result<Ident> {
148+
let expr = &attr.meta.require_name_value()?.value;
149+
if let Expr::Path(path_expr) = expr {
150+
Ok(path_expr.path.require_ident()?.clone())
151+
} else {
152+
Err(Error::new_spanned(
153+
expr,
154+
"Base must be a identifier and cannot be empty!",
155+
))
156+
}
157+
})
158+
.transpose()
159+
}
160+
143161
/// Struct representing the necessary components of a cxx mod to be passed through to generation
144162
pub struct PassthroughMod {
145163
pub(crate) items: Option<Vec<Item>>,

crates/cxx-qt-gen/src/parser/qobject.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use crate::{
1111
#[cfg(test)]
1212
use quote::format_ident;
1313

14-
use crate::parser::CaseConversion;
15-
use syn::{Attribute, Error, Expr, Ident, Meta, Result};
14+
use crate::parser::{parse_base_type, CaseConversion};
15+
use syn::{Attribute, Error, Ident, Meta, Result};
1616

1717
/// Metadata for registering QML element
1818
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@@ -91,20 +91,7 @@ impl ParsedQObject {
9191

9292
let has_qobject_macro = attributes.contains_key("qobject");
9393

94-
let base_class = attributes
95-
.get("base")
96-
.map(|attr| -> Result<Ident> {
97-
let expr = &attr.meta.require_name_value()?.value;
98-
if let Expr::Path(path_expr) = expr {
99-
Ok(path_expr.path.require_ident()?.clone())
100-
} else {
101-
Err(Error::new_spanned(
102-
expr,
103-
"Base must be a identifier and cannot be empty!",
104-
))
105-
}
106-
})
107-
.transpose()?;
94+
let base_class = parse_base_type(&attributes)?;
10895

10996
// Ensure that if there is no qobject macro that a base class is specificed
11097
if !has_qobject_macro && base_class.is_none() {

crates/cxx-qt-gen/test_inputs/inheritance.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ mod inheritance {
1515
type QPushButton;
1616
}
1717

18+
extern "C++Qt" {
19+
#[base = QPushButton]
20+
#[qobject]
21+
type QPushButtonChild;
22+
}
23+
1824
extern "RustQt" {
1925
#[qobject]
2026
#[base = QAbstractItemModel]

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ mod inheritance {
107107
extern "C++" {
108108
include ! (< QtWidgets / QPushButton >);
109109
}
110+
extern "C++" {
111+
#[doc(hidden)]
112+
#[cxx_name = "upcastPtr"]
113+
#[namespace = "rust::cxxqt1"]
114+
unsafe fn cxx_qt_ffi_QPushButtonChild_upcastPtr(
115+
thiz: *const QPushButtonChild,
116+
) -> *const QPushButton;
117+
#[doc(hidden)]
118+
#[cxx_name = "downcastPtr"]
119+
#[namespace = "rust::cxxqt1"]
120+
unsafe fn cxx_qt_ffi_QPushButtonChild_downcastPtr(
121+
base: *const QPushButton,
122+
) -> *const QPushButtonChild;
123+
}
124+
extern "C++" {
125+
type QPushButtonChild;
126+
}
110127
extern "C++" {
111128
#[doc(hidden)]
112129
#[namespace = ""]
@@ -149,3 +166,11 @@ impl ::cxx_qt::Upcast<::cxx_qt::QObject> for inheritance::QPushButton {
149166
inheritance::cxx_qt_ffi_QPushButton_downcastPtr(base)
150167
}
151168
}
169+
impl ::cxx_qt::Upcast<inheritance::QPushButton> for inheritance::QPushButtonChild {
170+
unsafe fn upcast_ptr(this: *const Self) -> *const inheritance::QPushButton {
171+
inheritance::cxx_qt_ffi_QPushButtonChild_upcastPtr(this)
172+
}
173+
unsafe fn from_base_ptr(base: *const inheritance::QPushButton) -> *const Self {
174+
inheritance::cxx_qt_ffi_QPushButtonChild_downcastPtr(base)
175+
}
176+
}

0 commit comments

Comments
 (0)