diff --git a/crates/cxx-qt-gen/Cargo.toml b/crates/cxx-qt-gen/Cargo.toml index d0b90eedf..4952752bc 100644 --- a/crates/cxx-qt-gen/Cargo.toml +++ b/crates/cxx-qt-gen/Cargo.toml @@ -6,7 +6,11 @@ [package] name = "cxx-qt-gen" version.workspace = true -authors = ["Andrew Hayzen ", "Gerhard de Clercq ", "Leon Matthes "] +authors = [ + "Andrew Hayzen ", + "Gerhard de Clercq ", + "Leon Matthes ", +] edition.workspace = true license.workspace = true description = "Code generation for integrating `cxx-qt` into higher level tools" diff --git a/crates/cxx-qt-gen/src/generator/cpp/property/mod.rs b/crates/cxx-qt-gen/src/generator/cpp/property/mod.rs index 4a47f17ab..ce3743d82 100644 --- a/crates/cxx-qt-gen/src/generator/cpp/property/mod.rs +++ b/crates/cxx-qt-gen/src/generator/cpp/property/mod.rs @@ -73,10 +73,12 @@ mod tests { ParsedQProperty { ident: format_ident!("trivial_property"), ty: parse_quote! { i32 }, + flags: Default::default(), }, ParsedQProperty { ident: format_ident!("opaque_property"), ty: parse_quote! { UniquePtr }, + flags: Default::default(), }, ]; let qobject_idents = create_qobjectname(); @@ -358,6 +360,7 @@ mod tests { let properties = vec![ParsedQProperty { ident: format_ident!("mapped_property"), ty: parse_quote! { A }, + flags: Default::default(), }]; let qobject_idents = create_qobjectname(); diff --git a/crates/cxx-qt-gen/src/generator/naming/property.rs b/crates/cxx-qt-gen/src/generator/naming/property.rs index 96bd38578..5e577cea8 100644 --- a/crates/cxx-qt-gen/src/generator/naming/property.rs +++ b/crates/cxx-qt-gen/src/generator/naming/property.rs @@ -83,6 +83,7 @@ pub mod tests { let property = ParsedQProperty { ident: format_ident!("my_property"), ty, + flags: Default::default(), }; QPropertyNames::from(&property) } diff --git a/crates/cxx-qt-gen/src/generator/rust/property/mod.rs b/crates/cxx-qt-gen/src/generator/rust/property/mod.rs index ac676a7b0..4026bc3aa 100644 --- a/crates/cxx-qt-gen/src/generator/rust/property/mod.rs +++ b/crates/cxx-qt-gen/src/generator/rust/property/mod.rs @@ -77,14 +77,17 @@ mod tests { ParsedQProperty { ident: format_ident!("trivial_property"), ty: parse_quote! { i32 }, + flags: Default::default(), }, ParsedQProperty { ident: format_ident!("opaque_property"), ty: parse_quote! { UniquePtr }, + flags: Default::default(), }, ParsedQProperty { ident: format_ident!("unsafe_property"), ty: parse_quote! { *mut T }, + flags: Default::default(), }, ]; let qobject_idents = create_qobjectname(); diff --git a/crates/cxx-qt-gen/src/parser/property.rs b/crates/cxx-qt-gen/src/parser/property.rs index 93d4daf67..fb0b688d3 100644 --- a/crates/cxx-qt-gen/src/parser/property.rs +++ b/crates/cxx-qt-gen/src/parser/property.rs @@ -3,7 +3,16 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use syn::{parse::ParseStream, Attribute, Ident, Result, Token, Type}; +use std::collections::HashSet; + +use syn::{parse::ParseStream, punctuated::Punctuated, Attribute, Ident, Result, Token, Type}; + +#[derive(Debug, Eq, PartialEq, Hash)] +pub enum QPropertyFlag { + Read, + Write, + Notify, +} /// Describes a single Q_PROPERTY for a struct pub struct ParsedQProperty { @@ -11,6 +20,8 @@ pub struct ParsedQProperty { pub ident: Ident, /// The [syn::Type] of the property pub ty: Type, + /// HashSet of [QPropertyFlag]s which were specified + pub flags: HashSet, } impl ParsedQProperty { @@ -20,10 +31,42 @@ impl ParsedQProperty { let _comma = input.parse::()?; let ident = input.parse()?; + if input.is_empty() { + // No flags so return with empty HashSet + return Ok(Self { + ident, + ty, + flags: Default::default(), + }); + } + + let _comma = input.parse::()?; // Start of final identifiers + + // TODO: Allow parser to store pairs of items e.g read = get_value, Might be useful to use Meta::NameValue + let punctuated_flags: Punctuated = + Punctuated::parse_terminated(input)?; + + let flags: Vec = punctuated_flags.into_iter().collect(); // Removes the commas while collecting into Vec + + let mut flags_set: HashSet = HashSet::new(); + + for identifier in flags { + match identifier.to_string().as_str() { + "read" => flags_set.insert(QPropertyFlag::Read), + "write" => flags_set.insert(QPropertyFlag::Write), + "notify" => flags_set.insert(QPropertyFlag::Notify), + _ => panic!("Invalid Token"), // TODO: might not be a good idea to error here + }; + } + // 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 }) + Ok(Self { + ident, + ty, + flags: flags_set, + }) }) } } @@ -46,6 +89,42 @@ mod tests { assert_eq!(property.ty, parse_quote! { T }); } + #[test] + fn test_parse_read_flag() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(T, name, read)] + 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 }); + assert!(property.flags.contains(&QPropertyFlag::Read)); + } + + #[test] + fn test_parse_all_flags() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(T, name, read, write, notify)] + 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 }); + assert!(property.flags.contains(&QPropertyFlag::Read)); + assert!(property.flags.contains(&QPropertyFlag::Write)); + assert!(property.flags.contains(&QPropertyFlag::Notify)); + } + + #[test] + #[should_panic] + fn test_parse_invalid_flags() { + let mut input: ItemStruct = parse_quote! { + #[qproperty(T, name, read, write, A)] + struct MyStruct; + }; + let property = ParsedQProperty::parse(input.attrs.remove(0)).unwrap(); + } + #[test] fn test_parse_property_arg_extra() { let mut input: ItemStruct = parse_quote! {