diff --git a/CHANGELOG.md b/CHANGELOG.md index 95f3d289c..43c7def1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `impl cxx_qt::Threading for qobject::T` now needs to be specified for `qt_thread()` to be available - `#[cxx_qt::qsignals]` and `#[cxx_qt::inherit]` are now used in an `extern "RustQt"` block as `#[qsignal]` and `#[inherit]` - `#[qinvokable]` is now defined as a signature in `extern "RustQt"` +- `#[qproperty]` is now defined as an attribute on the qobject rather than the field ### Removed diff --git a/book/src/getting-started/1-qobjects-in-rust.md b/book/src/getting-started/1-qobjects-in-rust.md index 41554a27a..3fddf4d99 100644 --- a/book/src/getting-started/1-qobjects-in-rust.md +++ b/book/src/getting-started/1-qobjects-in-rust.md @@ -71,7 +71,7 @@ Typically this will be instantiated by QML and the lifetime will be directly ass The generated QObject subclass will then defer to the Rust struct for any behavior, which is then defined in Rust. For example, using the `#[qinvokable]` attribute, we can define functions that will be exposed to C++, but will execute Rust code. -Also, any fields in the Rust struct marked with `#[qproperty]` will be exposed to Qt as `Q_PROPERTY` fields. +Also, any fields in the Rust struct can be exposed to Qt as `Q_PROPERTY` fields by using the `#[qproperty(T, NAME)]` attribute on the struct. Therefore allowing you to assign them from QML as well. But enough theory for now, lets jump in and write [our first CXX-Qt module](./2-our-first-cxx-qt-module.md). diff --git a/book/src/getting-started/2-our-first-cxx-qt-module.md b/book/src/getting-started/2-our-first-cxx-qt-module.md index a36fb3d0f..cd970ab87 100644 --- a/book/src/getting-started/2-our-first-cxx-qt-module.md +++ b/book/src/getting-started/2-our-first-cxx-qt-module.md @@ -69,13 +69,13 @@ Additionally, we need to either `impl Default` or `#[derive(Default)]` for our s ``` The Rust struct can be defined just like a normal Rust struct and can contain any kind of field, even Rust-only types. -If a field is marked as `#[qproperty]` it will be exposed to the C++ side as a `Q_PROPERTY`. +If a field is tagged as `#[qproperty]` it will be exposed to the C++ side as a `Q_PROPERTY`. That means the newly created QObject subclass will have two properties as members: `number` and `string`. For names that contain multiple words, like `my_number`, CXX-Qt will automatically rename the field from snake_case to camelCase to fit with C++/QML naming conventions (e.g. `myNumber`). ### Types -Do note though that any fields marked as `#[qproperty]` must be types that CXX can translate to C++ types. +Do note though that any fields tagged as `#[qproperty]` must be types that CXX can translate to C++ types. In our case that means: - `number: i32` -> `::std::int32_t number` - `string: QString` -> `QString string` diff --git a/book/src/qobject/qobject_struct.md b/book/src/qobject/qobject_struct.md index 6c9ce37e5..43b7353e8 100644 --- a/book/src/qobject/qobject_struct.md +++ b/book/src/qobject/qobject_struct.md @@ -26,7 +26,7 @@ The macro does multiple other things for you though: - Generate a C++ QObject subclass that wraps the `MyObject` Rust struct. - Expose the generated QObject subclass to Rust as [`qobject::MyObject`](./generated-qobject.md) - Generate getters/setters for all fields. -- Generate `Q_PROPERTY`s for all fields that are marked as `#[qproperty]`. +- Generate `Q_PROPERTY`s for all fields that are tagged as `#[qproperty]`. - Generate signals if paired with a [`#[qsignal]` macro](./signals.md). ## Exposing to QML @@ -71,7 +71,7 @@ Fields within the `#[cxx_qt::qobject]` marked struct can be tagged with `#[qprop {{#include ../../../examples/qml_features/rust/src/properties.rs:book_properties_struct}} ``` -Any type that CXX supports may be marked as a `#[qproperty]`. +Any type that CXX supports may be tagged as a `#[qproperty]`. See the [Types page](../concepts/types.md) for a list of supported types. For every `#[qproperty]`, CXX-Qt will generate setters and getters, as well as a "changed" signal. @@ -90,7 +90,7 @@ where `` is the name of the property. These setters and getters assure that the changed signal is emitted every time the property is edited. -Any field that's not marked as `#[qproperty]` won't be accessible from C++, but it will be accessible from Rust. +Any field that's not tagged as `#[qproperty]` won't be accessible from C++, but it will be accessible from Rust. See the [Private fields section](#private-methods-and-fields) ## Default diff --git a/crates/cxx-qt-gen/src/parser/property.rs b/crates/cxx-qt-gen/src/parser/property.rs index 87bdd9f7d..21fc5ae0d 100644 --- a/crates/cxx-qt-gen/src/parser/property.rs +++ b/crates/cxx-qt-gen/src/parser/property.rs @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use syn::{Ident, Type, Visibility}; +use syn::{parse::ParseStream, parse_quote, Attribute, Ident, Result, Token, Type, Visibility}; /// Describes a single field for a struct pub struct ParsedRustField { @@ -24,3 +24,82 @@ pub struct ParsedQProperty { /// The [syn::Visibility] of the property pub vis: Visibility, } + +impl ParsedQProperty { + pub fn parse(attr: Attribute) -> Result { + attr.parse_args_with(|input: ParseStream| -> Result { + let ty = input.parse()?; + let _comma = input.parse::()?; + let ident = input.parse()?; + + // TODO: later we'll need to parse setters and getters here + // which are key-value, hence this not being parsed as a list + + Ok(Self { + ident, + ty, + // For now always assume pub visibility + vis: parse_quote! { pub }, + }) + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use quote::format_ident; + use syn::ItemStruct; + + #[test] + fn test_parse_property() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(T, name)] + struct MyStruct; + }; + let property = ParsedQProperty::parse(input.attrs.remove(0)).unwrap(); + assert_eq!(property.ident, format_ident!("name")); + assert_eq!(property.ty, parse_quote! { T }); + } + + #[test] + fn test_parse_property_arg_extra() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(T, name, A = B)] + struct MyStruct; + }; + let property = ParsedQProperty::parse(input.attrs.remove(0)); + assert!(property.is_err()); + } + + #[test] + fn test_parse_property_arg_wrong() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(A = B, name)] + struct MyStruct; + }; + let property = ParsedQProperty::parse(input.attrs.remove(0)); + assert!(property.is_err()); + } + + #[test] + fn test_parse_property_no_name() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(T)] + struct MyStruct; + }; + let property = ParsedQProperty::parse(input.attrs.remove(0)); + assert!(property.is_err()); + } + + #[test] + fn test_parse_property_no_type() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(T)] + struct MyStruct; + }; + let property = ParsedQProperty::parse(input.attrs.remove(0)); + assert!(property.is_err()); + } +} diff --git a/crates/cxx-qt-gen/src/parser/qobject.rs b/crates/cxx-qt-gen/src/parser/qobject.rs index 10604dd91..83e471274 100644 --- a/crates/cxx-qt-gen/src/parser/qobject.rs +++ b/crates/cxx-qt-gen/src/parser/qobject.rs @@ -3,10 +3,7 @@ // // 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::syntax::attribute::{attribute_find_path, attribute_tokens_to_map, AttributeDefault}; use crate::{ parser::{ inherit::ParsedInheritedMethod, @@ -17,8 +14,8 @@ use crate::{ syntax::path::path_compare_str, }; use syn::{ - spanned::Spanned, Error, Fields, Ident, ImplItem, Item, ItemImpl, ItemStruct, LitStr, Result, - Visibility, + spanned::Spanned, Attribute, Error, Ident, ImplItem, Item, ItemImpl, ItemStruct, LitStr, + Result, Visibility, }; /// Metadata for registering QML element @@ -99,7 +96,7 @@ impl ParsedQObject { // Parse any properties in the struct // and remove the #[qproperty] attribute - let (properties, _) = Self::parse_struct_fields(&mut qobject_struct.fields)?; + let properties = Self::parse_struct_attributes(&mut qobject_struct.attrs)?; // Ensure that the QObject is marked as pub otherwise the error is non obvious // https://github.com/KDAB/cxx-qt/issues/457 @@ -264,33 +261,14 @@ impl ParsedQObject { } } - /// Extract all the properties from [syn::Fields] from a [syn::ItemStruct] - fn parse_struct_fields( - fields: &mut Fields, - ) -> Result<(Vec, Vec)> { + fn parse_struct_attributes(attrs: &mut Vec) -> Result> { let mut properties = vec![]; - let mut rust_fields = vec![]; - for field in fields_to_named_fields_mut(fields)? { - // Try to find any properties defined within the struct - if let Some(index) = attribute_find_path(&field.attrs, &["qproperty"]) { - // Remove the #[qproperty] attribute - field.attrs.remove(index); - - properties.push(ParsedQProperty { - ident: field.ident.clone().unwrap(), - ty: field.ty.clone(), - vis: field.vis.clone(), - }); - } else { - rust_fields.push(ParsedRustField { - ident: field.ident.clone().unwrap(), - ty: field.ty.clone(), - vis: field.vis.clone(), - }) - } + + while let Some(index) = attribute_find_path(attrs, &["qproperty"]) { + properties.push(ParsedQProperty::parse(attrs.remove(index))?); } - Ok((properties, rust_fields)) + Ok(properties) } } @@ -336,11 +314,10 @@ pub mod tests { fn test_from_struct_properties_and_fields() { let qobject_struct: ItemStruct = parse_quote! { #[cxx_qt::qobject] + #[qproperty(i32, int_property)] + #[qproperty(i32, public_property)] pub struct MyObject { - #[qproperty] int_property: i32, - - #[qproperty] pub public_property: i32, field: i32, @@ -412,11 +389,10 @@ pub mod tests { fn test_parse_struct_fields_valid() { let item: ItemStruct = parse_quote! { #[cxx_qt::qobject] + #[qproperty(f64, f64_property)] + #[qproperty(f64, public_property)] pub struct T { - #[qproperty] f64_property: f64, - - #[qproperty] pub public_property: f64, field: f64, @@ -427,7 +403,7 @@ pub mod tests { assert_eq!(properties[0].ident, "f64_property"); assert_eq!(properties[0].ty, f64_type()); - assert!(matches!(properties[0].vis, Visibility::Inherited)); + assert!(matches!(properties[0].vis, Visibility::Public(_))); assert_eq!(properties[1].ident, "public_property"); assert_eq!(properties[1].ty, f64_type()); @@ -435,12 +411,12 @@ pub mod tests { } #[test] - fn test_parse_struct_fields_invalid() { + fn test_parse_struct_fields() { let item: ItemStruct = parse_quote! { #[cxx_qt::qobject] pub struct T(f64); }; - assert!(ParsedQObject::from_struct(&item, 0).is_err()); + assert!(ParsedQObject::from_struct(&item, 0).is_ok()); } #[test] diff --git a/crates/cxx-qt-gen/src/syntax/fields.rs b/crates/cxx-qt-gen/src/syntax/fields.rs deleted file mode 100644 index ff3dd3f7c..000000000 --- a/crates/cxx-qt-gen/src/syntax/fields.rs +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company -// SPDX-FileContributor: Andrew Hayzen -// -// SPDX-License-Identifier: MIT OR Apache-2.0 - -use syn::{spanned::Spanned, Error, Field, Fields, FieldsNamed, Result}; - -/// In a group of [syn::Fields] extract any [syn::FieldNamed] fields and allow for mutation -/// -/// If there are [syn::FieldsUnnamed] then an error occurs -pub fn fields_to_named_fields_mut(fields: &mut Fields) -> Result> { - match fields { - Fields::Named(FieldsNamed { named, .. }) => Ok(named.iter_mut().collect()), - Fields::Unnamed(_) => Err(Error::new(fields.span(), "Fields cannot be unnamed")), - // Unit is an empty struct or enum etc - Fields::Unit => Ok(vec![]), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use syn::{parse_quote, ItemStruct, Type, Variant}; - - /// Helper which returns a f64 as a [syn::Type] - fn f64_type() -> Type { - parse_quote! { f64 } - } - - #[test] - fn test_fields_to_named_fields_enum_variant_named() { - let mut v: Variant = parse_quote! { - PointChanged { x: f64, y: f64 } - }; - let result = fields_to_named_fields_mut(&mut v.fields).unwrap(); - assert_eq!(result.len(), 2); - assert_eq!(result[0].ident.as_ref().unwrap(), "x"); - assert_eq!(result[0].ty, f64_type()); - assert_eq!(result[1].ident.as_ref().unwrap(), "y"); - assert_eq!(result[1].ty, f64_type()); - } - - #[test] - fn test_fields_to_named_fields_enum_variant_unamed() { - let mut v: Variant = parse_quote! { - PointChanged(f64, f64) - }; - let result = fields_to_named_fields_mut(&mut v.fields); - assert!(result.is_err()); - } - - #[test] - fn test_fields_to_named_fields_enum_variant_empty() { - let mut v: Variant = parse_quote! { - PointChanged - }; - let result = fields_to_named_fields_mut(&mut v.fields).unwrap(); - assert_eq!(result.len(), 0); - } - - #[test] - fn test_fields_to_named_fields_struct_named() { - let mut s: ItemStruct = parse_quote! { - struct Point { - x: f64, - y: f64 - } - }; - let result = fields_to_named_fields_mut(&mut s.fields).unwrap(); - assert_eq!(result.len(), 2); - assert_eq!(result[0].ident.as_ref().unwrap(), "x"); - assert_eq!(result[0].ty, f64_type()); - assert_eq!(result[1].ident.as_ref().unwrap(), "y"); - assert_eq!(result[1].ty, f64_type()); - } - - #[test] - fn test_fields_to_named_fields_struct_unamed() { - let mut s: ItemStruct = parse_quote! { - struct Point(f64, f64); - }; - let result = fields_to_named_fields_mut(&mut s.fields); - assert!(result.is_err()); - } - - #[test] - fn test_fields_to_named_fields_struct_empty() { - let mut s: ItemStruct = parse_quote! { - struct Point; - }; - let result = fields_to_named_fields_mut(&mut s.fields).unwrap(); - assert_eq!(result.len(), 0); - } - - #[test] - fn test_fields_to_named_fields_mutatable() { - let mut s: ItemStruct = parse_quote! { - struct Point { - #[attribute] - x: f64, - y: f64 - } - }; - let mut result = fields_to_named_fields_mut(&mut s.fields).unwrap(); - assert_eq!(result.len(), 2); - result[0].attrs.clear(); - - let expected: ItemStruct = parse_quote! { - struct Point { - x: f64, - y: f64 - } - }; - assert_eq!(s, expected); - } -} diff --git a/crates/cxx-qt-gen/src/syntax/mod.rs b/crates/cxx-qt-gen/src/syntax/mod.rs index 8f1a5c72f..d90bb538e 100644 --- a/crates/cxx-qt-gen/src/syntax/mod.rs +++ b/crates/cxx-qt-gen/src/syntax/mod.rs @@ -5,7 +5,6 @@ pub mod attribute; pub mod expr; -pub mod fields; pub mod foreignmod; pub mod path; mod qtfile; diff --git a/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs index 4929b9b87..701c19170 100644 --- a/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs @@ -80,8 +80,8 @@ pub mod ffi { } #[cxx_qt::qobject(base = "QStringListModel")] + #[qproperty(i32, property_name)] pub struct MyObject { - #[qproperty] property_name: i32, } @@ -127,8 +127,8 @@ pub mod ffi { } #[cxx_qt::qobject] + #[qproperty(i32, property_name)] pub struct SecondObject { - #[qproperty] property_name: i32, } diff --git a/crates/cxx-qt-gen/test_inputs/properties.rs b/crates/cxx-qt-gen/test_inputs/properties.rs index 6d72503e6..be22f0346 100644 --- a/crates/cxx-qt-gen/test_inputs/properties.rs +++ b/crates/cxx-qt-gen/test_inputs/properties.rs @@ -8,10 +8,10 @@ mod ffi { #[cxx_qt::qobject] #[derive(Default)] + #[qproperty(i32, primitive)] + #[qproperty(QPoint, trivial)] pub struct MyObject { - #[qproperty] primitive: i32, - #[qproperty] trivial: QPoint, opaque: UniquePtr, diff --git a/examples/demo_threading/rust/src/lib.rs b/examples/demo_threading/rust/src/lib.rs index b18432358..b978cf030 100644 --- a/examples/demo_threading/rust/src/lib.rs +++ b/examples/demo_threading/rust/src/lib.rs @@ -24,15 +24,15 @@ mod ffi { } #[cxx_qt::qobject(qml_uri = "com.kdab.energy", qml_version = "1.0")] + #[qproperty(f64, average_use)] + #[qproperty(u32, sensors)] + #[qproperty(f64, total_use)] pub struct EnergyUsage { /// The average power usage of the connected sensors - #[qproperty] average_use: f64, /// The count of connected sensors - #[qproperty] sensors: u32, /// The total power usage of the connected sensors - #[qproperty] total_use: f64, /// The join handles of the running threads diff --git a/examples/qml_extension_plugin/plugin/rust/src/lib.rs b/examples/qml_extension_plugin/plugin/rust/src/lib.rs index 8e5c5cb55..d2a381e3c 100644 --- a/examples/qml_extension_plugin/plugin/rust/src/lib.rs +++ b/examples/qml_extension_plugin/plugin/rust/src/lib.rs @@ -37,10 +37,10 @@ mod ffi { } #[cxx_qt::qobject] + #[qproperty(i32, number)] + #[qproperty(QString, string)] pub struct MyObject { - #[qproperty] pub number: i32, - #[qproperty] pub string: QString, } diff --git a/examples/qml_features/rust/src/containers.rs b/examples/qml_features/rust/src/containers.rs index e202d0b71..06c8a64aa 100644 --- a/examples/qml_features/rust/src/containers.rs +++ b/examples/qml_features/rust/src/containers.rs @@ -37,22 +37,22 @@ pub mod ffi { /// It has Q_PROPERTYs which expose a string with the container's contents to show in QML #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] #[derive(Default)] + #[qproperty(QString, string_hash)] + #[qproperty(QString, string_list)] + #[qproperty(QString, string_map)] + #[qproperty(QString, string_set)] + #[qproperty(QString, string_vector)] + // Expose as a Q_PROPERTY so that QML tests can ensure that QVariantMap works + #[qproperty(QMap_QString_QVariant, map)] pub struct RustContainers { - #[qproperty] string_hash: QString, - #[qproperty] string_list: QString, - #[qproperty] string_map: QString, - #[qproperty] string_set: QString, - #[qproperty] string_vector: QString, pub(crate) hash: QHash_QString_QVariant, pub(crate) list: QList_i32, - // Expose as a Q_PROPERTY so that QML tests can ensure that QVariantMap works - #[qproperty] pub(crate) map: QMap_QString_QVariant, pub(crate) set: QSet_i32, pub(crate) vector: QVector_i32, diff --git a/examples/qml_features/rust/src/multiple_qobjects.rs b/examples/qml_features/rust/src/multiple_qobjects.rs index 574883ae9..b0e3b7a67 100644 --- a/examples/qml_features/rust/src/multiple_qobjects.rs +++ b/examples/qml_features/rust/src/multiple_qobjects.rs @@ -19,10 +19,10 @@ pub mod ffi { /// The first QObject #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(i32, counter)] + #[qproperty(QColor, color)] pub struct FirstObject { - #[qproperty] counter: i32, - #[qproperty] color: QColor, } @@ -56,10 +56,10 @@ pub mod ffi { /// The second QObject #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(i32, counter)] + #[qproperty(QUrl, url)] pub struct SecondObject { - #[qproperty] counter: i32, - #[qproperty] url: QUrl, } diff --git a/examples/qml_features/rust/src/nested_qobjects.rs b/examples/qml_features/rust/src/nested_qobjects.rs index 15bcae873..bd98a0fcb 100644 --- a/examples/qml_features/rust/src/nested_qobjects.rs +++ b/examples/qml_features/rust/src/nested_qobjects.rs @@ -20,8 +20,8 @@ pub mod ffi { /// The inner QObject #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] #[derive(Default)] + #[qproperty(i32, counter)] pub struct InnerObject { - #[qproperty] counter: i32, } @@ -33,8 +33,8 @@ pub mod ffi { /// The outer QObject which has a Q_PROPERTY pointing to the inner QObject #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(*mut CxxInnerObject, inner)] pub struct OuterObject { - #[qproperty] inner: *mut CxxInnerObject, } diff --git a/examples/qml_features/rust/src/properties.rs b/examples/qml_features/rust/src/properties.rs index 17b51f45e..d25767de0 100644 --- a/examples/qml_features/rust/src/properties.rs +++ b/examples/qml_features/rust/src/properties.rs @@ -20,21 +20,21 @@ pub mod ffi { /// A QObject which has Q_PROPERTYs // ANCHOR: book_properties_struct #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(bool, connected)] + #[qproperty(QUrl, connected_url)] + #[qproperty(QUrl, previous_connected_url)] + #[qproperty(QString, status_message)] pub struct RustProperties { /// A connected Q_PROPERTY - #[qproperty] connected: bool, /// A connected_url Q_PROPERTY - #[qproperty] pub(crate) connected_url: QUrl, /// A previous_connected_url Q_PROPERTY - #[qproperty] previous_connected_url: QUrl, /// A status_message Q_PROPERTY - #[qproperty] status_message: QString, } // ANCHOR_END: book_properties_struct diff --git a/examples/qml_features/rust/src/serialisation.rs b/examples/qml_features/rust/src/serialisation.rs index b6b018008..b618edd45 100644 --- a/examples/qml_features/rust/src/serialisation.rs +++ b/examples/qml_features/rust/src/serialisation.rs @@ -39,12 +39,12 @@ pub mod ffi { /// A QObject which can be serialised #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(i32, number)] + #[qproperty(QString, string)] pub struct Serialisation { /// The number Q_PROPERTY - #[qproperty] pub number: i32, /// The string Q_PROPERTY - #[qproperty] pub string: QString, } diff --git a/examples/qml_features/rust/src/signals.rs b/examples/qml_features/rust/src/signals.rs index a78888f7f..1e341f5d9 100644 --- a/examples/qml_features/rust/src/signals.rs +++ b/examples/qml_features/rust/src/signals.rs @@ -38,10 +38,10 @@ pub mod ffi { // ANCHOR: book_signals_struct #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] #[derive(Default)] + #[qproperty(bool, logging_enabled)] pub struct RustSignals { pub(crate) connections: Option<[cxx_qt_lib::QMetaObjectConnection; 3]>, - #[qproperty] logging_enabled: bool, } diff --git a/examples/qml_features/rust/src/singleton.rs b/examples/qml_features/rust/src/singleton.rs index 12fe50d2b..7777b1a72 100644 --- a/examples/qml_features/rust/src/singleton.rs +++ b/examples/qml_features/rust/src/singleton.rs @@ -12,9 +12,9 @@ pub mod ffi { /// A QObject which is a QML_SINGLETON #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0", qml_singleton)] #[derive(Default)] + #[qproperty(i32, persistent_value)] pub struct RustSingleton { /// A Q_PROPERTY with a persistent value - #[qproperty] persistent_value: i32, } diff --git a/examples/qml_features/rust/src/threading.rs b/examples/qml_features/rust/src/threading.rs index fc5d798c9..97f577e0f 100644 --- a/examples/qml_features/rust/src/threading.rs +++ b/examples/qml_features/rust/src/threading.rs @@ -23,12 +23,12 @@ pub mod ffi { /// A QObject which has threading #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(QString, title)] + #[qproperty(QUrl, url)] pub struct ThreadingWebsite { /// The title Q_PROPERTY - #[qproperty] title: QString, /// The url Q_PROPERTY - #[qproperty] url: QUrl, pub(crate) loading: std::sync::atomic::AtomicBool, diff --git a/examples/qml_features/rust/src/types.rs b/examples/qml_features/rust/src/types.rs index b4d0c2e4c..b632d5d98 100644 --- a/examples/qml_features/rust/src/types.rs +++ b/examples/qml_features/rust/src/types.rs @@ -75,14 +75,14 @@ pub mod ffi { /// A QObject which shows custom types #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(bool, boolean)] + #[qproperty(QPointF, point)] + #[qproperty(QUrl, url)] + #[qproperty(i32, custom_value)] pub struct Types { - #[qproperty] boolean: bool, - #[qproperty] point: QPointF, - #[qproperty] url: QUrl, - #[qproperty] custom_value: i32, } diff --git a/examples/qml_features/rust/src/uncreatable.rs b/examples/qml_features/rust/src/uncreatable.rs index 4908e3eee..04990fdd6 100644 --- a/examples/qml_features/rust/src/uncreatable.rs +++ b/examples/qml_features/rust/src/uncreatable.rs @@ -12,9 +12,9 @@ pub mod ffi { /// A QObject which is a QML_UNCREATABLE #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0", qml_uncreatable)] #[derive(Default)] + #[qproperty(i32, value)] pub struct RustUncreatable { /// A value Q_PROPERTY - #[qproperty] value: i32, } } diff --git a/examples/qml_minimal/rust/src/cxxqt_object.rs b/examples/qml_minimal/rust/src/cxxqt_object.rs index 23476ae73..fc4f7487f 100644 --- a/examples/qml_minimal/rust/src/cxxqt_object.rs +++ b/examples/qml_minimal/rust/src/cxxqt_object.rs @@ -24,10 +24,10 @@ pub mod ffi { /// The Rust struct for the QObject // ANCHOR: book_rustobj_struct #[cxx_qt::qobject(qml_uri = "com.kdab.cxx_qt.demo", qml_version = "1.0")] + #[qproperty(i32, number)] + #[qproperty(QString, string)] pub struct MyObject { - #[qproperty] number: i32, - #[qproperty] string: QString, } // ANCHOR_END: book_rustobj_struct diff --git a/tests/basic_cxx_qt/rust/src/data.rs b/tests/basic_cxx_qt/rust/src/data.rs index 455107431..e99a36363 100644 --- a/tests/basic_cxx_qt/rust/src/data.rs +++ b/tests/basic_cxx_qt/rust/src/data.rs @@ -33,10 +33,10 @@ mod ffi { } #[cxx_qt::qobject] + #[qproperty(i32, number)] + #[qproperty(QString, string)] pub struct MyData { - #[qproperty] pub number: i32, - #[qproperty] pub string: QString, } diff --git a/tests/basic_cxx_qt/rust/src/lib.rs b/tests/basic_cxx_qt/rust/src/lib.rs index 8c322f63b..e59fd54f9 100644 --- a/tests/basic_cxx_qt/rust/src/lib.rs +++ b/tests/basic_cxx_qt/rust/src/lib.rs @@ -18,10 +18,10 @@ mod ffi { } #[cxx_qt::qobject] + #[qproperty(i32, number)] + #[qproperty(QString, string)] pub struct MyObject { - #[qproperty] number: i32, - #[qproperty] string: QString, pub(crate) update_call_count: i32, diff --git a/tests/basic_cxx_qt/rust/src/types.rs b/tests/basic_cxx_qt/rust/src/types.rs index 87fc99439..da09b7233 100644 --- a/tests/basic_cxx_qt/rust/src/types.rs +++ b/tests/basic_cxx_qt/rust/src/types.rs @@ -8,24 +8,24 @@ mod ffi { #[cxx_qt::qobject] #[derive(Default)] + #[qproperty(bool, boolean)] + #[qproperty(f32, float_32)] + #[qproperty(f64, float_64)] + #[qproperty(i8, int_8)] + #[qproperty(i16, int_16)] + #[qproperty(i32, int_32)] + #[qproperty(u8, uint_8)] + #[qproperty(u16, uint_16)] + #[qproperty(u32, uint_32)] pub struct MyTypes { - #[qproperty] boolean: bool, - #[qproperty] float_32: f32, - #[qproperty] float_64: f64, - #[qproperty] int_8: i8, - #[qproperty] int_16: i16, - #[qproperty] int_32: i32, - #[qproperty] uint_8: u8, - #[qproperty] uint_16: u16, - #[qproperty] uint_32: u32, } }