Skip to content

Commit 20dd5ad

Browse files
fix: Allow generated methods to be reused by other properties
- Add list of methods pending generation - Perform a lookup in the pending methods if they aren't found in the bridge - Use name of pending method if found
1 parent d795722 commit 20dd5ad

File tree

6 files changed

+101
-5
lines changed

6 files changed

+101
-5
lines changed

crates/cxx-qt-gen/src/generator/naming/property.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -126,32 +126,32 @@ fn capitalise_first(str: String) -> String {
126126
}
127127

128128
/// For a given property name generate the getter name
129-
fn getter_name_from_property(name: &Name) -> Name {
129+
pub fn getter_name_from_property(name: &Name) -> Name {
130130
name.clone()
131131
.with_cxx_name(format!("get{}", capitalise_first(name.cxx_unqualified())))
132132
}
133133

134134
/// For a given property name generate the setter name
135-
fn setter_name_from_property(name: &Name) -> Name {
135+
pub fn setter_name_from_property(name: &Name) -> Name {
136136
name.clone()
137137
.with_rust_name(format_ident!("set_{}", name.rust_unqualified()))
138138
.with_cxx_name(format!("set{}", capitalise_first(name.cxx_unqualified())))
139139
}
140140

141141
/// For a given property name generate the notify signal name
142-
fn notify_name_from_property(name: &Name) -> Name {
142+
pub fn notify_name_from_property(name: &Name) -> Name {
143143
name.clone()
144144
.with_rust_name(format_ident!("{}_changed", name.rust_unqualified()))
145145
.with_cxx_name(format!("{}Changed", name.cxx_unqualified()))
146146
}
147147

148148
#[cfg(test)]
149149
pub mod tests {
150-
use syn::parse_quote;
151-
152150
use super::*;
153151
use crate::parser::property::QPropertyFlags;
154152
use crate::parser::qobject::ParsedQObject;
153+
use crate::parser::CaseConversion;
154+
use syn::{parse_quote, ItemStruct};
155155

156156
pub fn create_i32_qpropertyname() -> QPropertyNames {
157157
let property = ParsedQProperty {
@@ -167,6 +167,21 @@ pub mod tests {
167167
.expect("Failed to create QPropertyNames")
168168
}
169169

170+
#[test]
171+
fn test_invalid_custom_signal() {
172+
let input: ItemStruct = parse_quote! {
173+
#[qproperty(T, reused_prop, READ, WRITE, NOTIFY = unknown_signal)]
174+
struct MyStruct;
175+
};
176+
let property = ParsedQProperty::parse(&input.attrs[0], CaseConversion::none()).unwrap();
177+
178+
let obj = ParsedQObject::mock();
179+
180+
let structured_qobject = StructuredQObject::mock(&obj);
181+
let qproperty_names = QPropertyNames::try_from_property(&property, &structured_qobject);
182+
assert!(qproperty_names.is_err());
183+
}
184+
170185
#[test]
171186
fn test_parsed_property() {
172187
let names = create_i32_qpropertyname();

crates/cxx-qt-gen/src/generator/structuring/qobject.rs

+18
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub struct StructuredQObject<'a> {
2222
pub inherited_methods: Vec<&'a ParsedInheritedMethod>,
2323
pub signals: Vec<&'a ParsedSignal>,
2424
pub constructors: Vec<&'a Constructor>,
25+
pub pending_methods: Vec<Name>,
26+
pub pending_signals: Vec<Name>,
2527
pub threading: bool,
2628
}
2729

@@ -40,13 +42,27 @@ impl<'a> StructuredQObject<'a> {
4042

4143
/// Creates a [StructuredQObject] from a [ParsedQObject] with empty enum, method and signal collections
4244
pub fn from_qobject(qobject: &'a ParsedQObject) -> Self {
45+
let pending_methods = qobject
46+
.properties
47+
.iter()
48+
.flat_map(|property| property.pending_methods())
49+
.collect();
50+
51+
let pending_signals = qobject
52+
.properties
53+
.iter()
54+
.flat_map(|property| property.pending_signals())
55+
.collect();
56+
4357
Self {
4458
declaration: qobject,
4559
qenums: vec![],
4660
methods: vec![],
4761
inherited_methods: vec![],
4862
signals: vec![],
4963
constructors: vec![],
64+
pending_methods,
65+
pending_signals,
5066
threading: false,
5167
}
5268
}
@@ -55,12 +71,14 @@ impl<'a> StructuredQObject<'a> {
5571
pub fn method_lookup(&self, id: &Ident) -> Result<Name> {
5672
lookup(&self.methods, id, |method| &method.name)
5773
.or_else(|| lookup(&self.inherited_methods, id, |inherited| &inherited.name)) // fallback to searching inherited methods
74+
.or_else(|| lookup(&self.pending_methods, id, |pending| pending))
5875
.ok_or_else(|| not_found_error("Method", id))
5976
}
6077

6178
/// Returns the name of the signal with the provided Rust ident if it exists, or an error
6279
pub fn signal_lookup(&self, id: &Ident) -> Result<Name> {
6380
lookup(&self.signals, id, |signal| &signal.name)
81+
.or_else(|| lookup(&self.pending_signals, id, |pending| pending))
6482
.ok_or_else(|| not_found_error("Signal", id))
6583
}
6684

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

+29
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ use syn::{
1313
Attribute, Expr, Ident, Meta, MetaNameValue, Result, Token, Type,
1414
};
1515

16+
use crate::generator::naming::property::{
17+
getter_name_from_property, notify_name_from_property, setter_name_from_property,
18+
};
1619
#[cfg(test)]
1720
use syn::ItemStruct;
1821

@@ -224,6 +227,32 @@ impl ParsedQProperty {
224227
}
225228
})
226229
}
230+
231+
/// Generates a list of method names which will be generated for this property
232+
pub fn pending_methods(&self) -> Vec<Name> {
233+
let mut pending = vec![];
234+
235+
if let FlagState::Auto = &self.flags.read {
236+
pending.push(getter_name_from_property(&self.name));
237+
}
238+
239+
if let Some(FlagState::Auto) = &self.flags.write {
240+
pending.push(setter_name_from_property(&self.name));
241+
}
242+
243+
pending
244+
}
245+
246+
/// Generates a list of signal names which will be generated for this property
247+
pub fn pending_signals(&self) -> Vec<Name> {
248+
let mut pending = vec![];
249+
250+
if let Some(FlagState::Auto) = &self.flags.notify {
251+
pending.push(notify_name_from_property(&self.name));
252+
}
253+
254+
pending
255+
}
227256
}
228257
#[cfg(test)]
229258
pub fn mock_property(input: ItemStruct) -> ParsedQProperty {

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

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod ffi {
2020
cxx_name = "renamedProperty",
2121
rust_name = "renamed_property"
2222
)]
23+
#[qproperty(i32, reused_signal_prop, READ, WRITE, NOTIFY = trivial_changed)]
2324
#[qproperty(i32, named_prop_2, rust_name = "renamed_property_2")]
2425
#[qproperty(i32, custom_on_changed_prop, cxx_name = "customOnChangedProp", READ, WRITE, NOTIFY = my_on_changed)]
2526
#[qproperty(i32, const_prop, cxx_name = "constProp", READ, CONSTANT)]

crates/cxx-qt-gen/test_outputs/properties.h

+4
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ class MyObject
132132
Q_PROPERTY(::std::int32_t readonlyProp READ getReadonlyProp)
133133
Q_PROPERTY(::std::int32_t renamedProperty READ getRenamedProperty WRITE
134134
setRenamedProperty NOTIFY renamedPropertyChanged)
135+
Q_PROPERTY(::std::int32_t reusedSignalProp READ getReusedSignalProp WRITE
136+
setReusedSignalProp NOTIFY trivialChanged)
135137
Q_PROPERTY(::std::int32_t named_prop_2 READ getNamed_prop_2 WRITE
136138
setNamed_prop_2 NOTIFY named_prop_2Changed)
137139
Q_PROPERTY(::std::int32_t customOnChangedProp READ getCustomOnChangedProp
@@ -156,6 +158,8 @@ class MyObject
156158
::std::int32_t const& getReadonlyProp() const noexcept;
157159
::std::int32_t const& getRenamedProperty() const noexcept;
158160
Q_SLOT void setRenamedProperty(::std::int32_t value) noexcept;
161+
::std::int32_t const& getReusedSignalProp() const noexcept;
162+
Q_SLOT void setReusedSignalProp(::std::int32_t value) noexcept;
159163
::std::int32_t const& getNamed_prop_2() const noexcept;
160164
Q_SLOT void setNamed_prop_2(::std::int32_t value) noexcept;
161165
::std::int32_t const& getCustomOnChangedProp() const noexcept;

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

+29
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ mod ffi {
8282
#[namespace = "cxx_qt::my_object"]
8383
fn set_renamed_property(self: Pin<&mut MyObject>, value: i32);
8484
}
85+
extern "Rust" {
86+
#[cxx_name = "getReusedSignalProp"]
87+
#[namespace = "cxx_qt::my_object"]
88+
unsafe fn reused_signal_prop<'a>(self: &'a MyObject) -> &'a i32;
89+
}
90+
extern "Rust" {
91+
#[cxx_name = "setReusedSignalProp"]
92+
#[namespace = "cxx_qt::my_object"]
93+
fn set_reused_signal_prop(self: Pin<&mut MyObject>, value: i32);
94+
}
8595
extern "Rust" {
8696
#[cxx_name = "getNamed_prop_2"]
8797
#[namespace = "cxx_qt::my_object"]
@@ -505,6 +515,25 @@ impl ffi::MyObject {
505515
self.as_mut().renamed_property_changed();
506516
}
507517
}
518+
impl ffi::MyObject {
519+
#[doc = "Getter for the Q_PROPERTY "]
520+
#[doc = "reused_signal_prop"]
521+
pub fn reused_signal_prop(&self) -> &i32 {
522+
&self.reused_signal_prop
523+
}
524+
}
525+
impl ffi::MyObject {
526+
#[doc = "Setter for the Q_PROPERTY "]
527+
#[doc = "reused_signal_prop"]
528+
pub fn set_reused_signal_prop(mut self: core::pin::Pin<&mut Self>, value: i32) {
529+
use cxx_qt::CxxQtType;
530+
if self.reused_signal_prop == value {
531+
return;
532+
}
533+
self.as_mut().rust_mut().reused_signal_prop = value;
534+
self.as_mut().trivial_changed();
535+
}
536+
}
508537
impl ffi::MyObject {
509538
#[doc = "Getter for the Q_PROPERTY "]
510539
#[doc = "renamed_property_2"]

0 commit comments

Comments
 (0)