Skip to content

Commit

Permalink
Add extend method for simplifying multiple generated blocks into one
Browse files Browse the repository at this point in the history
  • Loading branch information
BenFordTytherington committed Jan 16, 2025
1 parent 352d33f commit d10a509
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 137 deletions.
5 changes: 4 additions & 1 deletion crates/cxx-qt-gen/src/generator/rust/cxxqttype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use syn::{parse_quote, Result};

use super::fragment::GeneratedRustFragment;

pub fn generate(qobject_names: &QObjectNames, type_names: &TypeNames) -> Result<GeneratedRustFragment> {
pub fn generate(
qobject_names: &QObjectNames,
type_names: &TypeNames,
) -> Result<GeneratedRustFragment> {
let cpp_struct_ident = &qobject_names.name.rust_unqualified();
let rust_struct_ident = &qobject_names.rust_struct.rust_unqualified();
let (rust_fn_name, rust_fn_attrs, rust_fn_qualified) = qobject_names
Expand Down
21 changes: 7 additions & 14 deletions crates/cxx-qt-gen/src/generator/rust/externcxxqt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{
generator::rust::{
fragment::GeneratedRustFragment,
signals::generate_rust_signal,
},
generator::rust::{fragment::GeneratedRustFragment, signals::generate_rust_signal},
naming::TypeNames,
parser::externcxxqt::ParsedExternCxxQt,
syntax::path::path_compare_str,
Expand All @@ -19,8 +16,6 @@ impl GeneratedRustFragment {
extern_cxxqt_block: &ParsedExternCxxQt,
type_names: &TypeNames,
) -> Result<Self> {
let mut generated = Self::default();

let extern_block_namespace = if let Some(namespace) = &extern_cxxqt_block.namespace {
quote! { #[namespace = #namespace ] }
} else {
Expand Down Expand Up @@ -66,27 +61,25 @@ impl GeneratedRustFragment {
})
.collect::<Vec<_>>();

generated.append(&mut GeneratedRustFragment {
cxx_mod_contents: vec![
parse_quote! {
let mut generated = vec![GeneratedRustFragment {
cxx_mod_contents: vec![parse_quote! {
#extern_block_namespace
#unsafety extern "C++" {
#(#items)*

#(#types)*
}
}
],
}],
cxx_qt_mod_contents: vec![],
});
}];

// Build the signals
for signal in &extern_cxxqt_block.signals {
let qobject_name = type_names.lookup(&signal.qobject_ident)?;

generated.append(&mut generate_rust_signal(signal, qobject_name, type_names)?);
generated.push(generate_rust_signal(signal, qobject_name, type_names)?);
}

Ok(generated)
Ok(GeneratedRustFragment::flatten(generated))
}
}
16 changes: 12 additions & 4 deletions crates/cxx-qt-gen/src/generator/rust/fragment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ pub struct GeneratedRustFragment {
}

impl GeneratedRustFragment {
pub fn append(&mut self, other: &mut Self) {
self.cxx_mod_contents.append(&mut other.cxx_mod_contents);
self.cxx_qt_mod_contents
.append(&mut other.cxx_qt_mod_contents);
pub fn append(&mut self, other: Self) {
self.cxx_mod_contents.extend(other.cxx_mod_contents);
self.cxx_qt_mod_contents.extend(other.cxx_qt_mod_contents);
}

// Create a singular GeneratedRustFragment from a Vector of multiple
pub fn flatten(others: Vec<Self>) -> Self {
let mut this = Self::default();
for other in others {
this.append(other);
}
this
}
}
63 changes: 30 additions & 33 deletions crates/cxx-qt-gen/src/generator/rust/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,44 @@

use crate::generator::rust::get_params_tokens;
use crate::{
generator::{
naming::qobject::QObjectNames,
rust::fragment::GeneratedRustFragment,
},
generator::{naming::qobject::QObjectNames, rust::fragment::GeneratedRustFragment},
parser::method::ParsedMethod,
};
use quote::quote;
use syn::{parse_quote_spanned, spanned::Spanned, Result};

pub fn generate_rust_methods(
invokables: &Vec<&ParsedMethod>,
invokables: &[&ParsedMethod],
qobject_names: &QObjectNames,
) -> Result<GeneratedRustFragment> {
let mut generated = GeneratedRustFragment::default();
let cpp_class_name_rust = &qobject_names.name.rust_unqualified();

for &invokable in invokables {
// TODO: once we aren't using qobject::T in the extern "RustQt"
// we can just pass through the original ExternFn block and add the attribute?
let invokable_ident_cpp = invokable.name.cxx_unqualified();
let invokable_ident_rust = invokable.name.rust_unqualified();
let generated = invokables
.iter()
.map(|invokable| {
// TODO: once we aren't using qobject::T in the extern "RustQt"
// we can just pass through the original ExternFn block and add the attribute?
let invokable_ident_cpp = invokable.name.cxx_unqualified();
let invokable_ident_rust = invokable.name.rust_unqualified();

let parameter_signatures = get_params_tokens(
invokable.mutable,
&invokable.parameters,
cpp_class_name_rust,
);
let parameter_signatures = get_params_tokens(
invokable.mutable,
&invokable.parameters,
cpp_class_name_rust,
);

let return_type = &invokable.method.sig.output;
let return_type = &invokable.method.sig.output;

let mut unsafe_call = Some(quote! { unsafe });
if invokable.safe {
std::mem::swap(&mut unsafe_call, &mut None);
}
let mut unsafe_call = Some(quote! { unsafe });
if invokable.safe {
std::mem::swap(&mut unsafe_call, &mut None);
}

let cfgs = &invokable.cfgs;
let cxx_namespace = qobject_names.namespace_tokens();
let cfgs = &invokable.cfgs;
let cxx_namespace = qobject_names.namespace_tokens();

generated.append(&mut GeneratedRustFragment {
cxx_mod_contents: vec![
parse_quote_spanned! {
GeneratedRustFragment {
cxx_mod_contents: vec![parse_quote_spanned! {
invokable.method.span() =>
// Note: extern "Rust" block does not need to be unsafe
extern "Rust" {
Expand All @@ -62,13 +59,13 @@ pub fn generate_rust_methods(
#[doc(hidden)]
#unsafe_call fn #invokable_ident_rust(#parameter_signatures) #return_type;
}
}
],
cxx_qt_mod_contents: vec![],
});
}
}],
cxx_qt_mod_contents: vec![],
}
})
.collect::<Vec<_>>();

Ok(generated)
Ok(GeneratedRustFragment::flatten(generated))
}

#[cfg(test)]
Expand Down Expand Up @@ -106,7 +103,7 @@ mod tests {
let qobject_names = create_qobjectname();

let generated =
generate_rust_methods(&invokables.iter().collect(), &qobject_names).unwrap();
generate_rust_methods(&invokables.iter().collect::<Vec<_>>(), &qobject_names).unwrap();

assert_eq!(generated.cxx_mod_contents.len(), 4);
assert_eq!(generated.cxx_qt_mod_contents.len(), 0);
Expand Down
38 changes: 17 additions & 21 deletions crates/cxx-qt-gen/src/generator/rust/property/getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,26 @@ pub fn generate(
let cxx_namespace = qobject_names.namespace_tokens();

Ok(Some(GeneratedRustFragment {
cxx_mod_contents: vec![
parse_quote! {
extern "Rust" {
#[cxx_name = #getter_cpp]
// Needed for QObjects to have a namespace on their type or extern block
//
// A Namespace from cxx_qt::bridge would be automatically applied to all children
// but to apply it to only certain types, it is needed here too
#cxx_namespace
unsafe fn #getter_rust<'a>(self: &'a #cpp_class_name_rust) -> &'a #cxx_ty;
}
cxx_mod_contents: vec![parse_quote! {
extern "Rust" {
#[cxx_name = #getter_cpp]
// Needed for QObjects to have a namespace on their type or extern block
//
// A Namespace from cxx_qt::bridge would be automatically applied to all children
// but to apply it to only certain types, it is needed here too
#cxx_namespace
unsafe fn #getter_rust<'a>(self: &'a #cpp_class_name_rust) -> &'a #cxx_ty;
}
],
cxx_qt_mod_contents: vec![
parse_quote! {
impl #qualified_impl {
#[doc = "Getter for the Q_PROPERTY "]
#[doc = #ident_str]
pub fn #getter_rust(&self) -> &#qualified_ty {
&self.#ident
}
}],
cxx_qt_mod_contents: vec![parse_quote! {
impl #qualified_impl {
#[doc = "Getter for the Q_PROPERTY "]
#[doc = #ident_str]
pub fn #getter_rust(&self) -> &#qualified_ty {
&self.#ident
}
}
],
}],
}))
} else {
Ok(None)
Expand Down
12 changes: 6 additions & 6 deletions crates/cxx-qt-gen/src/generator/rust/property/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ pub fn generate_rust_properties(
for property in properties {
let idents = QPropertyNames::try_from_property(property, structured_qobject)?;

if let Some(mut getter) = getter::generate(&idents, qobject_names, &property.ty, type_names)? {
generated.append(&mut getter);
if let Some(getter) = getter::generate(&idents, qobject_names, &property.ty, type_names)? {
generated.append(getter);
};

if let Some(mut setter) = setter::generate(&idents, qobject_names, &property.ty, type_names)? {
generated.append(&mut setter);
if let Some(setter) = setter::generate(&idents, qobject_names, &property.ty, type_names)? {
generated.append(setter);
}

if let Some(notify) = signal::generate(&idents, qobject_names) {
signals.push(notify)
}
}

generated.append(&mut generate_rust_signals(
&signals.iter().collect(),
generated.append(generate_rust_signals(
&signals.iter().collect::<Vec<_>>(),
qobject_names,
type_names,
)?);
Expand Down
74 changes: 28 additions & 46 deletions crates/cxx-qt-gen/src/generator/rust/qobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@ use crate::{
generator::{
naming::{namespace::NamespaceName, qobject::QObjectNames},
rust::{
constructor, cxxqttype,
fragment::GeneratedRustFragment,
inherit,
method::generate_rust_methods,
property::generate_rust_properties,
signals::generate_rust_signals,
threading,
constructor, cxxqttype, fragment::GeneratedRustFragment, inherit,
method::generate_rust_methods, property::generate_rust_properties,
signals::generate_rust_signals, threading,
},
},
naming::TypeNames,
Expand All @@ -31,39 +27,24 @@ impl GeneratedRustFragment {
// Create the base object
let qobject_names = QObjectNames::from_qobject(qobject, type_names)?;
let namespace_idents = NamespaceName::from(qobject);
let mut generated = Self::default();

generated.append(&mut generate_qobject_definitions(
&qobject_names,
qobject.base_class.clone(),
type_names,
)?);

// Generate methods for the properties, invokables, signals
generated.append(&mut generate_rust_properties(
&qobject.properties,
&qobject_names,
type_names,
structured_qobject,
)?);
generated.append(&mut generate_rust_methods(
&structured_qobject.methods,
&qobject_names,
)?);
generated.append(&mut inherit::generate(
&qobject_names,
&structured_qobject.inherited_methods,
)?);
generated.append(&mut generate_rust_signals(
&structured_qobject.signals,
&qobject_names,
type_names,
)?);
let mut generated = vec![
generate_qobject_definitions(&qobject_names, qobject.base_class.clone(), type_names)?,
generate_rust_properties(
&qobject.properties,
&qobject_names,
type_names,
structured_qobject,
)?,
generate_rust_methods(&structured_qobject.methods, &qobject_names)?,
inherit::generate(&qobject_names, &structured_qobject.inherited_methods)?,
generate_rust_signals(&structured_qobject.signals, &qobject_names, type_names)?,
];

// If this type is a singleton then we need to add an include
if let Some(qml_metadata) = &qobject.qml_metadata {
if qml_metadata.singleton {
generated.append(&mut GeneratedRustFragment {
generated.push(GeneratedRustFragment {
cxx_mod_contents: vec![parse_quote! {
unsafe extern "C++" {
include!(<QtQml/QQmlEngine>);
Expand All @@ -76,23 +57,24 @@ impl GeneratedRustFragment {

// If this type has threading enabled then add generation
if structured_qobject.threading {
generated.append(&mut threading::generate(
generated.push(threading::generate(
&qobject_names,
&namespace_idents,
type_names,
)?);
}

generated.append(&mut constructor::generate(
&structured_qobject.constructors,
&qobject_names,
&namespace_idents,
type_names,
)?);

generated.append(&mut cxxqttype::generate(&qobject_names, type_names)?);
generated.extend(vec![
constructor::generate(
&structured_qobject.constructors,
&qobject_names,
&namespace_idents,
type_names,
)?,
cxxqttype::generate(&qobject_names, type_names)?,
]);

Ok(generated)
Ok(GeneratedRustFragment::flatten(generated))
}
}

Expand Down Expand Up @@ -164,7 +146,7 @@ fn generate_qobject_definitions(
}
},
],
cxx_qt_mod_contents: base_upcast
cxx_qt_mod_contents: base_upcast,
})
}

Expand Down
Loading

0 comments on commit d10a509

Please sign in to comment.