Skip to content

Commit 4b23a7b

Browse files
Feature naming on properties (KDAB#1072)
* Switch ParsedQProperty to use Name instead of Ident, and allow cxx_name and rust_name in flags - Add closure to group behaviour of flags requiring a value passed * Add parsing checks for name flags - using cxx_name or rust_name is allowed without READ flag - Maintains error for using property flags e.g. WRITE without including READ - cxx_name and rust_name must have strings as values, whereas other flags still need idents * Add naming to a property in test_inputs - Also refactor value assignment in parse_meta_name_value - Refactor cxx_name so that having no cxx_name requires no rust_name to do camelcase conversion * Add new Name method to combine common logic - Applies options with the correct renaming logic, and this is used in property renaming - Also switch from format_ident to a propagating syn::parse_string instead * Update changelog and book * Add to example and refactor auto_camel in name function
1 parent 4da68f5 commit 4b23a7b

File tree

19 files changed

+614
-195
lines changed

19 files changed

+614
-195
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3030
- Add support for the constant, required, reset and final flags in the qproperty macro
3131
- QObject subclasses can now inherit from other CXX-Qt generated QObject classes
3232
- `BUILD_WASM` CMake option to support WebAssembly builds and a book page for building for WASM
33+
- Add support for cxx_name and rust_name on qproperty attributes which applies to the QProperty generated as well as functions
3334

3435
### Changed
3536

book/src/bridge/extern_rustqt.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ Using the read flag will cause CXX-Qt to generate a getter function with an auto
141141

142142
If a custom function is specified, an implementation both in qobject::MyObject and and export in the bridge is expected.
143143

144+
Additionally, usng cxx_name and rust_name is possible similarly to the attributes avilable on other items. e.g. `#[qproperty(i32, num, cxx_name = "numberProp")]`
145+
144146
### Examples
145147

146148
- `#[qproperty(TYPE, NAME, READ)]` A read only property
@@ -165,6 +167,10 @@ If a custom function is specified, an implementation both in qobject::MyObject a
165167
- Specifies that the property will not be overriden by a derived class
166168
- `RESET = my_reset`
167169
- Specifies a function to reset the property to a default value, user function __must__ be provided or it will not compile
170+
- `cxx_name = "myCxxName`
171+
- Specifies an alternative name to use on the C++ side, applying to the property name as well as autogenerated functions
172+
- `rust_name = "my_rust_name"`
173+
- Specifies an alternative name to use on the rust side, applying to the property name as well as autogenerated functions
168174

169175
## Methods
170176

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub fn generate_cpp_properties(
6262
pub mod tests {
6363
use super::*;
6464

65+
use crate::generator::naming::property::property_name_from_rust_name;
6566
use crate::generator::naming::qobject::tests::create_qobjectname;
6667
use crate::generator::structuring::Structures;
6768
use crate::parser::property::QPropertyFlags;
@@ -471,7 +472,7 @@ pub mod tests {
471472
#[test]
472473
fn test_generate_cpp_properties_mapped_cxx_name() {
473474
let properties = vec![ParsedQProperty {
474-
ident: format_ident!("mapped_property"),
475+
name: property_name_from_rust_name(format_ident!("mapped_property")),
475476
ty: parse_quote! { A },
476477
flags: QPropertyFlags::default(),
477478
}];

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

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ impl QPropertyNames {
6363
property: &ParsedQProperty,
6464
structured_qobject: &StructuredQObject,
6565
) -> Result<Self> {
66-
let property_name = property_name_from_rust_name(property.ident.clone());
66+
let property_name = &property.name;
6767

6868
// Cache flags as they are accessed multiple times
6969
let flags = &property.flags;
7070

7171
let getter = NameState::from_flag_with_auto_fn(
7272
&flags.read,
73-
|| getter_name_from_property(&property_name),
73+
|| getter_name_from_property(property_name),
7474
structured_qobject,
7575
false,
7676
)?;
@@ -81,7 +81,7 @@ impl QPropertyNames {
8181
.map(|setter| {
8282
NameState::from_flag_with_auto_fn(
8383
&setter,
84-
|| setter_name_from_property(&property_name),
84+
|| setter_name_from_property(property_name),
8585
structured_qobject,
8686
false,
8787
)
@@ -94,7 +94,7 @@ impl QPropertyNames {
9494
.map(|notify| {
9595
NameState::from_flag_with_auto_fn(
9696
&notify,
97-
|| notify_name_from_property(&property_name),
97+
|| notify_name_from_property(property_name),
9898
structured_qobject,
9999
true,
100100
)
@@ -112,14 +112,15 @@ impl QPropertyNames {
112112
setter,
113113
notify,
114114
reset,
115-
name: property_name,
115+
name: property_name.clone(),
116116
})
117117
}
118118
}
119119

120-
fn property_name_from_rust_name(ident: Ident) -> Name {
120+
pub fn property_name_from_rust_name(ident: Ident) -> Name {
121121
// TODO: ParsedQProperty should probably take care of this already and allow the user to set
122122
// their own name for C++ if they want to.
123+
// REMOVE THIS FN
123124
let cxx_name = ident.to_string().to_case(Case::Camel);
124125
Name::new(ident).with_cxx_name(cxx_name)
125126
}
@@ -159,7 +160,7 @@ pub mod tests {
159160

160161
pub fn create_i32_qpropertyname() -> QPropertyNames {
161162
let property = ParsedQProperty {
162-
ident: format_ident!("my_property"),
163+
name: property_name_from_rust_name(format_ident!("my_property")),
163164
ty: parse_quote! { i32 },
164165
flags: QPropertyFlags::default(),
165166
};
@@ -175,27 +176,24 @@ pub mod tests {
175176
fn test_parsed_property() {
176177
let names = create_i32_qpropertyname();
177178
assert_eq!(names.name.cxx_unqualified(), "myProperty");
178-
assert_eq!(names.name.rust_unqualified(), &format_ident!("my_property"));
179+
assert_eq!(names.name.rust_unqualified(), "my_property");
179180
assert_eq!(names.getter.cxx_unqualified(), "getMyProperty");
180-
assert_eq!(
181-
names.getter.rust_unqualified(),
182-
&format_ident!("my_property")
183-
);
181+
assert_eq!(names.getter.rust_unqualified(), "my_property");
184182
assert_eq!(
185183
names.setter.as_ref().unwrap().cxx_unqualified(),
186184
"setMyProperty"
187185
);
188186
assert_eq!(
189187
names.setter.as_ref().unwrap().rust_unqualified(),
190-
&format_ident!("set_my_property")
188+
"set_my_property"
191189
);
192190
assert_eq!(
193191
names.notify.as_ref().unwrap().cxx_unqualified(),
194192
"myPropertyChanged"
195193
);
196194
assert_eq!(
197195
names.notify.as_ref().unwrap().rust_unqualified(),
198-
&format_ident!("my_property_changed")
196+
"my_property_changed"
199197
);
200198
}
201199
}

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

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,13 @@ pub mod tests {
109109
let names =
110110
QObjectNames::from_qobject(&create_parsed_qobject(), &TypeNames::mock()).unwrap();
111111
assert_eq!(names.name.cxx_unqualified(), "MyObject");
112-
assert_eq!(names.name.rust_unqualified(), &format_ident!("MyObject"));
112+
assert_eq!(names.name.rust_unqualified(), "MyObject");
113113
assert_eq!(names.rust_struct.cxx_unqualified(), "MyObjectRust");
114-
assert_eq!(
115-
names.rust_struct.rust_unqualified(),
116-
&format_ident!("MyObjectRust")
117-
);
118-
assert_eq!(
119-
names.cxx_qt_thread_class,
120-
format_ident!("MyObjectCxxQtThread")
121-
);
114+
assert_eq!(names.rust_struct.rust_unqualified(), "MyObjectRust");
115+
assert_eq!(names.cxx_qt_thread_class, "MyObjectCxxQtThread");
122116
assert_eq!(
123117
names.cxx_qt_thread_queued_fn_struct,
124-
format_ident!("MyObjectCxxQtThreadQueuedFn")
118+
"MyObjectCxxQtThreadQueuedFn"
125119
);
126120

127121
assert_eq!(

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -794,16 +794,15 @@ mod tests {
794794

795795
#[test]
796796
fn constructor_impl_with_unused_lifetime() {
797-
let result = super::generate(
797+
assert!(generate(
798798
&[&Constructor {
799799
lifetime: Some(parse_quote! { 'a }),
800800
..mock_constructor()
801801
}],
802802
&mock_name(),
803803
&mock_namespace(),
804804
&TypeNames::mock(),
805-
);
806-
807-
assert!(result.is_err());
805+
)
806+
.is_err());
808807
}
809808
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ pub fn generate_rust_properties(
6767
mod tests {
6868
use super::*;
6969

70+
use crate::generator::naming::property::property_name_from_rust_name;
7071
use crate::parser::property::QPropertyFlags;
7172
use crate::parser::qobject::ParsedQObject;
7273
use crate::{generator::naming::qobject::tests::create_qobjectname, tests::assert_tokens_eq};
@@ -77,17 +78,17 @@ mod tests {
7778
fn test_generate_rust_properties() {
7879
let properties = vec![
7980
ParsedQProperty {
80-
ident: format_ident!("trivial_property"),
81+
name: property_name_from_rust_name(format_ident!("trivial_property")),
8182
ty: parse_quote! { i32 },
8283
flags: QPropertyFlags::default(),
8384
},
8485
ParsedQProperty {
85-
ident: format_ident!("opaque_property"),
86+
name: property_name_from_rust_name(format_ident!("opaque_property")),
8687
ty: parse_quote! { UniquePtr<QColor> },
8788
flags: QPropertyFlags::default(),
8889
},
8990
ParsedQProperty {
90-
ident: format_ident!("unsafe_property"),
91+
name: property_name_from_rust_name(format_ident!("unsafe_property")),
9192
ty: parse_quote! { *mut T },
9293
flags: QPropertyFlags::default(),
9394
},

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

Lines changed: 4 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -123,92 +123,6 @@ mod tests {
123123
use quote::format_ident;
124124
use syn::{parse_quote, ItemMod};
125125

126-
#[test]
127-
fn test_structuring_unknown_qobject() {
128-
let module = parse_quote! {
129-
#[cxx_qt::bridge]
130-
mod ffi {
131-
extern "RustQt" {
132-
#[qobject]
133-
type MyObject = super::MyObjectRust;
134-
}
135-
136-
unsafe extern "RustQt" {
137-
#[qsignal]
138-
fn ready(self: Pin<&mut UnknownObject>);
139-
}
140-
}
141-
};
142-
let parser = Parser::from(module).unwrap();
143-
let structures = Structures::new(&parser.cxx_qt_data);
144-
145-
assert!(structures.is_err());
146-
}
147-
148-
#[test]
149-
fn test_module_invalid_qobject_qenum() {
150-
let module = parse_quote! {
151-
#[cxx_qt::bridge]
152-
mod ffi {
153-
#[qenum(MyObject)]
154-
enum MyEnum {
155-
A,
156-
}
157-
}
158-
};
159-
160-
let parser = Parser::from(module).unwrap();
161-
assert!(Structures::new(&parser.cxx_qt_data).is_err());
162-
}
163-
164-
#[test]
165-
fn test_module_invalid_qobject_method() {
166-
let module = parse_quote! {
167-
#[cxx_qt::bridge]
168-
mod ffi {
169-
unsafe extern "RustQt" {
170-
#[qinvokable]
171-
fn test_fn(self: Pin<&mut MyObject>);
172-
}
173-
}
174-
};
175-
176-
let parser = Parser::from(module).unwrap();
177-
assert!(Structures::new(&parser.cxx_qt_data).is_err());
178-
}
179-
180-
#[test]
181-
fn test_module_invalid_qobject_signal() {
182-
let module = parse_quote! {
183-
#[cxx_qt::bridge]
184-
mod ffi {
185-
unsafe extern "RustQt" {
186-
#[qsignal]
187-
fn test_fn(self: Pin<&mut MyObject>);
188-
}
189-
}
190-
};
191-
192-
let parser = Parser::from(module).unwrap();
193-
assert!(Structures::new(&parser.cxx_qt_data).is_err());
194-
}
195-
196-
#[test]
197-
fn test_module_invalid_qobject_inherited() {
198-
let module = parse_quote! {
199-
#[cxx_qt::bridge]
200-
mod ffi {
201-
unsafe extern "RustQt" {
202-
#[inherit]
203-
fn test_fn(self: Pin<&mut MyObject>);
204-
}
205-
}
206-
};
207-
208-
let parser = Parser::from(module).unwrap();
209-
assert!(Structures::new(&parser.cxx_qt_data).is_err());
210-
}
211-
212126
#[test]
213127
fn test_invalid_lookup() {
214128
let module = parse_quote! {
@@ -338,20 +252,15 @@ mod tests {
338252
}
339253
}
340254

341-
fn assert_structuring_error(additional_items: impl IntoIterator<Item = syn::Item>) {
342-
let mut bridge = mock_bridge();
343-
bridge.content.as_mut().unwrap().1.extend(additional_items);
344-
let parser = Parser::from(bridge).unwrap();
345-
assert!(Structures::new(&parser.cxx_qt_data).is_err());
346-
}
347-
348255
#[test]
349256
fn test_incompatible_trait_impl() {
350-
// TODO: Possible to use assert_parse_errors?
351-
assert_structuring_error([
257+
let mut bridge = mock_bridge();
258+
bridge.content.as_mut().unwrap().1.extend([
352259
parse_quote! {impl cxx_qt::Threading for MyObject {}},
353260
parse_quote! {impl cxx_qt::Threading for MyObject {}},
354261
]);
262+
let parser = Parser::from(bridge).unwrap();
263+
assert!(Structures::new(&parser.cxx_qt_data).is_err());
355264
}
356265

357266
#[test]

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ mod name;
1616
pub(crate) mod rust;
1717
mod type_names;
1818

19-
pub use name::Name;
19+
pub use name::{AutoCamel, Name};
2020
pub use type_names::TypeNames;

0 commit comments

Comments
 (0)