From c3a02729a25e13afeaa2bc1d71ae2296c21ec0b2 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Fri, 25 Aug 2023 17:51:44 +0100 Subject: [PATCH] cxx-qt-gen: add support for closures in signals Also reuse same code path for RustQt and C++Qt signals. Closes #595 --- .../src/generator/cpp/externcxxqt.rs | 26 +- .../src/generator/cpp/property/mod.rs | 170 +++- .../cxx-qt-gen/src/generator/cpp/qobject.rs | 24 +- crates/cxx-qt-gen/src/generator/cpp/signal.rs | 546 +++++++---- .../src/generator/naming/namespace.rs | 10 - .../src/generator/naming/signals.rs | 49 +- .../src/generator/rust/externcxxqt.rs | 7 +- .../src/generator/rust/property/mod.rs | 329 ++++++- .../src/generator/rust/property/signal.rs | 2 + .../cxx-qt-gen/src/generator/rust/qobject.rs | 2 + .../cxx-qt-gen/src/generator/rust/signals.rs | 845 ++++++++++++++---- crates/cxx-qt-gen/src/writer/cpp/header.rs | 32 +- crates/cxx-qt-gen/src/writer/cpp/mod.rs | 23 +- crates/cxx-qt-gen/src/writer/cpp/source.rs | 33 +- crates/cxx-qt-gen/test_inputs/signals.rs | 12 +- .../test_outputs/passthrough_and_naming.cpp | 424 +++++++-- .../test_outputs/passthrough_and_naming.h | 110 ++- .../test_outputs/passthrough_and_naming.rs | 557 ++++++++++-- crates/cxx-qt-gen/test_outputs/properties.cpp | 144 ++- crates/cxx-qt-gen/test_outputs/properties.h | 36 +- crates/cxx-qt-gen/test_outputs/properties.rs | 158 +++- crates/cxx-qt-gen/test_outputs/signals.cpp | 307 +++++-- crates/cxx-qt-gen/test_outputs/signals.h | 70 +- crates/cxx-qt-gen/test_outputs/signals.rs | 427 +++++++-- 24 files changed, 3509 insertions(+), 834 deletions(-) diff --git a/crates/cxx-qt-gen/src/generator/cpp/externcxxqt.rs b/crates/cxx-qt-gen/src/generator/cpp/externcxxqt.rs index f3ba79b69..fd3ca3e1b 100644 --- a/crates/cxx-qt-gen/src/generator/cpp/externcxxqt.rs +++ b/crates/cxx-qt-gen/src/generator/cpp/externcxxqt.rs @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::{ - generator::cpp::signal::generate_cpp_free_signal, + generator::cpp::signal::generate_cpp_signal, parser::{externcxxqt::ParsedExternCxxQt, mappings::ParsedCxxMappings}, CppFragment, }; @@ -15,10 +15,10 @@ use syn::Result; pub struct GeneratedCppExternCxxQtBlocks { /// List of includes pub includes: BTreeSet, - /// List of methods - pub method: CppFragment, - /// Namespace of the method block - pub namespace: String, + /// List of forward declares before the class and include of the generated CXX header + pub forward_declares: Vec, + /// List of fragments + pub fragments: Vec, } pub fn generate( @@ -29,7 +29,13 @@ pub fn generate( for block in blocks { for signal in &block.signals { - out.push(generate_cpp_free_signal(signal, cxx_mappings)?); + let mut block = GeneratedCppExternCxxQtBlocks::default(); + let data = generate_cpp_signal(signal, &signal.qobject_ident, cxx_mappings)?; + block.includes = data.includes; + block.forward_declares = data.forward_declares; + block.fragments = data.fragments; + debug_assert!(data.methods.is_empty()); + out.push(block); } } @@ -58,9 +64,6 @@ mod tests { .unwrap()]; let generated = generate(&blocks, &ParsedCxxMappings::default()).unwrap(); assert_eq!(generated.len(), 2); - - assert_eq!(generated[0].namespace, "rust::cxxqtgen1::externcxxqt"); - assert_eq!(generated[1].namespace, "rust::cxxqtgen1::externcxxqt"); } #[test] @@ -86,10 +89,5 @@ mod tests { let generated = generate(&blocks, &cxx_mappings).unwrap(); assert_eq!(generated.len(), 1); - - assert_eq!( - generated[0].namespace, - "rust::cxxqtgen1::externcxxqt::mynamespace" - ); } } 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 3064b97e4..fa7b691e9 100644 --- a/crates/cxx-qt-gen/src/generator/cpp/property/mod.rs +++ b/crates/cxx-qt-gen/src/generator/cpp/property/mod.rs @@ -90,7 +90,7 @@ mod tests { assert_str_eq!(generated.metaobjects[1], "Q_PROPERTY(::std::unique_ptr opaqueProperty READ getOpaqueProperty WRITE setOpaqueProperty NOTIFY opaquePropertyChanged)"); // methods - assert_eq!(generated.methods.len(), 8); + assert_eq!(generated.methods.len(), 6); let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[0] { (header, source) } else { @@ -179,64 +179,133 @@ mod tests { }; assert_str_eq!(header, "Q_SIGNAL void trivialPropertyChanged();"); - let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[5] { + let header = if let CppFragment::Header(header) = &generated.methods[5] { + header + } else { + panic!("Expected header!") + }; + assert_str_eq!(header, "Q_SIGNAL void opaquePropertyChanged();"); + + assert_eq!(generated.fragments.len(), 2); + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[0] + { (header, source) } else { panic!("Expected Pair") }; assert_str_eq!( header, - "::QMetaObject::Connection trivialPropertyChangedConnect(::rust::Fn func, ::Qt::ConnectionType type);" + indoc! {r#" + namespace rust::cxxqtgen1 { + ::QMetaObject::Connection + MyObject_trivialPropertyChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlertrivialPropertyChanged closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1 + "#} ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamstrivialPropertyChanged *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_MyObject_signal_handler_trivialPropertyChanged(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamstrivialPropertyChanged *>::operator()(MyObject& self) + { + call_MyObject_signal_handler_trivialPropertyChanged(*this, self); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamstrivialPropertyChanged *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamstrivialPropertyChanged *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - MyObject::trivialPropertyChangedConnect(::rust::Fn func, ::Qt::ConnectionType type) + MyObject_trivialPropertyChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlertrivialPropertyChanged closure, ::Qt::ConnectionType type) { - return ::QObject::connect(this, + return ::QObject::connect( + &self, &MyObject::trivialPropertyChanged, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard guard(self); + closure.template operator()(self); }, type); } + } // namespace rust::cxxqtgen1 "#} ); - let header = if let CppFragment::Header(header) = &generated.methods[6] { - header - } else { - panic!("Expected header!") - }; - assert_str_eq!(header, "Q_SIGNAL void opaquePropertyChanged();"); - - let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[7] { + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[1] + { (header, source) } else { panic!("Expected Pair") }; assert_str_eq!( header, - "::QMetaObject::Connection opaquePropertyChangedConnect(::rust::Fn func, ::Qt::ConnectionType type);" + indoc! {r#" + namespace rust::cxxqtgen1 { + ::QMetaObject::Connection + MyObject_opaquePropertyChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandleropaquePropertyChanged closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1 + "#} ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsopaquePropertyChanged *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_MyObject_signal_handler_opaquePropertyChanged(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsopaquePropertyChanged *>::operator()(MyObject& self) + { + call_MyObject_signal_handler_opaquePropertyChanged(*this, self); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsopaquePropertyChanged *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsopaquePropertyChanged *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - MyObject::opaquePropertyChangedConnect(::rust::Fn func, ::Qt::ConnectionType type) + MyObject_opaquePropertyChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandleropaquePropertyChanged closure, ::Qt::ConnectionType type) { - return ::QObject::connect(this, + return ::QObject::connect( + &self, &MyObject::opaquePropertyChanged, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard guard(self); + closure.template operator()(self); }, type); } + } // namespace rust::cxxqtgen1 "#} ); @@ -304,7 +373,7 @@ mod tests { assert_str_eq!(generated.metaobjects[0], "Q_PROPERTY(A1 mappedProperty READ getMappedProperty WRITE setMappedProperty NOTIFY mappedPropertyChanged)"); // methods - assert_eq!(generated.methods.len(), 4); + assert_eq!(generated.methods.len(), 3); let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[0] { (header, source) } else { @@ -347,30 +416,65 @@ mod tests { }; assert_str_eq!(header, "Q_SIGNAL void mappedPropertyChanged();"); - let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[3] { + assert_eq!(generated.fragments.len(), 1); + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[0] + { (header, source) } else { panic!("Expected Pair") }; assert_str_eq!( header, - "::QMetaObject::Connection mappedPropertyChangedConnect(::rust::Fn func, ::Qt::ConnectionType type);" + indoc! {r#" + namespace rust::cxxqtgen1 { + ::QMetaObject::Connection + MyObject_mappedPropertyChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlermappedPropertyChanged closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1 + "#} ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsmappedPropertyChanged *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_MyObject_signal_handler_mappedPropertyChanged(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsmappedPropertyChanged *>::operator()(MyObject& self) + { + call_MyObject_signal_handler_mappedPropertyChanged(*this, self); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsmappedPropertyChanged *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsmappedPropertyChanged *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - MyObject::mappedPropertyChangedConnect(::rust::Fn func, ::Qt::ConnectionType type) + MyObject_mappedPropertyChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlermappedPropertyChanged closure, ::Qt::ConnectionType type) { - return ::QObject::connect(this, + return ::QObject::connect( + &self, &MyObject::mappedPropertyChanged, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard guard(self); + closure.template operator()(self); }, type); } + } // namespace rust::cxxqtgen1 "#} ); diff --git a/crates/cxx-qt-gen/src/generator/cpp/qobject.rs b/crates/cxx-qt-gen/src/generator/cpp/qobject.rs index a6b5327c4..67e5fbf59 100644 --- a/crates/cxx-qt-gen/src/generator/cpp/qobject.rs +++ b/crates/cxx-qt-gen/src/generator/cpp/qobject.rs @@ -17,28 +17,40 @@ use syn::Result; #[derive(Default)] pub struct GeneratedCppQObjectBlocks { + /// List of includes + pub includes: BTreeSet, /// List of forward declares before the class and include of the generated CXX header + /// + /// For now these are not namespaced pub forward_declares: Vec, + /// List of forward declares before the class and include of the generated CXX header + // + // TODO: later combine these into forward_declares + // once we have solved how to handle namespacing + pub forward_declares_namespaced: Vec, + /// List of fragments which are outside of the QObject namespace + pub fragments: Vec, + /// Base class of the QObject + pub base_classes: Vec, /// List of Qt Meta Object items (eg Q_PROPERTY) pub metaobjects: Vec, /// List of public methods for the QObject pub methods: Vec, /// List of private methods for the QObject pub private_methods: Vec, - /// List of includes - pub includes: BTreeSet, - /// Base class of the QObject - pub base_classes: Vec, } impl GeneratedCppQObjectBlocks { pub fn append(&mut self, other: &mut Self) { + self.includes.append(&mut other.includes); self.forward_declares.append(&mut other.forward_declares); + self.forward_declares_namespaced + .append(&mut other.forward_declares_namespaced); + self.fragments.append(&mut other.fragments); + self.base_classes.append(&mut other.base_classes); self.metaobjects.append(&mut other.metaobjects); self.methods.append(&mut other.methods); self.private_methods.append(&mut other.private_methods); - self.includes.append(&mut other.includes); - self.base_classes.append(&mut other.base_classes); } pub fn from(qobject: &ParsedQObject) -> GeneratedCppQObjectBlocks { diff --git a/crates/cxx-qt-gen/src/generator/cpp/signal.rs b/crates/cxx-qt-gen/src/generator/cpp/signal.rs index 23dae16e7..f8224ac16 100644 --- a/crates/cxx-qt-gen/src/generator/cpp/signal.rs +++ b/crates/cxx-qt-gen/src/generator/cpp/signal.rs @@ -5,12 +5,11 @@ use crate::{ generator::{ - cpp::{ - externcxxqt::GeneratedCppExternCxxQtBlocks, fragment::CppFragment, - qobject::GeneratedCppQObjectBlocks, + cpp::{fragment::CppFragment, qobject::GeneratedCppQObjectBlocks}, + naming::{ + qobject::QObjectName, + signals::{QSignalHelperName, QSignalName}, }, - naming::namespace::namespace_externcxxqt_with_qobject_namespace, - naming::{qobject::QObjectName, signals::QSignalName}, utils::cpp::syn_type_to_cpp_type, }, parser::{ @@ -18,117 +17,178 @@ use crate::{ }, }; use indoc::formatdoc; -use syn::Result; +use std::collections::BTreeSet; +use syn::{Ident, Result}; + +#[derive(Default)] +pub struct CppSignalFragment { + /// List of includes + pub includes: BTreeSet, + /// List of forward declares that go before the CXX include + pub forward_declares: Vec, + /// List of fragments that go at the top of the header or source + /// + /// Note that these should include their namespace + pub fragments: Vec, + /// Any methods for the class + pub methods: Vec, +} /// Combined output of possible parameter lines to be used struct Parameters { - types_closure: String, - types_signal: String, - values_closure: String, -} - -/// Representation of the self pair -/// -/// This allows for *this being passed or a parameter in the arguments -struct SelfValue<'a> { - ident: &'a str, - ty: &'a str, + /// name with type of parameters + named_types: String, + /// name with type of parameters including self + named_types_with_self: String, + /// Raw types of the parameters including self + types_with_self: String, + /// Raw ::std::move values of the parameters including self + values_with_self: String, } /// From given parameters, mappings, and self value constructor the combined parameter lines fn parameter_types_and_values( parameters: &[ParsedFunctionParameter], cxx_mappings: &ParsedCxxMappings, - self_value: SelfValue, + self_ty: &str, ) -> Result { - let mut parameter_types_closure = vec![]; - let mut parameter_values_closure = vec![]; + let mut parameter_named_types_with_self = vec![]; + let mut parameter_types_with_self = vec![]; + let mut parameter_values_with_self = vec![]; for parameter in parameters { let cxx_ty = syn_type_to_cpp_type(¶meter.ty, cxx_mappings)?; let ident_str = parameter.ident.to_string(); - parameter_types_closure.push(format!("{cxx_ty} {ident_str}",)); - parameter_values_closure.push(format!("::std::move({ident_str})")); + parameter_named_types_with_self.push(format!("{cxx_ty} {ident_str}",)); + parameter_types_with_self.push(cxx_ty.clone()); + parameter_values_with_self.push(format!("::std::move({ident_str})")); } - let parameters_types_signal = parameter_types_closure.join(", "); + let parameter_named_types = parameter_named_types_with_self.join(", "); // Insert the extra argument into the closure - parameter_types_closure.insert(0, format!("{ty}&", ty = self_value.ty)); - parameter_values_closure.insert(0, self_value.ident.to_owned()); + let self_ty = cxx_mappings.cxx(self_ty); + parameter_named_types_with_self.insert(0, format!("{self_ty}& self")); + parameter_types_with_self.insert(0, format!("{self_ty}&")); + parameter_values_with_self.insert(0, "self".to_owned()); Ok(Parameters { - types_closure: parameter_types_closure.join(", "), - types_signal: parameters_types_signal, - values_closure: parameter_values_closure.join(", "), + named_types: parameter_named_types, + named_types_with_self: parameter_named_types_with_self.join(", "), + types_with_self: parameter_types_with_self.join(", "), + values_with_self: parameter_values_with_self.join(", "), }) } -/// Generate C++ blocks for a free signal on an existing QObject (not generated by CXX-Qt), eg QPushButton::clicked -pub fn generate_cpp_free_signal( +pub fn generate_cpp_signal( signal: &ParsedSignal, + qobject_ident: &Ident, cxx_mappings: &ParsedCxxMappings, -) -> Result { - let mut generated = GeneratedCppExternCxxQtBlocks::default(); +) -> Result { + let mut generated = CppSignalFragment::default(); + + // Add the include we need + generated + .includes + .insert("#include ".to_owned()); - // Prepare the idents we need - let qobject_ident = signal.qobject_ident.to_string(); - let qobject_ident_namespaced = cxx_mappings.cxx(&qobject_ident); + // Build a namespace that includes any namespace for the T + let qobject_ident_str = qobject_ident.to_string(); + let qobject_ident_namespaced = cxx_mappings.cxx(&qobject_ident_str); + + // Prepare the idents let idents = QSignalName::from(signal); - let signal_ident = idents.name.cpp.to_string(); - // TODO: in the future we might improve the naming of the methods - // to avoid collisions (maybe use a separator similar to how CXX uses $?) - let connect_ident = idents.connect_name.cpp.to_string(); + let idents_helper = QSignalHelperName::new(&idents, qobject_ident, cxx_mappings); + + let signal_ident = idents.name.cpp; + let free_connect_ident_cpp = idents_helper.connect_name.cpp; // Retrieve the parameters for the signal - let parameters = parameter_types_and_values( - &signal.parameters, - cxx_mappings, - SelfValue { - ident: "self", - ty: &qobject_ident_namespaced, - }, - )?; - let parameters_types_closure = parameters.types_closure; - let parameters_types_signal = parameters.types_signal; - let parameters_values_closure = parameters.values_closure; + let parameters = + parameter_types_and_values(&signal.parameters, cxx_mappings, &qobject_ident_namespaced)?; + let parameters_named_types = parameters.named_types; + let parameters_named_types_with_self = parameters.named_types_with_self; + let parameter_types_with_self = parameters.types_with_self; + let parameter_values_with_self = parameters.values_with_self; + + let param_struct = idents_helper.struct_param; + let signal_handler_alias = idents_helper.handler_alias; + let signal_handler_alias_namespaced = idents_helper.handler_alias_namespaced; + let signal_handler_call = idents_helper.function_call; + let signal_handler_drop = idents_helper.function_drop; + let namespace = idents_helper.namespace; + + let signal_handler_type = format!("SignalHandler<::{namespace}::{param_struct} *>"); + + generated.forward_declares.push(formatdoc! { + r#" + namespace {namespace} {{ + using {signal_handler_alias} = ::rust::cxxqtlib1::SignalHandler; + }} // namespace {namespace} + "# + }); + + // Generate the Q_SIGNAL if this is not an existing signal + if !signal.inherit { + generated.methods.push(CppFragment::Header(format!( + "Q_SIGNAL void {signal_ident}({parameters_named_types});" + ))); + } - generated.method = CppFragment::Pair { - header: formatdoc!( - r#" - ::QMetaObject::Connection - {qobject_ident}_{connect_ident}({qobject_ident_namespaced}& self, ::rust::Fn func, ::Qt::ConnectionType type); - "#, - ), + generated.fragments.push(CppFragment::Pair { + header: formatdoc! { + r#" + namespace {namespace} {{ + ::QMetaObject::Connection + {free_connect_ident_cpp}({qobject_ident_namespaced}& self, {signal_handler_alias_namespaced} closure, ::Qt::ConnectionType type); + }} // namespace {namespace} + "# + }, source: formatdoc! { r#" - ::QMetaObject::Connection - {qobject_ident}_{connect_ident}({qobject_ident_namespaced}& self, ::rust::Fn func, ::Qt::ConnectionType type) - {{ - return ::QObject::connect( - &self, - &{qobject_ident_namespaced}::{signal_ident}, - &self, - [&, func = ::std::move(func)]({parameters_types_signal}) {{ - const ::rust::cxxqtlib1::MaybeLockGuard<{qobject_ident_namespaced}> guard(self); - func({parameters_values_closure}); - }}, - type); - }} - "#, - }, - }; + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 {{ + template <> + {signal_handler_type}::~SignalHandler() + {{ + if (data[0] == nullptr && data[1] == nullptr) + {{ + return; + }} - // Build a namespace that includes any namespace for the T - generated.namespace = namespace_externcxxqt_with_qobject_namespace( - cxx_mappings - .namespaces - .get(&signal.qobject_ident.to_string()), - ); + {signal_handler_drop}(::std::move(*this)); + }} - generated - .includes - .insert("#include ".to_owned()); + template <> + template <> + void {signal_handler_type}::operator()<{parameter_types_with_self}>({parameters_named_types_with_self}) + {{ + {signal_handler_call}(*this, {parameter_values_with_self}); + }} + + static_assert(alignof({signal_handler_type}) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof({signal_handler_type}) == sizeof(::std::size_t[2]), "unexpected size"); + }} // namespace rust::cxxqtlib1 + + namespace {namespace} {{ + ::QMetaObject::Connection + {free_connect_ident_cpp}({qobject_ident_namespaced}& self, {signal_handler_alias_namespaced} closure, ::Qt::ConnectionType type) + {{ + return ::QObject::connect( + &self, + &{qobject_ident_namespaced}::{signal_ident}, + &self, + [&, closure = ::std::move(closure)]({parameters_named_types}) mutable {{ + const ::rust::cxxqtlib1::MaybeLockGuard<{qobject_ident_namespaced}> guard(self); + closure.template operator()<{parameter_types_with_self}>({parameter_values_with_self}); + }}, + type); + }} + }} // namespace {namespace} + "#, + } + }); Ok(generated) } @@ -139,61 +199,16 @@ pub fn generate_cpp_signals( cxx_mappings: &ParsedCxxMappings, ) -> Result { let mut generated = GeneratedCppQObjectBlocks::default(); - let qobject_ident = qobject_idents.cpp_class.cpp.to_string(); - - if !signals.is_empty() { - generated - .includes - .insert("#include ".to_owned()); - } + let qobject_ident = &qobject_idents.cpp_class.cpp; for signal in signals { - // Prepare the idents - let idents = QSignalName::from(signal); - let signal_ident = idents.name.cpp.to_string(); - let connect_ident = idents.connect_name.cpp.to_string(); - - // Generate the parameters - let parameters = parameter_types_and_values( - &signal.parameters, - cxx_mappings, - SelfValue { - ident: "*this", - ty: &qobject_ident, - }, - )?; - let parameters_types_closure = parameters.types_closure; - let parameters_types_signal = parameters.types_signal; - let parameters_values_closure = parameters.values_closure; - - // Generate the Q_SIGNAL if this is not an existing signal - if !signal.inherit { - generated.methods.push(CppFragment::Header(format!( - "Q_SIGNAL void {signal_ident}({parameters_types_signal});" - ))); - } - - generated.methods.push(CppFragment::Pair { - header: format!( - "::QMetaObject::Connection {connect_ident}(::rust::Fn func, ::Qt::ConnectionType type);", - ), - source: formatdoc! { - r#" - ::QMetaObject::Connection - {qobject_ident}::{connect_ident}(::rust::Fn func, ::Qt::ConnectionType type) - {{ - return ::QObject::connect(this, - &{qobject_ident}::{signal_ident}, - this, - [&, func = ::std::move(func)]({parameters_types_signal}) {{ - const ::rust::cxxqtlib1::MaybeLockGuard<{qobject_ident}> guard(*this); - func({parameters_values_closure}); - }}, - type); - }} - "#, - }, - }); + let mut block = GeneratedCppQObjectBlocks::default(); + let data = generate_cpp_signal(signal, qobject_ident, cxx_mappings)?; + block.includes = data.includes; + block.forward_declares_namespaced = data.forward_declares; + block.fragments = data.fragments; + block.methods = data.methods; + generated.append(&mut block); } Ok(generated) @@ -241,7 +256,7 @@ mod tests { let generated = generate_cpp_signals(&signals, &qobject_idents, &ParsedCxxMappings::default()).unwrap(); - assert_eq!(generated.methods.len(), 2); + assert_eq!(generated.methods.len(), 1); let header = if let CppFragment::Header(header) = &generated.methods[0] { header } else { @@ -252,30 +267,65 @@ mod tests { "Q_SIGNAL void dataChanged(::std::int32_t trivial, ::std::unique_ptr opaque);" ); - let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[1] { + assert_eq!(generated.fragments.len(), 1); + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[0] + { (header, source) } else { panic!("Expected Pair") }; assert_str_eq!( header, - "::QMetaObject::Connection dataChangedConnect(::rust::Fn opaque)> func, ::Qt::ConnectionType type);" + indoc! {r#" + namespace rust::cxxqtgen1 { + ::QMetaObject::Connection + MyObject_dataChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerdataChanged closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1 + "#} ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_MyObject_signal_handler_dataChanged(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>::operator()>(MyObject& self, ::std::int32_t trivial, ::std::unique_ptr opaque) + { + call_MyObject_signal_handler_dataChanged(*this, self, ::std::move(trivial), ::std::move(opaque)); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - MyObject::dataChangedConnect(::rust::Fn opaque)> func, ::Qt::ConnectionType type) + MyObject_dataChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerdataChanged closure, ::Qt::ConnectionType type) { - return ::QObject::connect(this, + return ::QObject::connect( + &self, &MyObject::dataChanged, - this, - [&, func = ::std::move(func)](::std::int32_t trivial, ::std::unique_ptr opaque) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this, ::std::move(trivial), ::std::move(opaque)); + &self, + [&, closure = ::std::move(closure)](::std::int32_t trivial, ::std::unique_ptr opaque) mutable { + const ::rust::cxxqtlib1::MaybeLockGuard guard(self); + closure.template operator()>(self, ::std::move(trivial), ::std::move(opaque)); }, type); } + } // namespace rust::cxxqtgen1 "#} ); } @@ -309,7 +359,7 @@ mod tests { let generated = generate_cpp_signals(&signals, &qobject_idents, &cxx_mappings).unwrap(); - assert_eq!(generated.methods.len(), 2); + assert_eq!(generated.methods.len(), 1); let header = if let CppFragment::Header(header) = &generated.methods[0] { header } else { @@ -317,30 +367,65 @@ mod tests { }; assert_str_eq!(header, "Q_SIGNAL void dataChanged(A1 mapped);"); - let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[1] { + assert_eq!(generated.fragments.len(), 1); + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[0] + { (header, source) } else { panic!("Expected Pair") }; assert_str_eq!( header, - "::QMetaObject::Connection dataChangedConnect(::rust::Fn func, ::Qt::ConnectionType type);" + indoc! {r#" + namespace rust::cxxqtgen1 { + ::QMetaObject::Connection + MyObject_dataChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerdataChanged closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1 + "#} ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_MyObject_signal_handler_dataChanged(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>::operator()(MyObject& self, A1 mapped) + { + call_MyObject_signal_handler_dataChanged(*this, self, ::std::move(mapped)); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsdataChanged *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - MyObject::dataChangedConnect(::rust::Fn func, ::Qt::ConnectionType type) + MyObject_dataChangedConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerdataChanged closure, ::Qt::ConnectionType type) { - return ::QObject::connect(this, + return ::QObject::connect( + &self, &MyObject::dataChanged, - this, - [&, func = ::std::move(func)](A1 mapped) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this, ::std::move(mapped)); + &self, + [&, closure = ::std::move(closure)](A1 mapped) mutable { + const ::rust::cxxqtlib1::MaybeLockGuard guard(self); + closure.template operator()(self, ::std::move(mapped)); }, type); } + } // namespace rust::cxxqtgen1 "#} ); } @@ -368,29 +453,67 @@ mod tests { let generated = generate_cpp_signals(&signals, &qobject_idents, &ParsedCxxMappings::default()).unwrap(); - assert_eq!(generated.methods.len(), 1); + assert_eq!(generated.methods.len(), 0); + assert_eq!(generated.fragments.len(), 1); - let (header, source) = if let CppFragment::Pair { header, source } = &generated.methods[0] { + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[0] + { (header, source) } else { panic!("Expected Pair") }; - assert_str_eq!(header, "::QMetaObject::Connection baseNameConnect(::rust::Fn func, ::Qt::ConnectionType type);"); + assert_str_eq!( + header, + indoc! {r#" + namespace rust::cxxqtgen1 { + ::QMetaObject::Connection + MyObject_baseNameConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerbaseName closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1 + "#} + ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsbaseName *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_MyObject_signal_handler_baseName(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsbaseName *>::operator()(MyObject& self) + { + call_MyObject_signal_handler_baseName(*this, self); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsbaseName *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::MyObjectCxxQtSignalParamsbaseName *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - MyObject::baseNameConnect(::rust::Fn func, ::Qt::ConnectionType type) + MyObject_baseNameConnect(MyObject& self, ::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerbaseName closure, ::Qt::ConnectionType type) { - return ::QObject::connect(this, + return ::QObject::connect( + &self, &MyObject::baseName, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard guard(self); + closure.template operator()(self); }, type); } + } // namespace rust::cxxqtgen1 "#} ); } @@ -409,13 +532,22 @@ mod tests { rust: format_ident!("signal_rust_name"), }, safe: true, - inherit: false, + inherit: true, private: false, }; - let generated = generate_cpp_free_signal(&signal, &ParsedCxxMappings::default()).unwrap(); + let generated = generate_cpp_signal( + &signal, + &signal.qobject_ident, + &ParsedCxxMappings::default(), + ) + .unwrap(); + + assert_eq!(generated.methods.len(), 0); - let (header, source) = if let CppFragment::Pair { header, source } = &generated.method { + assert_eq!(generated.fragments.len(), 1); + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[0] + { (header, source) } else { panic!("Expected Pair") @@ -425,26 +557,55 @@ mod tests { header, indoc! { r#" + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - ObjRust_signalRustNameConnect(ObjRust& self, ::rust::Fn func, ::Qt::ConnectionType type); + ObjRust_signalRustNameConnect(ObjRust& self, ::rust::cxxqtgen1::ObjRustCxxQtSignalHandlersignalRustName closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1 "#} ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::ObjRustCxxQtSignalParamssignalRustName *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_ObjRust_signal_handler_signalRustName(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::ObjRustCxxQtSignalParamssignalRustName *>::operator()(ObjRust& self) + { + call_ObjRust_signal_handler_signalRustName(*this, self); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::ObjRustCxxQtSignalParamssignalRustName *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::ObjRustCxxQtSignalParamssignalRustName *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1 { ::QMetaObject::Connection - ObjRust_signalRustNameConnect(ObjRust& self, ::rust::Fn func, ::Qt::ConnectionType type) + ObjRust_signalRustNameConnect(ObjRust& self, ::rust::cxxqtgen1::ObjRustCxxQtSignalHandlersignalRustName closure, ::Qt::ConnectionType type) { return ::QObject::connect( &self, &ObjRust::signalRustName, &self, - [&, func = ::std::move(func)]() { + [&, closure = ::std::move(closure)]() mutable { const ::rust::cxxqtlib1::MaybeLockGuard guard(self); - func(self); + closure.template operator()(self); }, type); } + } // namespace rust::cxxqtgen1 "#} ); } @@ -464,7 +625,7 @@ mod tests { rust: format_ident!("signal_rust_name"), }, safe: true, - inherit: false, + inherit: true, private: false, }; @@ -476,9 +637,13 @@ mod tests { .namespaces .insert("ObjRust".to_owned(), "mynamespace".to_owned()); - let generated = generate_cpp_free_signal(&signal, &cxx_mappings).unwrap(); + let generated = generate_cpp_signal(&signal, &signal.qobject_ident, &cxx_mappings).unwrap(); + + assert_eq!(generated.methods.len(), 0); - let (header, source) = if let CppFragment::Pair { header, source } = &generated.method { + assert_eq!(generated.fragments.len(), 1); + let (header, source) = if let CppFragment::Pair { header, source } = &generated.fragments[0] + { (header, source) } else { panic!("Expected Pair") @@ -488,26 +653,55 @@ mod tests { header, indoc! { r#" + namespace rust::cxxqtgen1::mynamespace { ::QMetaObject::Connection - ObjRust_signalCxxNameConnect(::mynamespace::ObjCpp& self, ::rust::Fn func, ::Qt::ConnectionType type); + ObjRust_signalCxxNameConnect(::mynamespace::ObjCpp& self, ::rust::cxxqtgen1::mynamespace::ObjRustCxxQtSignalHandlersignalCxxName closure, ::Qt::ConnectionType type); + } // namespace rust::cxxqtgen1::mynamespace "#} ); assert_str_eq!( source, indoc! {r#" + // Define namespace otherwise we hit a GCC bug + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + namespace rust::cxxqtlib1 { + template <> + SignalHandler<::rust::cxxqtgen1::mynamespace::ObjRustCxxQtSignalParamssignalCxxName *>::~SignalHandler() + { + if (data[0] == nullptr && data[1] == nullptr) + { + return; + } + + drop_ObjRust_signal_handler_signalCxxName(::std::move(*this)); + } + + template <> + template <> + void SignalHandler<::rust::cxxqtgen1::mynamespace::ObjRustCxxQtSignalParamssignalCxxName *>::operator()<::mynamespace::ObjCpp&>(::mynamespace::ObjCpp& self) + { + call_ObjRust_signal_handler_signalCxxName(*this, self); + } + + static_assert(alignof(SignalHandler<::rust::cxxqtgen1::mynamespace::ObjRustCxxQtSignalParamssignalCxxName *>) <= alignof(::std::size_t), "unexpected aligment"); + static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::mynamespace::ObjRustCxxQtSignalParamssignalCxxName *>) == sizeof(::std::size_t[2]), "unexpected size"); + } // namespace rust::cxxqtlib1 + + namespace rust::cxxqtgen1::mynamespace { ::QMetaObject::Connection - ObjRust_signalCxxNameConnect(::mynamespace::ObjCpp& self, ::rust::Fn func, ::Qt::ConnectionType type) + ObjRust_signalCxxNameConnect(::mynamespace::ObjCpp& self, ::rust::cxxqtgen1::mynamespace::ObjRustCxxQtSignalHandlersignalCxxName closure, ::Qt::ConnectionType type) { return ::QObject::connect( &self, &::mynamespace::ObjCpp::signalCxxName, &self, - [&, func = ::std::move(func)]() { + [&, closure = ::std::move(closure)]() mutable { const ::rust::cxxqtlib1::MaybeLockGuard<::mynamespace::ObjCpp> guard(self); - func(self); + closure.template operator()<::mynamespace::ObjCpp&>(self); }, type); } + } // namespace rust::cxxqtgen1::mynamespace "#} ); } diff --git a/crates/cxx-qt-gen/src/generator/naming/namespace.rs b/crates/cxx-qt-gen/src/generator/naming/namespace.rs index 5f21f546c..01f216a97 100644 --- a/crates/cxx-qt-gen/src/generator/naming/namespace.rs +++ b/crates/cxx-qt-gen/src/generator/naming/namespace.rs @@ -38,16 +38,6 @@ pub fn namespace_combine_ident(namespace: &str, ident: &Ident) -> String { format!("{namespace}::{ident}") } -/// Build the externcxxqt namespace combined with the given qobject_namespace -pub fn namespace_externcxxqt_with_qobject_namespace(qobject_namespace: Option<&String>) -> String { - let mut free_namespace = vec!["rust::cxxqtgen1::externcxxqt"]; - if let Some(qobject_namespace) = qobject_namespace { - free_namespace.push(qobject_namespace); - } - - free_namespace.join("::") -} - /// For a given base namespace and QObject ident generate the internal namespace /// /// The base namespace could be from the module bridge or from the QObject diff --git a/crates/cxx-qt-gen/src/generator/naming/signals.rs b/crates/cxx-qt-gen/src/generator/naming/signals.rs index 9ead2bf9e..0c4f71d32 100644 --- a/crates/cxx-qt-gen/src/generator/naming/signals.rs +++ b/crates/cxx-qt-gen/src/generator/naming/signals.rs @@ -2,8 +2,8 @@ // SPDX-FileContributor: Andrew Hayzen // // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::generator::naming::CombinedIdent; use crate::parser::signals::ParsedSignal; +use crate::{generator::naming::CombinedIdent, parser::mappings::ParsedCxxMappings}; use convert_case::{Case, Casing}; use quote::format_ident; use syn::Ident; @@ -40,6 +40,53 @@ impl CombinedIdent { } } +pub struct QSignalHelperName { + pub connect_name: CombinedIdent, + pub function_call: Ident, + pub function_drop: Ident, + pub handler_alias: Ident, + pub handler_alias_namespaced: String, + pub namespace: String, + pub struct_closure: Ident, + pub struct_param: Ident, +} + +impl QSignalHelperName { + pub fn new( + idents: &QSignalName, + qobject_ident: &Ident, + cxx_mappings: &ParsedCxxMappings, + ) -> Self { + let signal_ident = &idents.name.cpp; + let handler_alias = format_ident!("{qobject_ident}CxxQtSignalHandler{signal_ident}"); + let namespace = { + let mut namespace = vec!["rust::cxxqtgen1"]; + if let Some(qobject_namespace) = cxx_mappings.namespaces.get(&qobject_ident.to_string()) + { + namespace.push(qobject_namespace); + } + + namespace.join("::") + }; + + // TODO: in the future we might improve the naming of the methods + // to avoid collisions (maybe use a separator similar to how CXX uses $?) + Self { + connect_name: CombinedIdent { + cpp: format_ident!("{}_{}", qobject_ident, idents.connect_name.cpp), + rust: format_ident!("{}_{}", qobject_ident, idents.connect_name.rust), + }, + function_drop: format_ident!("drop_{qobject_ident}_signal_handler_{signal_ident}"), + function_call: format_ident!("call_{qobject_ident}_signal_handler_{signal_ident}"), + handler_alias_namespaced: format!("::{namespace}::{handler_alias}"), + struct_closure: format_ident!("{qobject_ident}CxxQtSignalClosure{signal_ident}"), + struct_param: format_ident!("{qobject_ident}CxxQtSignalParams{signal_ident}"), + namespace, + handler_alias, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/cxx-qt-gen/src/generator/rust/externcxxqt.rs b/crates/cxx-qt-gen/src/generator/rust/externcxxqt.rs index ab192d96f..f0797c217 100644 --- a/crates/cxx-qt-gen/src/generator/rust/externcxxqt.rs +++ b/crates/cxx-qt-gen/src/generator/rust/externcxxqt.rs @@ -6,7 +6,7 @@ use crate::{ generator::rust::{ fragment::{GeneratedRustFragment, RustFragmentPair}, - signals::generate_rust_free_signal, + signals::generate_rust_signal, }, parser::{externcxxqt::ParsedExternCxxQt, mappings::ParsedCxxMappings}, }; @@ -40,8 +40,11 @@ impl GeneratedRustFragment { // Build the signals for signal in &extern_cxxqt_block.signals { - generated.append(&mut generate_rust_free_signal( + let qobject_name = &signal.qobject_ident; + + generated.append(&mut generate_rust_signal( signal, + qobject_name, cxx_mappings, module_ident, )?); 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 cfcc23e9a..398076fa9 100644 --- a/crates/cxx-qt-gen/src/generator/rust/property/mod.rs +++ b/crates/cxx-qt-gen/src/generator/rust/property/mod.rs @@ -14,7 +14,7 @@ use crate::{ }, parser::{mappings::ParsedCxxMappings, property::ParsedQProperty}, }; -use syn::Result; +use syn::{Ident, Result}; use super::signals::generate_rust_signals; @@ -22,6 +22,7 @@ pub fn generate_rust_properties( properties: &Vec, qobject_idents: &QObjectName, cxx_mappings: &ParsedCxxMappings, + module_ident: &Ident, ) -> Result { let mut generated = GeneratedRustFragment::default(); let mut signals = vec![]; @@ -65,6 +66,7 @@ pub fn generate_rust_properties( &signals, qobject_idents, cxx_mappings, + module_ident, )?); Ok(generated) @@ -96,13 +98,17 @@ mod tests { ]; let qobject_idents = create_qobjectname(); - let generated = - generate_rust_properties(&properties, &qobject_idents, &ParsedCxxMappings::default()) - .unwrap(); + let generated = generate_rust_properties( + &properties, + &qobject_idents, + &ParsedCxxMappings::default(), + &format_ident!("ffi"), + ) + .unwrap(); // Check that we have the expected number of blocks - assert_eq!(generated.cxx_mod_contents.len(), 12); - assert_eq!(generated.cxx_qt_mod_contents.len(), 9); + assert_eq!(generated.cxx_mod_contents.len(), 15); + assert_eq!(generated.cxx_qt_mod_contents.len(), 30); // Trivial Property @@ -265,13 +271,15 @@ mod tests { // Signals + // trivial_property + assert_tokens_eq( &generated.cxx_mod_contents[6], parse_quote! { unsafe extern "C++" { #[doc = "Notify for the Q_PROPERTY"] - #[rust_name = "trivial_property_changed"] - fn trivialPropertyChanged(self: Pin<&mut MyObject>, ); + #[cxx_name = "trivialPropertyChanged"] + fn trivial_property_changed(self: Pin<&mut MyObject>); } }, ); @@ -279,17 +287,53 @@ mod tests { &generated.cxx_mod_contents[7], parse_quote! { unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlertrivialPropertyChanged = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + #[must_use] + #[rust_name = "MyObject_connect_trivial_property_changed"] + fn MyObject_trivialPropertyChangedConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlertrivialPropertyChanged, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }, + ); + assert_tokens_eq( + &generated.cxx_mod_contents[8], + parse_quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_trivialPropertyChanged(handler: MyObjectCxxQtSignalHandlertrivialPropertyChanged); + + #[doc(hidden)] + fn call_MyObject_signal_handler_trivialPropertyChanged(handler: &mut MyObjectCxxQtSignalHandlertrivialPropertyChanged, self_value: Pin<&mut MyObject>, ); + } + }, + ); + + assert_tokens_eq( + &generated.cxx_qt_mod_contents[6], + parse_quote! { + impl MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "trivialPropertyChanged"] #[doc = ", so that when the signal is emitted the function pointer is executed."] #[must_use] - #[rust_name = "connect_trivial_property_changed"] - fn trivialPropertyChangedConnect(self: Pin <&mut MyObject>, func: fn(Pin<&mut MyObject>, ), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + pub fn connect_trivial_property_changed, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + { + ffi::MyObject_connect_trivial_property_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) + } } }, ); assert_tokens_eq( - &generated.cxx_qt_mod_contents[6], + &generated.cxx_qt_mod_contents[7], parse_quote! { impl MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -298,39 +342,126 @@ mod tests { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_trivial_property_changed(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, )) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_trivial_property_changed, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_trivial_property_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_trivial_property_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[8], + parse_quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosuretrivialPropertyChanged {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[9], + parse_quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosuretrivialPropertyChanged { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlertrivialPropertyChanged"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[10], + parse_quote! { + use core::mem::drop as drop_MyObject_signal_handler_trivialPropertyChanged; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[11], + parse_quote! { + fn call_MyObject_signal_handler_trivialPropertyChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + ) { + handler.closure()(self_value, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[12], + parse_quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[13], + parse_quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); + + // opaque_property assert_tokens_eq( - &generated.cxx_mod_contents[8], + &generated.cxx_mod_contents[9], parse_quote! { unsafe extern "C++" { #[doc = "Notify for the Q_PROPERTY"] - #[rust_name = "opaque_property_changed"] - fn opaquePropertyChanged(self: Pin<&mut MyObject>, ); + #[cxx_name = "opaquePropertyChanged"] + fn opaque_property_changed(self: Pin<&mut MyObject>); } }, ); assert_tokens_eq( - &generated.cxx_mod_contents[9], + &generated.cxx_mod_contents[10], parse_quote! { unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandleropaquePropertyChanged = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + #[must_use] + #[rust_name = "MyObject_connect_opaque_property_changed"] + fn MyObject_opaquePropertyChangedConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandleropaquePropertyChanged, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }, + ); + assert_tokens_eq( + &generated.cxx_mod_contents[11], + parse_quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_opaquePropertyChanged(handler: MyObjectCxxQtSignalHandleropaquePropertyChanged); + + #[doc(hidden)] + fn call_MyObject_signal_handler_opaquePropertyChanged(handler: &mut MyObjectCxxQtSignalHandleropaquePropertyChanged, self_value: Pin<&mut MyObject>, ); + } + }, + ); + + assert_tokens_eq( + &generated.cxx_qt_mod_contents[14], + parse_quote! { + impl MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "opaquePropertyChanged"] #[doc = ", so that when the signal is emitted the function pointer is executed."] #[must_use] - #[rust_name = "connect_opaque_property_changed"] - fn opaquePropertyChangedConnect(self: Pin <&mut MyObject>, func: fn(Pin<&mut MyObject>, ), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + pub fn connect_opaque_property_changed, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + { + ffi::MyObject_connect_opaque_property_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) + } } }, ); assert_tokens_eq( - &generated.cxx_qt_mod_contents[7], + &generated.cxx_qt_mod_contents[15], parse_quote! { impl MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -339,39 +470,126 @@ mod tests { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_opaque_property_changed(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, )) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_opaque_property_changed, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_opaque_property_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_opaque_property_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[16], + parse_quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosureopaquePropertyChanged {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[17], + parse_quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureopaquePropertyChanged { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandleropaquePropertyChanged"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[18], + parse_quote! { + use core::mem::drop as drop_MyObject_signal_handler_opaquePropertyChanged; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[19], + parse_quote! { + fn call_MyObject_signal_handler_opaquePropertyChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + ) { + handler.closure()(self_value, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[20], + parse_quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[21], + parse_quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); + + // unsafe_property assert_tokens_eq( - &generated.cxx_mod_contents[10], + &generated.cxx_mod_contents[12], parse_quote! { unsafe extern "C++" { #[doc = "Notify for the Q_PROPERTY"] - #[rust_name = "unsafe_property_changed"] - fn unsafePropertyChanged(self: Pin<&mut MyObject>, ); + #[cxx_name = "unsafePropertyChanged"] + fn unsafe_property_changed(self: Pin<&mut MyObject>); } }, ); assert_tokens_eq( - &generated.cxx_mod_contents[11], + &generated.cxx_mod_contents[13], parse_quote! { unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlerunsafePropertyChanged = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + #[must_use] + #[rust_name = "MyObject_connect_unsafe_property_changed"] + fn MyObject_unsafePropertyChangedConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlerunsafePropertyChanged, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }, + ); + assert_tokens_eq( + &generated.cxx_mod_contents[14], + parse_quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_unsafePropertyChanged(handler: MyObjectCxxQtSignalHandlerunsafePropertyChanged); + + #[doc(hidden)] + fn call_MyObject_signal_handler_unsafePropertyChanged(handler: &mut MyObjectCxxQtSignalHandlerunsafePropertyChanged, self_value: Pin<&mut MyObject>, ); + } + }, + ); + + assert_tokens_eq( + &generated.cxx_qt_mod_contents[22], + parse_quote! { + impl MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "unsafePropertyChanged"] #[doc = ", so that when the signal is emitted the function pointer is executed."] #[must_use] - #[rust_name = "connect_unsafe_property_changed"] - fn unsafePropertyChangedConnect(self: Pin <&mut MyObject>, func: fn(Pin<&mut MyObject>, ), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + pub fn connect_unsafe_property_changed, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + { + ffi::MyObject_connect_unsafe_property_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) + } } }, ); assert_tokens_eq( - &generated.cxx_qt_mod_contents[8], + &generated.cxx_qt_mod_contents[23], parse_quote! { impl MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -380,12 +598,61 @@ mod tests { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_unsafe_property_changed(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, )) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_unsafe_property_changed, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_unsafe_property_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_unsafe_property_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[24], + parse_quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosureunsafePropertyChanged {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[25], + parse_quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureunsafePropertyChanged { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerunsafePropertyChanged"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[26], + parse_quote! { + use core::mem::drop as drop_MyObject_signal_handler_unsafePropertyChanged; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[27], + parse_quote! { + fn call_MyObject_signal_handler_unsafePropertyChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + ) { + handler.closure()(self_value, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[28], + parse_quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[29], + parse_quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); } } diff --git a/crates/cxx-qt-gen/src/generator/rust/property/signal.rs b/crates/cxx-qt-gen/src/generator/rust/property/signal.rs index 1611e754a..12ed1ae76 100644 --- a/crates/cxx-qt-gen/src/generator/rust/property/signal.rs +++ b/crates/cxx-qt-gen/src/generator/rust/property/signal.rs @@ -15,8 +15,10 @@ pub fn generate(idents: &QPropertyName, qobject_idents: &QObjectName) -> ParsedS // structs to build the signal name let cpp_class_rust = &qobject_idents.cpp_class.rust; let notify_rust = &idents.notify.rust; + let notify_cpp_str = &idents.notify.cpp.to_string(); let method: ForeignItemFn = syn::parse_quote! { #[doc = "Notify for the Q_PROPERTY"] + #[cxx_name = #notify_cpp_str] fn #notify_rust(self: Pin<&mut #cpp_class_rust>); }; ParsedSignal::from_property_method( diff --git a/crates/cxx-qt-gen/src/generator/rust/qobject.rs b/crates/cxx-qt-gen/src/generator/rust/qobject.rs index 0035474da..522efafb7 100644 --- a/crates/cxx-qt-gen/src/generator/rust/qobject.rs +++ b/crates/cxx-qt-gen/src/generator/rust/qobject.rs @@ -45,6 +45,7 @@ impl GeneratedRustFragment { &qobject.properties, &qobject_idents, cxx_mappings, + module_ident, )?); generated.append(&mut generate_rust_methods( &qobject.methods, @@ -58,6 +59,7 @@ impl GeneratedRustFragment { &qobject.signals, &qobject_idents, cxx_mappings, + module_ident, )?); generated.append(&mut qenum::generate(&qobject.qenums)); diff --git a/crates/cxx-qt-gen/src/generator/rust/signals.rs b/crates/cxx-qt-gen/src/generator/rust/signals.rs index 4270700fd..92f41eaa4 100644 --- a/crates/cxx-qt-gen/src/generator/rust/signals.rs +++ b/crates/cxx-qt-gen/src/generator/rust/signals.rs @@ -6,42 +6,36 @@ use crate::{ generator::{ naming::{ - namespace::namespace_externcxxqt_with_qobject_namespace, qobject::QObjectName, - signals::QSignalName, + qobject::QObjectName, + signals::{QSignalHelperName, QSignalName}, }, rust::fragment::{GeneratedRustFragment, RustFragmentPair}, utils::rust::{syn_ident_cxx_bridge_to_qualified_impl, syn_type_cxx_bridge_to_qualified}, }, parser::{mappings::ParsedCxxMappings, signals::ParsedSignal}, + syntax::attribute::attribute_find_path, }; -use quote::{format_ident, quote}; -use syn::{parse_quote, FnArg, Ident, Result}; +use quote::quote; +use syn::{parse_quote, FnArg, Ident, Result, Type}; -pub fn generate_rust_free_signal( +pub fn generate_rust_signal( signal: &ParsedSignal, + qobject_name: &Ident, cxx_mappings: &ParsedCxxMappings, module_ident: &Ident, ) -> Result { - let qobject_name = &signal.qobject_ident; let idents = QSignalName::from(signal); + let idents_helper = QSignalHelperName::new(&idents, qobject_name, cxx_mappings); + let signal_name_cpp = idents.name.cpp; let signal_name_cpp_str = signal_name_cpp.to_string(); - let free_connect_ident_cpp = - format_ident!("{}_{}", signal.qobject_ident, idents.connect_name.cpp); - let free_connect_ident_rust = - format_ident!("{}_{}", signal.qobject_ident, idents.connect_name.rust); - let free_connect_ident_rust_str = - format_ident!("{}_{}", signal.qobject_ident, idents.connect_name.rust).to_string(); let connect_ident_rust = idents.connect_name.rust; let on_ident_rust = idents.on_name; let original_method = &signal.method; - // Build a namespace that includes any namespace for the T - let connect_namespace = namespace_externcxxqt_with_qobject_namespace( - cxx_mappings - .namespaces - .get(&signal.qobject_ident.to_string()), - ); + let free_connect_ident_cpp = idents_helper.connect_name.cpp; + let free_connect_ident_rust = idents_helper.connect_name.rust; + let free_connect_ident_rust_str = free_connect_ident_rust.to_string(); let parameters_cxx: Vec = signal .parameters @@ -52,7 +46,7 @@ pub fn generate_rust_free_signal( parse_quote! { #ident: #ty } }) .collect(); - let parameters_qualified: Vec = parameters_cxx + let parameters_qualified_arg: Vec = parameters_cxx .iter() .cloned() .map(|mut parameter| { @@ -63,6 +57,21 @@ pub fn generate_rust_free_signal( parameter }) .collect(); + let parameters_name: Vec = signal + .parameters + .iter() + .map(|parameter| parameter.ident.clone()) + .collect(); + let parameters_qualified_type: Vec = parameters_cxx + .iter() + .cloned() + .map(|parameter| match parameter { + FnArg::Typed(pat_type) => { + syn_type_cxx_bridge_to_qualified(&pat_type.ty, &cxx_mappings.qualified) + } + _ => unreachable!("should only have typed no receiver"), + }) + .collect(); let self_type_cxx = if signal.mutable { parse_quote! { Pin<&mut #qobject_name> } @@ -82,6 +91,7 @@ pub fn generate_rust_free_signal( let mut cxx_bridge = vec![]; + // TODO: what happens with RustQt signals, can they be private yet? if !signal.private { cxx_bridge.push(quote! { #unsafe_block extern "C++" { @@ -90,13 +100,35 @@ pub fn generate_rust_free_signal( }); } + let closure_struct = idents_helper.struct_closure; + let signal_handler_alias = idents_helper.handler_alias; + let signal_handler_alias_namespaced_str = idents_helper.handler_alias_namespaced.to_string(); + let signal_handler_call = idents_helper.function_call; + let signal_handler_drop = idents_helper.function_drop; + let namespace_str = idents_helper.namespace.to_string(); + cxx_bridge.push(quote! { unsafe extern "C++" { #[doc(hidden)] - #[namespace = #connect_namespace] + #[namespace = #namespace_str] + type #signal_handler_alias = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = #namespace_str] #[must_use] #[rust_name = #free_connect_ident_rust_str] - fn #free_connect_ident_cpp(self_value: #self_type_cxx, func: #unsafe_call fn(#self_type_cxx, #(#parameters_cxx),*), conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + fn #free_connect_ident_cpp(self_value: #self_type_cxx, signal_handler: #signal_handler_alias, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }); + + cxx_bridge.push(quote! { + #[namespace = #namespace_str] + extern "Rust" { + #[doc(hidden)] + fn #signal_handler_drop(handler: #signal_handler_alias); + + #[doc(hidden)] + #unsafe_call fn #signal_handler_call(handler: &mut #signal_handler_alias, self_value: #self_type_cxx, #(#parameters_cxx),*); } }); @@ -108,12 +140,14 @@ pub fn generate_rust_free_signal( #[doc = "Connect the given function pointer to the signal "] #[doc = #signal_name_cpp_str] #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[doc = "\n"] - #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn #on_ident_rust(self: #self_type_qualified, func: fn(#self_type_qualified, #(#parameters_qualified),*)) -> cxx_qt_lib::QMetaObjectConnection + pub fn #connect_ident_rust(self: #self_type_qualified, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection { - #module_ident::#free_connect_ident_rust(self, func, cxx_qt_lib::ConnectionType::AutoConnection) + #module_ident::#free_connect_ident_rust( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::<#closure_struct>::new(Box::new(closure)), + conn_type, + ) } } }, @@ -122,13 +156,47 @@ pub fn generate_rust_free_signal( #[doc = "Connect the given function pointer to the signal "] #[doc = #signal_name_cpp_str] #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc = "\n"] + #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn #connect_ident_rust(self: #self_type_qualified, func: fn(#self_type_qualified, #(#parameters_qualified),*), conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + pub fn #on_ident_rust(self: #self_type_qualified, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - #module_ident::#free_connect_ident_rust(self, func, conn_type) + #module_ident::#free_connect_ident_rust( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::<#closure_struct>::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, + quote! { + #[doc(hidden)] + pub struct #closure_struct {} + }, + quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for #closure_struct { + type Id = cxx::type_id!(#signal_handler_alias_namespaced_str); + type FnType = dyn FnMut(#self_type_qualified, #(#parameters_qualified_type),*); + } + }, + quote! { + use core::mem::drop as #signal_handler_drop; + }, + quote! { + fn #signal_handler_call( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler<#closure_struct>, + self_value: #self_type_qualified, + #(#parameters_qualified_arg),* + ) { + handler.closure()(self_value, #(#parameters_name),*); + } + }, + quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler<#closure_struct>, usize); + }, + quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler<#closure_struct>, [usize; 2]); + }, ], }; @@ -147,103 +215,37 @@ pub fn generate_rust_signals( signals: &Vec, qobject_idents: &QObjectName, cxx_mappings: &ParsedCxxMappings, + module_ident: &Ident, ) -> Result { let mut generated = GeneratedRustFragment::default(); let qobject_name = &qobject_idents.cpp_class.rust; // Create the methods for the other signals for signal in signals { - let idents = QSignalName::from(signal); - let signal_name_rust = idents.name.rust; - let signal_name_rust_str = signal_name_rust.to_string(); - let signal_name_cpp = idents.name.cpp; - let signal_name_cpp_str = signal_name_cpp.to_string(); - let connect_ident_cpp = idents.connect_name.cpp; - let connect_ident_rust = idents.connect_name.rust; - let connect_ident_rust_str = connect_ident_rust.to_string(); - let on_ident_rust = idents.on_name; - - let parameters_cxx: Vec = signal - .parameters - .iter() - .map(|parameter| { - let ident = ¶meter.ident; - let ty = ¶meter.ty; - parse_quote! { #ident: #ty } - }) - .collect(); - let parameters_qualified: Vec = parameters_cxx - .iter() - .cloned() - .map(|mut parameter| { - if let FnArg::Typed(pat_type) = &mut parameter { - *pat_type.ty = - syn_type_cxx_bridge_to_qualified(&pat_type.ty, &cxx_mappings.qualified); - } - parameter - }) - .collect(); - - let self_type_cxx = if signal.mutable { - parse_quote! { Pin<&mut #qobject_name> } - } else { - parse_quote! { &#qobject_name } - }; - let self_type_qualified = - syn_type_cxx_bridge_to_qualified(&self_type_cxx, &cxx_mappings.qualified); - let qualified_impl = - syn_ident_cxx_bridge_to_qualified_impl(qobject_name, &cxx_mappings.qualified); - - let mut unsafe_block = None; - let mut unsafe_call = Some(quote! { unsafe }); - if signal.safe { - std::mem::swap(&mut unsafe_call, &mut unsafe_block); - } + let signal = { + let mut signal = signal.clone(); - let attrs = &signal.method.attrs; - - let fragment = RustFragmentPair { - cxx_bridge: vec![ - quote! { - #unsafe_block extern "C++" { - #(#attrs)* - #[rust_name = #signal_name_rust_str] - #unsafe_call fn #signal_name_cpp(self: #self_type_cxx, #(#parameters_cxx),*); - } - }, - quote! { - unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = #signal_name_cpp_str] - #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[must_use] - #[rust_name = #connect_ident_rust_str] - fn #connect_ident_cpp(self: #self_type_cxx, func: #unsafe_call fn(#self_type_cxx, #(#parameters_cxx),*), conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; - } - }, - ], - implementation: vec![quote! { - impl #qualified_impl { - #[doc = "Connect the given function pointer to the signal "] - #[doc = #signal_name_cpp_str] - #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[doc = "\n"] - #[doc = "Note that this method uses a AutoConnection connection type."] - #[must_use] - pub fn #on_ident_rust(self: #self_type_qualified, func: fn(#self_type_qualified, #(#parameters_qualified),*)) -> cxx_qt_lib::QMetaObjectConnection - { - self.#connect_ident_rust(func, cxx_qt_lib::ConnectionType::AutoConnection) - } - } - }], + // Inject a cxx_name if there isn't any custom naming as we automatically rename RustQt signals + if attribute_find_path(&signal.method.attrs, &["cxx_name"]).is_none() + && attribute_find_path(&signal.method.attrs, &["rust_name"]).is_none() + { + let idents = QSignalName::from(&signal); + let signal_name_cpp_str = idents.name.cpp.to_string(); + signal + .method + .attrs + .push(parse_quote!(#[cxx_name = #signal_name_cpp_str])); + signal + } else { + signal + } }; - - generated - .cxx_mod_contents - .append(&mut fragment.cxx_bridge_as_items()?); - generated - .cxx_qt_mod_contents - .append(&mut fragment.implementation_as_items()?); + generated.append(&mut generate_rust_signal( + &signal, + qobject_name, + cxx_mappings, + module_ident, + )?); } Ok(generated) @@ -282,18 +284,19 @@ mod tests { &vec![qsignal], &qobject_idents, &ParsedCxxMappings::default(), + &format_ident!("ffi"), ) .unwrap(); - assert_eq!(generated.cxx_mod_contents.len(), 2); - assert_eq!(generated.cxx_qt_mod_contents.len(), 1); + assert_eq!(generated.cxx_mod_contents.len(), 3); + assert_eq!(generated.cxx_qt_mod_contents.len(), 8); assert_tokens_eq( &generated.cxx_mod_contents[0], quote! { unsafe extern "C++" { - #[rust_name = "ready"] - fn ready(self: Pin<&mut MyObject>, ); + #[cxx_name = "ready"] + fn ready(self: Pin<&mut MyObject>); } }, ); @@ -301,17 +304,53 @@ mod tests { &generated.cxx_mod_contents[1], quote! { unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlerready = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + #[must_use] + #[rust_name = "MyObject_connect_ready"] + fn MyObject_readyConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlerready, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }, + ); + assert_tokens_eq( + &generated.cxx_mod_contents[2], + quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_ready(handler: MyObjectCxxQtSignalHandlerready); + + #[doc(hidden)] + fn call_MyObject_signal_handler_ready(handler: &mut MyObjectCxxQtSignalHandlerready, self_value: Pin<&mut MyObject>, ); + } + }, + ); + + assert_tokens_eq( + &generated.cxx_qt_mod_contents[0], + quote! { + impl MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "ready"] #[doc = ", so that when the signal is emitted the function pointer is executed."] #[must_use] - #[rust_name = "connect_ready"] - fn readyConnect(self: Pin<&mut MyObject>, func: fn(Pin<&mut MyObject>, ), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + pub fn connect_ready, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + { + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) + } } }, ); assert_tokens_eq( - &generated.cxx_qt_mod_contents[0], + &generated.cxx_qt_mod_contents[1], quote! { impl MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -320,13 +359,62 @@ mod tests { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_ready(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, )) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_ready, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_ready(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[2], + quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosureready {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[3], + quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureready { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerready"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[4], + quote! { + use core::mem::drop as drop_MyObject_signal_handler_ready; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[5], + quote! { + fn call_MyObject_signal_handler_ready( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + ) { + handler.closure()(self_value, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[6], + quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[7], + quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); } #[test] @@ -362,19 +450,20 @@ mod tests { &vec![qsignal], &qobject_idents, &ParsedCxxMappings::default(), + &format_ident!("ffi"), ) .unwrap(); - assert_eq!(generated.cxx_mod_contents.len(), 2); - assert_eq!(generated.cxx_qt_mod_contents.len(), 1); + assert_eq!(generated.cxx_mod_contents.len(), 3); + assert_eq!(generated.cxx_qt_mod_contents.len(), 8); assert_tokens_eq( &generated.cxx_mod_contents[0], quote! { unsafe extern "C++" { #[attribute] - #[rust_name = "data_changed"] - fn dataChanged(self: Pin<&mut MyObject>, trivial: i32, opaque: UniquePtr); + #[cxx_name = "dataChanged"] + fn data_changed(self: Pin<&mut MyObject>, trivial: i32, opaque: UniquePtr); } }, ); @@ -382,17 +471,53 @@ mod tests { &generated.cxx_mod_contents[1], quote! { unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlerdataChanged = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + #[must_use] + #[rust_name = "MyObject_connect_data_changed"] + fn MyObject_dataChangedConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlerdataChanged, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }, + ); + assert_tokens_eq( + &generated.cxx_mod_contents[2], + quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_dataChanged(handler: MyObjectCxxQtSignalHandlerdataChanged); + + #[doc(hidden)] + fn call_MyObject_signal_handler_dataChanged(handler: &mut MyObjectCxxQtSignalHandlerdataChanged, self_value: Pin<&mut MyObject>, trivial: i32, opaque: UniquePtr); + } + }, + ); + + assert_tokens_eq( + &generated.cxx_qt_mod_contents[0], + quote! { + impl MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "dataChanged"] #[doc = ", so that when the signal is emitted the function pointer is executed."] #[must_use] - #[rust_name = "connect_data_changed"] - fn dataChangedConnect(self: Pin<&mut MyObject>, func: fn(Pin<&mut MyObject>, trivial: i32, opaque: UniquePtr), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + pub fn connect_data_changed, i32, cxx::UniquePtr) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + { + ffi::MyObject_connect_data_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) + } } }, ); assert_tokens_eq( - &generated.cxx_qt_mod_contents[0], + &generated.cxx_qt_mod_contents[1], quote! { impl MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -401,13 +526,64 @@ mod tests { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_data_changed(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, trivial: i32, opaque: cxx::UniquePtr)) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_data_changed, i32, cxx::UniquePtr) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_data_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_data_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[2], + quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosuredataChanged {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[3], + quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosuredataChanged { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerdataChanged"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, i32, cxx::UniquePtr); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[4], + quote! { + use core::mem::drop as drop_MyObject_signal_handler_dataChanged; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[5], + quote! { + fn call_MyObject_signal_handler_dataChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + trivial: i32, + opaque: cxx::UniquePtr + ) { + handler.closure()(self_value, trivial, opaque); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[6], + quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[7], + quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); } #[test] @@ -436,18 +612,19 @@ mod tests { &vec![qsignal], &qobject_idents, &ParsedCxxMappings::default(), + &format_ident!("ffi"), ) .unwrap(); - assert_eq!(generated.cxx_mod_contents.len(), 2); - assert_eq!(generated.cxx_qt_mod_contents.len(), 1); + assert_eq!(generated.cxx_mod_contents.len(), 3); + assert_eq!(generated.cxx_qt_mod_contents.len(), 8); assert_tokens_eq( &generated.cxx_mod_contents[0], quote! { extern "C++" { - #[rust_name = "unsafe_signal"] - unsafe fn unsafeSignal(self: Pin<&mut MyObject>, param: *mut T); + #[cxx_name = "unsafeSignal"] + unsafe fn unsafe_signal(self: Pin<&mut MyObject>, param: *mut T); } }, ); @@ -455,17 +632,53 @@ mod tests { &generated.cxx_mod_contents[1], quote! { unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlerunsafeSignal = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + #[must_use] + #[rust_name = "MyObject_connect_unsafe_signal"] + fn MyObject_unsafeSignalConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlerunsafeSignal, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }, + ); + assert_tokens_eq( + &generated.cxx_mod_contents[2], + quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_unsafeSignal(handler: MyObjectCxxQtSignalHandlerunsafeSignal); + + #[doc(hidden)] + unsafe fn call_MyObject_signal_handler_unsafeSignal(handler: &mut MyObjectCxxQtSignalHandlerunsafeSignal, self_value: Pin<&mut MyObject>, param: *mut T); + } + }, + ); + + assert_tokens_eq( + &generated.cxx_qt_mod_contents[0], + quote! { + impl MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "unsafeSignal"] #[doc = ", so that when the signal is emitted the function pointer is executed."] #[must_use] - #[rust_name = "connect_unsafe_signal"] - fn unsafeSignalConnect(self: Pin <&mut MyObject>, func: unsafe fn(Pin<&mut MyObject>, param: *mut T), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + pub fn connect_unsafe_signal, *mut T) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + { + ffi::MyObject_connect_unsafe_signal( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) + } } }, ); assert_tokens_eq( - &generated.cxx_qt_mod_contents[0], + &generated.cxx_qt_mod_contents[1], quote! { impl MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -474,13 +687,63 @@ mod tests { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_unsafe_signal(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, param: *mut T)) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_unsafe_signal, *mut T) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_unsafe_signal(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_unsafe_signal( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[2], + quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosureunsafeSignal {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[3], + quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureunsafeSignal { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerunsafeSignal"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, *mut T); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[4], + quote! { + use core::mem::drop as drop_MyObject_signal_handler_unsafeSignal; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[5], + quote! { + fn call_MyObject_signal_handler_unsafeSignal( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + param: *mut T + ) { + handler.closure()(self_value, param); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[6], + quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[7], + quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); } #[test] @@ -507,19 +770,20 @@ mod tests { &vec![qsignal], &qobject_idents, &ParsedCxxMappings::default(), + &format_ident!("ffi"), ) .unwrap(); - assert_eq!(generated.cxx_mod_contents.len(), 2); - assert_eq!(generated.cxx_qt_mod_contents.len(), 1); + assert_eq!(generated.cxx_mod_contents.len(), 3); + assert_eq!(generated.cxx_qt_mod_contents.len(), 8); assert_tokens_eq( &generated.cxx_mod_contents[0], quote! { unsafe extern "C++" { #[inherit] - #[rust_name = "existing_signal"] - fn baseName(self: Pin<&mut MyObject>, ); + #[cxx_name = "baseName"] + fn existing_signal(self: Pin<&mut MyObject>, ); } }, ); @@ -527,17 +791,53 @@ mod tests { &generated.cxx_mod_contents[1], quote! { unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlerbaseName = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + #[must_use] + #[rust_name = "MyObject_connect_existing_signal"] + fn MyObject_baseNameConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlerbaseName, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + } + }, + ); + assert_tokens_eq( + &generated.cxx_mod_contents[2], + quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_baseName(handler: MyObjectCxxQtSignalHandlerbaseName); + + #[doc(hidden)] + fn call_MyObject_signal_handler_baseName(handler: &mut MyObjectCxxQtSignalHandlerbaseName, self_value: Pin<&mut MyObject>, ); + } + }, + ); + + assert_tokens_eq( + &generated.cxx_qt_mod_contents[0], + quote! { + impl MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "baseName"] #[doc = ", so that when the signal is emitted the function pointer is executed."] #[must_use] - #[rust_name = "connect_existing_signal"] - fn baseNameConnect(self: Pin<& mut MyObject>, func: fn(Pin<&mut MyObject>, ), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + pub fn connect_existing_signal, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + { + ffi::MyObject_connect_existing_signal( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) + } } }, ); assert_tokens_eq( - &generated.cxx_qt_mod_contents[0], + &generated.cxx_qt_mod_contents[1], quote! { impl MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -546,13 +846,62 @@ mod tests { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_existing_signal(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, )) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_existing_signal, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_existing_signal(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_existing_signal( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[2], + quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosurebaseName {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[3], + quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosurebaseName { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerbaseName"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[4], + quote! { + use core::mem::drop as drop_MyObject_signal_handler_baseName; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[5], + quote! { + fn call_MyObject_signal_handler_baseName( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + ) { + handler.closure()(self_value, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[6], + quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[7], + quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); } #[test] @@ -573,15 +922,16 @@ mod tests { private: false, }; - let generated = generate_rust_free_signal( + let generated = generate_rust_signal( &qsignal, + &qsignal.qobject_ident, &ParsedCxxMappings::default(), &format_ident!("ffi"), ) .unwrap(); - assert_eq!(generated.cxx_mod_contents.len(), 2); - assert_eq!(generated.cxx_qt_mod_contents.len(), 2); + assert_eq!(generated.cxx_mod_contents.len(), 3); + assert_eq!(generated.cxx_qt_mod_contents.len(), 8); assert_tokens_eq( &generated.cxx_mod_contents[0], @@ -595,14 +945,32 @@ mod tests { &generated.cxx_mod_contents[1], quote! { unsafe extern "C++" { - #[doc (hidden)] - #[namespace = "rust::cxxqtgen1::externcxxqt"] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlerready = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] #[must_use] #[rust_name = "MyObject_connect_ready"] - fn MyObject_readyConnect(self_value: Pin<&mut MyObject>, func: fn(Pin<&mut MyObject>, ), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + fn MyObject_readyConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlerready, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; } }, ); + assert_tokens_eq( + &generated.cxx_mod_contents[2], + quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_ready(handler: MyObjectCxxQtSignalHandlerready); + + #[doc(hidden)] + fn call_MyObject_signal_handler_ready(handler: &mut MyObjectCxxQtSignalHandlerready, self_value: Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( &generated.cxx_qt_mod_contents[0], quote! { @@ -610,12 +978,14 @@ mod tests { #[doc = "Connect the given function pointer to the signal "] #[doc = "ready"] #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[doc = "\n"] - #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_ready(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, )) -> cxx_qt_lib::QMetaObjectConnection + pub fn connect_ready, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection { - ffi::MyObject_connect_ready(self, func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) } } }, @@ -627,14 +997,65 @@ mod tests { #[doc = "Connect the given function pointer to the signal "] #[doc = "ready"] #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc = "\n"] + #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn connect_ready(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, ), conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_ready, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - ffi::MyObject_connect_ready(self, func, conn_type) + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[2], + quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosureready {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[3], + quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureready { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerready"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[4], + quote! { + use core::mem::drop as drop_MyObject_signal_handler_ready; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[5], + quote! { + fn call_MyObject_signal_handler_ready( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + ) { + handler.closure()(self_value, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[6], + quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[7], + quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); } #[test] @@ -655,28 +1076,47 @@ mod tests { private: true, }; - let generated = generate_rust_free_signal( + let generated = generate_rust_signal( &qsignal, + &qsignal.qobject_ident, &ParsedCxxMappings::default(), &format_ident!("ffi"), ) .unwrap(); - assert_eq!(generated.cxx_mod_contents.len(), 1); - assert_eq!(generated.cxx_qt_mod_contents.len(), 2); + assert_eq!(generated.cxx_mod_contents.len(), 2); + assert_eq!(generated.cxx_qt_mod_contents.len(), 8); assert_tokens_eq( &generated.cxx_mod_contents[0], quote! { unsafe extern "C++" { - #[doc (hidden)] - #[namespace = "rust::cxxqtgen1::externcxxqt"] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] + type MyObjectCxxQtSignalHandlerready = cxx_qt::signalhandler::CxxQtSignalHandler; + + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] #[must_use] #[rust_name = "MyObject_connect_ready"] - fn MyObject_readyConnect(self_value: Pin<&mut MyObject>, func: fn(Pin<&mut MyObject>, ), conn_type : CxxQtConnectionType) -> CxxQtQMetaObjectConnection; + fn MyObject_readyConnect(self_value: Pin<&mut MyObject>, signal_handler: MyObjectCxxQtSignalHandlerready, conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection; } }, ); + assert_tokens_eq( + &generated.cxx_mod_contents[1], + quote! { + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_ready(handler: MyObjectCxxQtSignalHandlerready); + + #[doc(hidden)] + fn call_MyObject_signal_handler_ready(handler: &mut MyObjectCxxQtSignalHandlerready, self_value: Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( &generated.cxx_qt_mod_contents[0], quote! { @@ -684,12 +1124,14 @@ mod tests { #[doc = "Connect the given function pointer to the signal "] #[doc = "ready"] #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[doc = "\n"] - #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_ready(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, )) -> cxx_qt_lib::QMetaObjectConnection + pub fn connect_ready, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F, conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection { - ffi::MyObject_connect_ready(self, func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + conn_type, + ) } } }, @@ -701,13 +1143,64 @@ mod tests { #[doc = "Connect the given function pointer to the signal "] #[doc = "ready"] #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc = "\n"] + #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn connect_ready(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, ), conn_type: cxx_qt_lib::ConnectionType) -> cxx_qt_lib::QMetaObjectConnection + pub fn on_ready, ) + 'static>(self: core::pin::Pin<&mut MyObject>, mut closure: F) -> cxx_qt_lib::QMetaObjectConnection { - ffi::MyObject_connect_ready(self, func, conn_type) + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } }, ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[2], + quote! { + #[doc(hidden)] + pub struct MyObjectCxxQtSignalClosureready {} + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[3], + quote! { + impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureready { + type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerready"); + type FnType = dyn FnMut(core::pin::Pin<&mut MyObject>, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[4], + quote! { + use core::mem::drop as drop_MyObject_signal_handler_ready; + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[5], + quote! { + fn call_MyObject_signal_handler_ready( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut MyObject>, + ) { + handler.closure()(self_value, ); + } + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[6], + quote! { + cxx_qt::static_assertions::assert_eq_align!(cxx_qt::signalhandler::CxxQtSignalHandler, usize); + }, + ); + assert_tokens_eq( + &generated.cxx_qt_mod_contents[7], + quote! { + cxx_qt::static_assertions::assert_eq_size!(cxx_qt::signalhandler::CxxQtSignalHandler, [usize; 2]); + }, + ); } } diff --git a/crates/cxx-qt-gen/src/writer/cpp/header.rs b/crates/cxx-qt-gen/src/writer/cpp/header.rs index 800e4eaae..a491913ef 100644 --- a/crates/cxx-qt-gen/src/writer/cpp/header.rs +++ b/crates/cxx-qt-gen/src/writer/cpp/header.rs @@ -47,7 +47,7 @@ fn forward_declare(generated: &GeneratedCppBlocks) -> Vec { .qobjects .iter() .map(|qobject| { - namespaced( + let forward_declares = namespaced( &qobject.namespace, &formatdoc! {r#" class {ident}; @@ -56,9 +56,20 @@ fn forward_declare(generated: &GeneratedCppBlocks) -> Vec { ident = &qobject.ident, forward_declares = qobject.blocks.forward_declares.join("\n"), }, - ) + ); + let forward_declares_namespaced = qobject.blocks.forward_declares_namespaced.join("\n"); + formatdoc! {r#" + {forward_declares} + {forward_declares_namespaced} + "#} }) .chain(generated.forward_declares.iter().cloned()) + .chain( + generated + .extern_cxx_qt + .iter() + .map(|external| external.forward_declares.join("\n")), + ) .collect::>() } @@ -88,7 +99,16 @@ fn qobjects_header(generated: &GeneratedCppBlocks) -> Vec { private_methods = create_block("private", &qobject.blocks.private_methods.iter().filter_map(pair_as_header).collect::>()), }); + let fragments = qobject + .blocks + .fragments + .iter() + .filter_map(pair_as_header) + .collect::>() + .join("\n"); + formatdoc! {r#" + {fragments} {class_definition} Q_DECLARE_METATYPE({metatype}*) @@ -131,8 +151,12 @@ pub fn write_cpp_header(generated: &GeneratedCppBlocks) -> String { let extern_cxx_qt = generated .extern_cxx_qt .iter() - .filter_map(|block| { - pair_as_header(&block.method).map(|method| namespaced(&block.namespace, &method)) + .flat_map(|block| { + block + .fragments + .iter() + .filter_map(pair_as_header) + .collect::>() }) .collect::>() .join("\n"); diff --git a/crates/cxx-qt-gen/src/writer/cpp/mod.rs b/crates/cxx-qt-gen/src/writer/cpp/mod.rs index 8119c9bb7..265f84e4c 100644 --- a/crates/cxx-qt-gen/src/writer/cpp/mod.rs +++ b/crates/cxx-qt-gen/src/writer/cpp/mod.rs @@ -63,7 +63,6 @@ mod tests { namespace: "cxx_qt::my_object".to_owned(), namespace_internals: "cxx_qt::my_object::cxx_qt_my_object".to_owned(), blocks: GeneratedCppQObjectBlocks { - forward_declares: vec![], base_classes: vec!["QStringListModel".to_owned()], includes: { let mut includes = BTreeSet::::default(); @@ -165,7 +164,8 @@ mod tests { // non-const private method } "#}.to_owned(), - }] + }], + ..Default::default() } } ], @@ -186,7 +186,6 @@ mod tests { namespace: "cxx_qt".to_owned(), namespace_internals: "cxx_qt::cxx_qt_first_object".to_owned(), blocks: GeneratedCppQObjectBlocks { - forward_declares: vec![], base_classes: vec!["QStringListModel".to_owned()], includes: { let mut includes = BTreeSet::::default(); @@ -221,7 +220,7 @@ mod tests { }, CppFragment::Header("Q_SIGNAL void countChanged();".to_owned()), ], - private_methods: vec![], + ..Default::default() } }, GeneratedCppQObject { @@ -230,7 +229,6 @@ mod tests { namespace: "cxx_qt".to_owned(), namespace_internals: "cxx_qt::cxx_qt_second_object".to_owned(), blocks: GeneratedCppQObjectBlocks { - forward_declares: vec![], base_classes: vec!["QStringListModel".to_owned()], includes: { let mut includes = BTreeSet::::default(); @@ -273,7 +271,8 @@ mod tests { // private method } "#}.to_owned(), - }] + }], + ..Default::default() }, } ] @@ -301,9 +300,12 @@ mod tests { } // namespace cxx_qt::my_object + + #include "cxx-qt-gen/cxx_file_stem.cxx.h" + namespace cxx_qt::my_object { class MyObject : public QStringListModel { @@ -352,15 +354,20 @@ mod tests { } // namespace cxx_qt + + namespace cxx_qt { class SecondObject; } // namespace cxx_qt + + #include "cxx-qt-gen/cxx_file_stem.cxx.h" + namespace cxx_qt { class FirstObject : public QStringListModel { @@ -384,6 +391,7 @@ mod tests { Q_DECLARE_METATYPE(cxx_qt::FirstObject*) + namespace cxx_qt { class SecondObject : public QStringListModel { @@ -422,9 +430,12 @@ mod tests { class MyObject; + + #include "cxx-qt-gen/cxx_file_stem.cxx.h" + class MyObject : public QStringListModel { Q_OBJECT diff --git a/crates/cxx-qt-gen/src/writer/cpp/source.rs b/crates/cxx-qt-gen/src/writer/cpp/source.rs index 4e8f157cb..304263784 100644 --- a/crates/cxx-qt-gen/src/writer/cpp/source.rs +++ b/crates/cxx-qt-gen/src/writer/cpp/source.rs @@ -30,13 +30,35 @@ fn qobjects_source(generated: &GeneratedCppBlocks) -> Vec { .filter_map(pair_as_source) .collect::>() .join("\n"); - namespaced(&qobject.namespace, &methods) + let namespaced = namespaced(&qobject.namespace, &methods); + + qobject + .blocks + .fragments + .iter() + .filter_map(pair_as_source) + .chain([namespaced]) + .collect::>() + .join("\n") }) .collect::>() } /// For a given GeneratedCppBlocks write this into a C++ source pub fn write_cpp_source(generated: &GeneratedCppBlocks) -> String { + let extern_cxx_qt = generated + .extern_cxx_qt + .iter() + .flat_map(|block| { + block + .fragments + .iter() + .filter_map(pair_as_source) + .collect::>() + }) + .collect::>() + .join("\n"); + formatdoc! {r#" #include "cxx-qt-gen/{cxx_file_stem}.cxxqt.h" @@ -44,15 +66,6 @@ pub fn write_cpp_source(generated: &GeneratedCppBlocks) -> String { {qobjects} "#, cxx_file_stem = generated.cxx_file_stem, - extern_cxx_qt = { - let mut out = vec![]; - for block in &generated.extern_cxx_qt { - if let Some(method) = pair_as_source(&block.method) { - out.push(namespaced(&block.namespace, &method)); - } - } - out.join("\n") - }, qobjects = qobjects_source(generated).join("\n"), } } diff --git a/crates/cxx-qt-gen/test_inputs/signals.rs b/crates/cxx-qt-gen/test_inputs/signals.rs index ca53aecc4..e045121dc 100644 --- a/crates/cxx-qt-gen/test_inputs/signals.rs +++ b/crates/cxx-qt-gen/test_inputs/signals.rs @@ -6,6 +6,16 @@ mod ffi { type QPoint = cxx_qt_lib::QPoint; } + unsafe extern "C++Qt" { + include!(); + /// QTimer + type QTimer; + + /// When the QTimer timeout occurs + #[qsignal] + pub(self) fn timeout(self: Pin<&mut QTimer>); + } + unsafe extern "RustQt" { #[qobject] type MyObject = super::MyObjectRust; @@ -19,7 +29,7 @@ mod ffi { first: i32, second: UniquePtr, third: QPoint, - fourth: &'a QPoint, + fourth: &QPoint, ); #[cxx_name = "newData"] diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp index 59dae9f9c..1448d39e4 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp @@ -1,117 +1,311 @@ #include "cxx-qt-gen/multi_object.cxxqt.h" -namespace rust::cxxqtgen1::externcxxqt { +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler< + ::rust::cxxqtgen1::QPushButtonCxxQtSignalParamsclicked*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_QPushButton_signal_handler_clicked(::std::move(*this)); +} + +template<> +template<> +void +SignalHandler<::rust::cxxqtgen1::QPushButtonCxxQtSignalParamsclicked*>:: +operator()(QPushButton& self, bool checked) +{ + call_QPushButton_signal_handler_clicked(*this, self, ::std::move(checked)); +} + +static_assert( + alignof( + SignalHandler<::rust::cxxqtgen1::QPushButtonCxxQtSignalParamsclicked*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof( + SignalHandler<::rust::cxxqtgen1::QPushButtonCxxQtSignalParamsclicked*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1 { ::QMetaObject::Connection -QPushButton_clickedConnect(QPushButton& self, - ::rust::Fn func, - ::Qt::ConnectionType type) +QPushButton_clickedConnect( + QPushButton& self, + ::rust::cxxqtgen1::QPushButtonCxxQtSignalHandlerclicked closure, + ::Qt::ConnectionType type) { return ::QObject::connect( &self, &QPushButton::clicked, &self, - [&, func = ::std::move(func)](bool checked) { + [&, closure = ::std::move(closure)](bool checked) mutable { const ::rust::cxxqtlib1::MaybeLockGuard guard(self); - func(self, ::std::move(checked)); + closure.template operator()(self, + ::std::move(checked)); }, type); } +} // namespace rust::cxxqtgen1 + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::mynamespace:: + ExternObjectCxxQtSignalParamsdataReady*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } -} // namespace rust::cxxqtgen1::externcxxqt + drop_ExternObject_signal_handler_dataReady(::std::move(*this)); +} -namespace rust::cxxqtgen1::externcxxqt::mynamespace { +template<> +template<> +void +SignalHandler< + ::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalParamsdataReady*>:: +operator()<::mynamespace::ExternObjectCpp&>( + ::mynamespace::ExternObjectCpp& self) +{ + call_ExternObject_signal_handler_dataReady(*this, self); +} + +static_assert( + alignof(SignalHandler<::rust::cxxqtgen1::mynamespace:: + ExternObjectCxxQtSignalParamsdataReady*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof(SignalHandler<::rust::cxxqtgen1::mynamespace:: + ExternObjectCxxQtSignalParamsdataReady*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::mynamespace { ::QMetaObject::Connection ExternObject_dataReadyConnect( ::mynamespace::ExternObjectCpp& self, - ::rust::Fn func, + ::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalHandlerdataReady + closure, ::Qt::ConnectionType type) { return ::QObject::connect( &self, &::mynamespace::ExternObjectCpp::dataReady, &self, - [&, func = ::std::move(func)]() { + [&, closure = ::std::move(closure)]() mutable { const ::rust::cxxqtlib1::MaybeLockGuard<::mynamespace::ExternObjectCpp> guard(self); - func(self); + closure.template operator()<::mynamespace::ExternObjectCpp&>(self); }, type); } +} // namespace rust::cxxqtgen1::mynamespace + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::mynamespace:: + ExternObjectCxxQtSignalParamserrorOccurred*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } -} // namespace rust::cxxqtgen1::externcxxqt::mynamespace + drop_ExternObject_signal_handler_errorOccurred(::std::move(*this)); +} -namespace rust::cxxqtgen1::externcxxqt::mynamespace { +template<> +template<> +void +SignalHandler< + ::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalParamserrorOccurred*>:: +operator()<::mynamespace::ExternObjectCpp&>( + ::mynamespace::ExternObjectCpp& self) +{ + call_ExternObject_signal_handler_errorOccurred(*this, self); +} + +static_assert( + alignof(SignalHandler<::rust::cxxqtgen1::mynamespace:: + ExternObjectCxxQtSignalParamserrorOccurred*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof(SignalHandler<::rust::cxxqtgen1::mynamespace:: + ExternObjectCxxQtSignalParamserrorOccurred*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::mynamespace { ::QMetaObject::Connection ExternObject_errorOccurredConnect( ::mynamespace::ExternObjectCpp& self, - ::rust::Fn func, + ::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalHandlererrorOccurred + closure, ::Qt::ConnectionType type) { return ::QObject::connect( &self, &::mynamespace::ExternObjectCpp::errorOccurred, &self, - [&, func = ::std::move(func)]() { + [&, closure = ::std::move(closure)]() mutable { const ::rust::cxxqtlib1::MaybeLockGuard<::mynamespace::ExternObjectCpp> guard(self); - func(self); + closure.template operator()<::mynamespace::ExternObjectCpp&>(self); }, type); } +} // namespace rust::cxxqtgen1::mynamespace -} // namespace rust::cxxqtgen1::externcxxqt::mynamespace - -namespace cxx_qt::multi_object { -::std::int32_t const& -MyObject::getPropertyName() const +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalParamspropertyNameChanged*>::~SignalHandler() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - return getPropertyNameWrapper(); + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_MyObject_signal_handler_propertyNameChanged(::std::move(*this)); } +template<> +template<> void -MyObject::setPropertyName(::std::int32_t const& value) +SignalHandler<::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalParamspropertyNameChanged*>:: +operator()<::cxx_qt::multi_object::MyObject&>( + ::cxx_qt::multi_object::MyObject& self) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - setPropertyNameWrapper(value); + call_MyObject_signal_handler_propertyNameChanged(*this, self); } +static_assert( + alignof(SignalHandler<::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalParamspropertyNameChanged*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof(SignalHandler<::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalParamspropertyNameChanged*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::multi_object { ::QMetaObject::Connection -MyObject::propertyNameChangedConnect(::rust::Fn func, - ::Qt::ConnectionType type) +MyObject_propertyNameChangedConnect( + ::cxx_qt::multi_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalHandlerpropertyNameChanged closure, + ::Qt::ConnectionType type) { return ::QObject::connect( - this, - &MyObject::propertyNameChanged, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + &::cxx_qt::multi_object::MyObject::propertyNameChanged, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::multi_object::MyObject> + guard(self); + closure.template operator()<::cxx_qt::multi_object::MyObject&>(self); }, type); } +} // namespace rust::cxxqtgen1::cxx_qt::multi_object + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalParamsready*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_MyObject_signal_handler_ready(::std::move(*this)); +} +template<> +template<> void -MyObject::invokableName() +SignalHandler< + ::rust::cxxqtgen1::cxx_qt::multi_object::MyObjectCxxQtSignalParamsready*>:: +operator()<::cxx_qt::multi_object::MyObject&>( + ::cxx_qt::multi_object::MyObject& self) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - invokableNameWrapper(); + call_MyObject_signal_handler_ready(*this, self); } +static_assert(alignof(SignalHandler<::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalParamsready*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalParamsready*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::multi_object { ::QMetaObject::Connection -MyObject::readyConnect(::rust::Fn func, - ::Qt::ConnectionType type) +MyObject_readyConnect( + ::cxx_qt::multi_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::multi_object::MyObjectCxxQtSignalHandlerready + closure, + ::Qt::ConnectionType type) { return ::QObject::connect( - this, - &MyObject::ready, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + &::cxx_qt::multi_object::MyObject::ready, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::multi_object::MyObject> + guard(self); + closure.template operator()<::cxx_qt::multi_object::MyObject&>(self); }, type); } +} // namespace rust::cxxqtgen1::cxx_qt::multi_object + +namespace cxx_qt::multi_object { +::std::int32_t const& +MyObject::getPropertyName() const +{ + const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); + return getPropertyNameWrapper(); +} + +void +MyObject::setPropertyName(::std::int32_t const& value) +{ + const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); + setPropertyNameWrapper(value); +} + +void +MyObject::invokableName() +{ + const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); + invokableNameWrapper(); +} MyObject::MyObject(QObject* parent) : QStringListModel(parent) @@ -123,57 +317,143 @@ MyObject::MyObject(QObject* parent) } // namespace cxx_qt::multi_object -namespace second_object { -::std::int32_t const& -SecondObject::getPropertyName() const +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler< + ::rust::cxxqtgen1::second_object:: + SecondObjectCxxQtSignalParamspropertyNameChanged*>::~SignalHandler() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - return getPropertyNameWrapper(); + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_SecondObject_signal_handler_propertyNameChanged(::std::move(*this)); } +template<> +template<> void -SecondObject::setPropertyName(::std::int32_t const& value) +SignalHandler<::rust::cxxqtgen1::second_object:: + SecondObjectCxxQtSignalParamspropertyNameChanged*>:: +operator()<::second_object::SecondObject&>(::second_object::SecondObject& self) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - setPropertyNameWrapper(value); + call_SecondObject_signal_handler_propertyNameChanged(*this, self); } +static_assert( + alignof(SignalHandler<::rust::cxxqtgen1::second_object:: + SecondObjectCxxQtSignalParamspropertyNameChanged*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof(SignalHandler<::rust::cxxqtgen1::second_object:: + SecondObjectCxxQtSignalParamspropertyNameChanged*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::second_object { ::QMetaObject::Connection -SecondObject::propertyNameChangedConnect(::rust::Fn func, - ::Qt::ConnectionType type) +SecondObject_propertyNameChangedConnect( + ::second_object::SecondObject& self, + ::rust::cxxqtgen1::second_object:: + SecondObjectCxxQtSignalHandlerpropertyNameChanged closure, + ::Qt::ConnectionType type) { return ::QObject::connect( - this, - &SecondObject::propertyNameChanged, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + &::second_object::SecondObject::propertyNameChanged, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::second_object::SecondObject> + guard(self); + closure.template operator()<::second_object::SecondObject&>(self); }, type); } +} // namespace rust::cxxqtgen1::second_object + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::second_object:: + SecondObjectCxxQtSignalParamsready*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_SecondObject_signal_handler_ready(::std::move(*this)); +} +template<> +template<> void -SecondObject::invokableName() +SignalHandler< + ::rust::cxxqtgen1::second_object::SecondObjectCxxQtSignalParamsready*>:: +operator()<::second_object::SecondObject&>(::second_object::SecondObject& self) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - invokableNameWrapper(); + call_SecondObject_signal_handler_ready(*this, self); } +static_assert( + alignof( + SignalHandler< + ::rust::cxxqtgen1::second_object::SecondObjectCxxQtSignalParamsready*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof( + SignalHandler< + ::rust::cxxqtgen1::second_object::SecondObjectCxxQtSignalParamsready*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::second_object { ::QMetaObject::Connection -SecondObject::readyConnect(::rust::Fn func, - ::Qt::ConnectionType type) +SecondObject_readyConnect( + ::second_object::SecondObject& self, + ::rust::cxxqtgen1::second_object::SecondObjectCxxQtSignalHandlerready closure, + ::Qt::ConnectionType type) { return ::QObject::connect( - this, - &SecondObject::ready, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + &::second_object::SecondObject::ready, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::second_object::SecondObject> + guard(self); + closure.template operator()<::second_object::SecondObject&>(self); }, type); } +} // namespace rust::cxxqtgen1::second_object + +namespace second_object { +::std::int32_t const& +SecondObject::getPropertyName() const +{ + const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); + return getPropertyNameWrapper(); +} + +void +SecondObject::setPropertyName(::std::int32_t const& value) +{ + const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); + setPropertyNameWrapper(value); +} + +void +SecondObject::invokableName() +{ + const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); + invokableNameWrapper(); +} SecondObject::SecondObject(QObject* parent) : QObject(parent) diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h index 941c886b1..44b6e4057 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h @@ -10,38 +10,95 @@ class MyObject; } // namespace cxx_qt::multi_object +namespace rust::cxxqtgen1::cxx_qt::multi_object { +using MyObjectCxxQtSignalHandlerpropertyNameChanged = + ::rust::cxxqtlib1::SignalHandler< + struct MyObjectCxxQtSignalParamspropertyNameChanged*>; +} // namespace rust::cxxqtgen1::cxx_qt::multi_object + +namespace rust::cxxqtgen1::cxx_qt::multi_object { +using MyObjectCxxQtSignalHandlerready = + ::rust::cxxqtlib1::SignalHandler; +} // namespace rust::cxxqtgen1::cxx_qt::multi_object + namespace second_object { class SecondObject; } // namespace second_object +namespace rust::cxxqtgen1::second_object { +using SecondObjectCxxQtSignalHandlerpropertyNameChanged = + ::rust::cxxqtlib1::SignalHandler< + struct SecondObjectCxxQtSignalParamspropertyNameChanged*>; +} // namespace rust::cxxqtgen1::second_object + +namespace rust::cxxqtgen1::second_object { +using SecondObjectCxxQtSignalHandlerready = + ::rust::cxxqtlib1::SignalHandler; +} // namespace rust::cxxqtgen1::second_object + +namespace rust::cxxqtgen1 { +using QPushButtonCxxQtSignalHandlerclicked = + ::rust::cxxqtlib1::SignalHandler; +} // namespace rust::cxxqtgen1 + +namespace rust::cxxqtgen1::mynamespace { +using ExternObjectCxxQtSignalHandlerdataReady = + ::rust::cxxqtlib1::SignalHandler< + struct ExternObjectCxxQtSignalParamsdataReady*>; +} // namespace rust::cxxqtgen1::mynamespace + +namespace rust::cxxqtgen1::mynamespace { +using ExternObjectCxxQtSignalHandlererrorOccurred = + ::rust::cxxqtlib1::SignalHandler< + struct ExternObjectCxxQtSignalParamserrorOccurred*>; +} // namespace rust::cxxqtgen1::mynamespace + #include "cxx-qt-gen/multi_object.cxx.h" -namespace rust::cxxqtgen1::externcxxqt { +namespace rust::cxxqtgen1 { ::QMetaObject::Connection -QPushButton_clickedConnect(QPushButton& self, - ::rust::Fn func, - ::Qt::ConnectionType type); - -} // namespace rust::cxxqtgen1::externcxxqt +QPushButton_clickedConnect( + QPushButton& self, + ::rust::cxxqtgen1::QPushButtonCxxQtSignalHandlerclicked closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1 -namespace rust::cxxqtgen1::externcxxqt::mynamespace { +namespace rust::cxxqtgen1::mynamespace { ::QMetaObject::Connection ExternObject_dataReadyConnect( ::mynamespace::ExternObjectCpp& self, - ::rust::Fn func, + ::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalHandlerdataReady + closure, ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::mynamespace -} // namespace rust::cxxqtgen1::externcxxqt::mynamespace - -namespace rust::cxxqtgen1::externcxxqt::mynamespace { +namespace rust::cxxqtgen1::mynamespace { ::QMetaObject::Connection ExternObject_errorOccurredConnect( ::mynamespace::ExternObjectCpp& self, - ::rust::Fn func, + ::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalHandlererrorOccurred + closure, ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::mynamespace -} // namespace rust::cxxqtgen1::externcxxqt::mynamespace +namespace rust::cxxqtgen1::cxx_qt::multi_object { +::QMetaObject::Connection +MyObject_propertyNameChangedConnect( + ::cxx_qt::multi_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::multi_object:: + MyObjectCxxQtSignalHandlerpropertyNameChanged closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::multi_object + +namespace rust::cxxqtgen1::cxx_qt::multi_object { +::QMetaObject::Connection +MyObject_readyConnect( + ::cxx_qt::multi_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::multi_object::MyObjectCxxQtSignalHandlerready + closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::multi_object namespace cxx_qt::multi_object { class MyObject @@ -60,13 +117,8 @@ class MyObject ::std::int32_t const& getPropertyName() const; Q_SLOT void setPropertyName(::std::int32_t const& value); Q_SIGNAL void propertyNameChanged(); - ::QMetaObject::Connection propertyNameChangedConnect( - ::rust::Fn func, - ::Qt::ConnectionType type); Q_INVOKABLE void invokableName(); Q_SIGNAL void ready(); - ::QMetaObject::Connection readyConnect(::rust::Fn func, - ::Qt::ConnectionType type); explicit MyObject(QObject* parent = nullptr); private: @@ -81,6 +133,23 @@ static_assert(::std::is_base_of::value, Q_DECLARE_METATYPE(cxx_qt::multi_object::MyObject*) +namespace rust::cxxqtgen1::second_object { +::QMetaObject::Connection +SecondObject_propertyNameChangedConnect( + ::second_object::SecondObject& self, + ::rust::cxxqtgen1::second_object:: + SecondObjectCxxQtSignalHandlerpropertyNameChanged closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::second_object + +namespace rust::cxxqtgen1::second_object { +::QMetaObject::Connection +SecondObject_readyConnect( + ::second_object::SecondObject& self, + ::rust::cxxqtgen1::second_object::SecondObjectCxxQtSignalHandlerready closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::second_object + namespace second_object { class SecondObject : public QObject @@ -97,13 +166,8 @@ class SecondObject ::std::int32_t const& getPropertyName() const; Q_SLOT void setPropertyName(::std::int32_t const& value); Q_SIGNAL void propertyNameChanged(); - ::QMetaObject::Connection propertyNameChangedConnect( - ::rust::Fn func, - ::Qt::ConnectionType type); Q_INVOKABLE void invokableName(); Q_SIGNAL void ready(); - ::QMetaObject::Connection readyConnect(::rust::Fn func, - ::Qt::ConnectionType type); explicit SecondObject(QObject* parent = nullptr); private: diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs index a8416418e..5cdbc7d7b 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs @@ -84,42 +84,72 @@ pub mod ffi { } unsafe extern "C++" { #[doc = "Notify for the Q_PROPERTY"] - #[rust_name = "property_name_changed"] - fn propertyNameChanged(self: Pin<&mut MyObject>); + #[cxx_name = "propertyNameChanged"] + fn property_name_changed(self: Pin<&mut MyObject>); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "propertyNameChanged"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::multi_object"] + type MyObjectCxxQtSignalHandlerpropertyNameChanged = + cxx_qt::signalhandler::CxxQtSignalHandler< + super::MyObjectCxxQtSignalClosurepropertyNameChanged, + >; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::multi_object"] #[must_use] - #[rust_name = "connect_property_name_changed"] - fn propertyNameChangedConnect( - self: Pin<&mut MyObject>, - func: fn(Pin<&mut MyObject>), + #[rust_name = "MyObject_connect_property_name_changed"] + fn MyObject_propertyNameChangedConnect( + self_value: Pin<&mut MyObject>, + signal_handler: MyObjectCxxQtSignalHandlerpropertyNameChanged, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::cxx_qt::multi_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_propertyNameChanged( + handler: MyObjectCxxQtSignalHandlerpropertyNameChanged, + ); + #[doc(hidden)] + fn call_MyObject_signal_handler_propertyNameChanged( + handler: &mut MyObjectCxxQtSignalHandlerpropertyNameChanged, + self_value: Pin<&mut MyObject>, + ); + } extern "Rust" { #[doc(hidden)] #[cxx_name = "invokableNameWrapper"] fn invokable_name(self: Pin<&mut MyObject>); } unsafe extern "C++" { - #[rust_name = "ready"] + #[cxx_name = "ready"] fn ready(self: Pin<&mut MyObject>); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "ready"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::multi_object"] + type MyObjectCxxQtSignalHandlerready = + cxx_qt::signalhandler::CxxQtSignalHandler; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::multi_object"] #[must_use] - #[rust_name = "connect_ready"] - fn readyConnect( - self: Pin<&mut MyObject>, - func: fn(Pin<&mut MyObject>), + #[rust_name = "MyObject_connect_ready"] + fn MyObject_readyConnect( + self_value: Pin<&mut MyObject>, + signal_handler: MyObjectCxxQtSignalHandlerready, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::cxx_qt::multi_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_ready(handler: MyObjectCxxQtSignalHandlerready); + #[doc(hidden)] + fn call_MyObject_signal_handler_ready( + handler: &mut MyObjectCxxQtSignalHandlerready, + self_value: Pin<&mut MyObject>, + ); + } extern "Rust" { #[cxx_name = "createRs"] #[namespace = "cxx_qt::multi_object::cxx_qt_my_object"] @@ -158,21 +188,38 @@ pub mod ffi { } unsafe extern "C++" { #[doc = "Notify for the Q_PROPERTY"] - #[rust_name = "property_name_changed"] - fn propertyNameChanged(self: Pin<&mut SecondObject>); + #[cxx_name = "propertyNameChanged"] + fn property_name_changed(self: Pin<&mut SecondObject>); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "propertyNameChanged"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::second_object"] + type SecondObjectCxxQtSignalHandlerpropertyNameChanged = + cxx_qt::signalhandler::CxxQtSignalHandler< + super::SecondObjectCxxQtSignalClosurepropertyNameChanged, + >; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::second_object"] #[must_use] - #[rust_name = "connect_property_name_changed"] - fn propertyNameChangedConnect( - self: Pin<&mut SecondObject>, - func: fn(Pin<&mut SecondObject>), + #[rust_name = "SecondObject_connect_property_name_changed"] + fn SecondObject_propertyNameChangedConnect( + self_value: Pin<&mut SecondObject>, + signal_handler: SecondObjectCxxQtSignalHandlerpropertyNameChanged, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::second_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_SecondObject_signal_handler_propertyNameChanged( + handler: SecondObjectCxxQtSignalHandlerpropertyNameChanged, + ); + #[doc(hidden)] + fn call_SecondObject_signal_handler_propertyNameChanged( + handler: &mut SecondObjectCxxQtSignalHandlerpropertyNameChanged, + self_value: Pin<&mut SecondObject>, + ); + } extern "Rust" { #[doc(hidden)] #[cxx_name = "invokableNameWrapper"] @@ -180,21 +227,34 @@ pub mod ffi { } unsafe extern "C++" { #[my_attribute] - #[rust_name = "ready"] + #[cxx_name = "ready"] fn ready(self: Pin<&mut SecondObject>); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "ready"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::second_object"] + type SecondObjectCxxQtSignalHandlerready = + cxx_qt::signalhandler::CxxQtSignalHandler; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::second_object"] #[must_use] - #[rust_name = "connect_ready"] - fn readyConnect( - self: Pin<&mut SecondObject>, - func: fn(Pin<&mut SecondObject>), + #[rust_name = "SecondObject_connect_ready"] + fn SecondObject_readyConnect( + self_value: Pin<&mut SecondObject>, + signal_handler: SecondObjectCxxQtSignalHandlerready, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::second_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_SecondObject_signal_handler_ready(handler: SecondObjectCxxQtSignalHandlerready); + #[doc(hidden)] + fn call_SecondObject_signal_handler_ready( + handler: &mut SecondObjectCxxQtSignalHandlerready, + self_value: Pin<&mut SecondObject>, + ); + } extern "Rust" { #[cxx_name = "createRs"] #[namespace = "second_object::cxx_qt_second_object"] @@ -222,45 +282,95 @@ pub mod ffi { } unsafe extern "C++" { #[doc(hidden)] - #[namespace = "rust::cxxqtgen1::externcxxqt"] + #[namespace = "rust::cxxqtgen1"] + type QPushButtonCxxQtSignalHandlerclicked = + cxx_qt::signalhandler::CxxQtSignalHandler; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1"] #[must_use] #[rust_name = "QPushButton_connect_clicked"] fn QPushButton_clickedConnect( self_value: Pin<&mut QPushButton>, - func: fn(Pin<&mut QPushButton>, checked: bool), + signal_handler: QPushButtonCxxQtSignalHandlerclicked, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1"] + extern "Rust" { + #[doc(hidden)] + fn drop_QPushButton_signal_handler_clicked(handler: QPushButtonCxxQtSignalHandlerclicked); + #[doc(hidden)] + fn call_QPushButton_signal_handler_clicked( + handler: &mut QPushButtonCxxQtSignalHandlerclicked, + self_value: Pin<&mut QPushButton>, + checked: bool, + ); + } unsafe extern "C++" { #[cxx_name = "dataReady"] fn data_ready(self: Pin<&mut ExternObject>); } unsafe extern "C++" { #[doc(hidden)] - #[namespace = "rust::cxxqtgen1::externcxxqt::mynamespace"] + #[namespace = "rust::cxxqtgen1::mynamespace"] + type ExternObjectCxxQtSignalHandlerdataReady = cxx_qt::signalhandler::CxxQtSignalHandler< + super::ExternObjectCxxQtSignalClosuredataReady, + >; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::mynamespace"] #[must_use] #[rust_name = "ExternObject_connect_data_ready"] fn ExternObject_dataReadyConnect( self_value: Pin<&mut ExternObject>, - func: fn(Pin<&mut ExternObject>), + signal_handler: ExternObjectCxxQtSignalHandlerdataReady, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::mynamespace"] + extern "Rust" { + #[doc(hidden)] + fn drop_ExternObject_signal_handler_dataReady( + handler: ExternObjectCxxQtSignalHandlerdataReady, + ); + #[doc(hidden)] + fn call_ExternObject_signal_handler_dataReady( + handler: &mut ExternObjectCxxQtSignalHandlerdataReady, + self_value: Pin<&mut ExternObject>, + ); + } unsafe extern "C++" { #[rust_name = "error_occurred"] fn errorOccurred(self: Pin<&mut ExternObject>); } unsafe extern "C++" { #[doc(hidden)] - #[namespace = "rust::cxxqtgen1::externcxxqt::mynamespace"] + #[namespace = "rust::cxxqtgen1::mynamespace"] + type ExternObjectCxxQtSignalHandlererrorOccurred = + cxx_qt::signalhandler::CxxQtSignalHandler< + super::ExternObjectCxxQtSignalClosureerrorOccurred, + >; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::mynamespace"] #[must_use] #[rust_name = "ExternObject_connect_error_occurred"] fn ExternObject_errorOccurredConnect( self_value: Pin<&mut ExternObject>, - func: fn(Pin<&mut ExternObject>), + signal_handler: ExternObjectCxxQtSignalHandlererrorOccurred, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::mynamespace"] + extern "Rust" { + #[doc(hidden)] + fn drop_ExternObject_signal_handler_errorOccurred( + handler: ExternObjectCxxQtSignalHandlererrorOccurred, + ); + #[doc(hidden)] + fn call_ExternObject_signal_handler_errorOccurred( + handler: &mut ExternObjectCxxQtSignalHandlererrorOccurred, + self_value: Pin<&mut ExternObject>, + ); + } } impl ffi::MyObject { #[doc = "Getter for the Q_PROPERTY "] @@ -281,6 +391,25 @@ impl ffi::MyObject { self.as_mut().property_name_changed(); } } +impl ffi::MyObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "propertyNameChanged"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_property_name_changed) + 'static>( + self: core::pin::Pin<&mut ffi::MyObject>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::MyObject_connect_property_name_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::< + MyObjectCxxQtSignalClosurepropertyNameChanged, + >::new(Box::new(closure)), + conn_type, + ) + } +} impl ffi::MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "propertyNameChanged"] @@ -288,11 +417,63 @@ impl ffi::MyObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_property_name_changed( + pub fn on_property_name_changed) + 'static>( self: core::pin::Pin<&mut ffi::MyObject>, - func: fn(core::pin::Pin<&mut ffi::MyObject>), + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_property_name_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_property_name_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::< + MyObjectCxxQtSignalClosurepropertyNameChanged, + >::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) + } +} +#[doc(hidden)] +pub struct MyObjectCxxQtSignalClosurepropertyNameChanged {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure + for MyObjectCxxQtSignalClosurepropertyNameChanged +{ + type Id = cxx::type_id!( + "::rust::cxxqtgen1::cxx_qt::multi_object::MyObjectCxxQtSignalHandlerpropertyNameChanged" + ); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::MyObject>); +} +use core::mem::drop as drop_MyObject_signal_handler_propertyNameChanged; +fn call_MyObject_signal_handler_propertyNameChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler< + MyObjectCxxQtSignalClosurepropertyNameChanged, + >, + self_value: core::pin::Pin<&mut ffi::MyObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); +impl ffi::MyObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "ready"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_ready) + 'static>( + self: core::pin::Pin<&mut ffi::MyObject>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + conn_type, + ) } } impl ffi::MyObject { @@ -302,13 +483,41 @@ impl ffi::MyObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_ready( + pub fn on_ready) + 'static>( self: core::pin::Pin<&mut ffi::MyObject>, - func: fn(core::pin::Pin<&mut ffi::MyObject>), + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_ready(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } +#[doc(hidden)] +pub struct MyObjectCxxQtSignalClosureready {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureready { + type Id = + cxx::type_id!("::rust::cxxqtgen1::cxx_qt::multi_object::MyObjectCxxQtSignalHandlerready"); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::MyObject>); +} +use core::mem::drop as drop_MyObject_signal_handler_ready; +fn call_MyObject_signal_handler_ready( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut ffi::MyObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); impl cxx_qt::Locking for ffi::MyObject {} #[doc(hidden)] pub fn create_rs_my_object_rust() -> std::boxed::Box { @@ -348,6 +557,27 @@ impl ffi::SecondObject { self.as_mut().property_name_changed(); } } +impl ffi::SecondObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "propertyNameChanged"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_property_name_changed< + F: FnMut(core::pin::Pin<&mut ffi::SecondObject>) + 'static, + >( + self: core::pin::Pin<&mut ffi::SecondObject>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::SecondObject_connect_property_name_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::< + SecondObjectCxxQtSignalClosurepropertyNameChanged, + >::new(Box::new(closure)), + conn_type, + ) + } +} impl ffi::SecondObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "propertyNameChanged"] @@ -355,11 +585,63 @@ impl ffi::SecondObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_property_name_changed( + pub fn on_property_name_changed) + 'static>( self: core::pin::Pin<&mut ffi::SecondObject>, - func: fn(core::pin::Pin<&mut ffi::SecondObject>), + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_property_name_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::SecondObject_connect_property_name_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::< + SecondObjectCxxQtSignalClosurepropertyNameChanged, + >::new(Box::new(closure)), + cxx_qt_lib::ConnectionType::AutoConnection, + ) + } +} +#[doc(hidden)] +pub struct SecondObjectCxxQtSignalClosurepropertyNameChanged {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure + for SecondObjectCxxQtSignalClosurepropertyNameChanged +{ + type Id = cxx::type_id!( + "::rust::cxxqtgen1::second_object::SecondObjectCxxQtSignalHandlerpropertyNameChanged" + ); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::SecondObject>); +} +use core::mem::drop as drop_SecondObject_signal_handler_propertyNameChanged; +fn call_SecondObject_signal_handler_propertyNameChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler< + SecondObjectCxxQtSignalClosurepropertyNameChanged, + >, + self_value: core::pin::Pin<&mut ffi::SecondObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); +impl ffi::SecondObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "ready"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_ready) + 'static>( + self: core::pin::Pin<&mut ffi::SecondObject>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::SecondObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + conn_type, + ) } } impl ffi::SecondObject { @@ -369,14 +651,42 @@ impl ffi::SecondObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_ready( + pub fn on_ready) + 'static>( self: core::pin::Pin<&mut ffi::SecondObject>, - func: fn(core::pin::Pin<&mut ffi::SecondObject>), + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_ready(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::SecondObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } #[doc(hidden)] +pub struct SecondObjectCxxQtSignalClosureready {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for SecondObjectCxxQtSignalClosureready { + type Id = + cxx::type_id!("::rust::cxxqtgen1::second_object::SecondObjectCxxQtSignalHandlerready"); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::SecondObject>); +} +use core::mem::drop as drop_SecondObject_signal_handler_ready; +fn call_SecondObject_signal_handler_ready( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut ffi::SecondObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); +#[doc(hidden)] pub fn create_rs_second_object_rust() -> std::boxed::Box { std::boxed::Box::new(core::default::Default::default()) } @@ -399,84 +709,165 @@ impl ffi::QPushButton { #[doc = "Connect the given function pointer to the signal "] #[doc = "clicked"] #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[doc = "\n"] - #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_clicked( + pub fn connect_clicked, bool) + 'static>( self: core::pin::Pin<&mut ffi::QPushButton>, - func: fn(core::pin::Pin<&mut ffi::QPushButton>, checked: bool), + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, ) -> cxx_qt_lib::QMetaObjectConnection { - ffi::QPushButton_connect_clicked(self, func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::QPushButton_connect_clicked( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + conn_type, + ) } } impl ffi::QPushButton { #[doc = "Connect the given function pointer to the signal "] #[doc = "clicked"] #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc = "\n"] + #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn connect_clicked( + pub fn on_clicked, bool) + 'static>( self: core::pin::Pin<&mut ffi::QPushButton>, - func: fn(core::pin::Pin<&mut ffi::QPushButton>, checked: bool), - conn_type: cxx_qt_lib::ConnectionType, + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - ffi::QPushButton_connect_clicked(self, func, conn_type) + ffi::QPushButton_connect_clicked( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } +#[doc(hidden)] +pub struct QPushButtonCxxQtSignalClosureclicked {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for QPushButtonCxxQtSignalClosureclicked { + type Id = cxx::type_id!("::rust::cxxqtgen1::QPushButtonCxxQtSignalHandlerclicked"); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::QPushButton>, bool); +} +use core::mem::drop as drop_QPushButton_signal_handler_clicked; +fn call_QPushButton_signal_handler_clicked( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut ffi::QPushButton>, + checked: bool, +) { + handler.closure()(self_value, checked); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); impl ffi::ExternObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "dataReady"] #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[doc = "\n"] - #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_data_ready( + pub fn connect_data_ready) + 'static>( self: core::pin::Pin<&mut ffi::ExternObject>, - func: fn(core::pin::Pin<&mut ffi::ExternObject>), + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, ) -> cxx_qt_lib::QMetaObjectConnection { - ffi::ExternObject_connect_data_ready(self, func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi :: ExternObject_connect_data_ready (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < ExternObjectCxxQtSignalClosuredataReady > :: new (Box :: new (closure)) , conn_type ,) } } impl ffi::ExternObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "dataReady"] #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc = "\n"] + #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn connect_data_ready( + pub fn on_data_ready) + 'static>( self: core::pin::Pin<&mut ffi::ExternObject>, - func: fn(core::pin::Pin<&mut ffi::ExternObject>), - conn_type: cxx_qt_lib::ConnectionType, + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - ffi::ExternObject_connect_data_ready(self, func, conn_type) + ffi :: ExternObject_connect_data_ready (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < ExternObjectCxxQtSignalClosuredataReady > :: new (Box :: new (closure)) , cxx_qt_lib :: ConnectionType :: AutoConnection ,) } } +#[doc(hidden)] +pub struct ExternObjectCxxQtSignalClosuredataReady {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for ExternObjectCxxQtSignalClosuredataReady { + type Id = + cxx::type_id!("::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalHandlerdataReady"); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::ExternObject>); +} +use core::mem::drop as drop_ExternObject_signal_handler_dataReady; +fn call_ExternObject_signal_handler_dataReady( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler< + ExternObjectCxxQtSignalClosuredataReady, + >, + self_value: core::pin::Pin<&mut ffi::ExternObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); impl ffi::ExternObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "errorOccurred"] #[doc = ", so that when the signal is emitted the function pointer is executed."] - #[doc = "\n"] - #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_error_occurred( + pub fn connect_error_occurred) + 'static>( self: core::pin::Pin<&mut ffi::ExternObject>, - func: fn(core::pin::Pin<&mut ffi::ExternObject>), + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, ) -> cxx_qt_lib::QMetaObjectConnection { - ffi::ExternObject_connect_error_occurred( - self, - func, - cxx_qt_lib::ConnectionType::AutoConnection, - ) + ffi :: ExternObject_connect_error_occurred (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < ExternObjectCxxQtSignalClosureerrorOccurred > :: new (Box :: new (closure)) , conn_type ,) } } impl ffi::ExternObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "errorOccurred"] #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc = "\n"] + #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn connect_error_occurred( + pub fn on_error_occurred) + 'static>( self: core::pin::Pin<&mut ffi::ExternObject>, - func: fn(core::pin::Pin<&mut ffi::ExternObject>), - conn_type: cxx_qt_lib::ConnectionType, + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - ffi::ExternObject_connect_error_occurred(self, func, conn_type) + ffi :: ExternObject_connect_error_occurred (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < ExternObjectCxxQtSignalClosureerrorOccurred > :: new (Box :: new (closure)) , cxx_qt_lib :: ConnectionType :: AutoConnection ,) } } +#[doc(hidden)] +pub struct ExternObjectCxxQtSignalClosureerrorOccurred {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure + for ExternObjectCxxQtSignalClosureerrorOccurred +{ + type Id = cxx::type_id!( + "::rust::cxxqtgen1::mynamespace::ExternObjectCxxQtSignalHandlererrorOccurred" + ); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::ExternObject>); +} +use core::mem::drop as drop_ExternObject_signal_handler_errorOccurred; +fn call_ExternObject_signal_handler_errorOccurred( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler< + ExternObjectCxxQtSignalClosureerrorOccurred, + >, + self_value: core::pin::Pin<&mut ffi::ExternObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); diff --git a/crates/cxx-qt-gen/test_outputs/properties.cpp b/crates/cxx-qt-gen/test_outputs/properties.cpp index a418e071c..207ad9884 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.cpp +++ b/crates/cxx-qt-gen/test_outputs/properties.cpp @@ -1,5 +1,119 @@ #include "cxx-qt-gen/ffi.cxxqt.h" +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsprimitiveChanged*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_MyObject_signal_handler_primitiveChanged(::std::move(*this)); +} + +template<> +template<> +void +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsprimitiveChanged*>:: +operator()<::cxx_qt::my_object::MyObject&>(::cxx_qt::my_object::MyObject& self) +{ + call_MyObject_signal_handler_primitiveChanged(*this, self); +} + +static_assert( + alignof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsprimitiveChanged*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsprimitiveChanged*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_primitiveChangedConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalHandlerprimitiveChanged closure, + ::Qt::ConnectionType type) +{ + return ::QObject::connect( + &self, + &::cxx_qt::my_object::MyObject::primitiveChanged, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::my_object::MyObject> + guard(self); + closure.template operator()<::cxx_qt::my_object::MyObject&>(self); + }, + type); +} +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamstrivialChanged*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_MyObject_signal_handler_trivialChanged(::std::move(*this)); +} + +template<> +template<> +void +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamstrivialChanged*>:: +operator()<::cxx_qt::my_object::MyObject&>(::cxx_qt::my_object::MyObject& self) +{ + call_MyObject_signal_handler_trivialChanged(*this, self); +} + +static_assert( + alignof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamstrivialChanged*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamstrivialChanged*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_trivialChangedConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlertrivialChanged + closure, + ::Qt::ConnectionType type) +{ + return ::QObject::connect( + &self, + &::cxx_qt::my_object::MyObject::trivialChanged, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::my_object::MyObject> + guard(self); + closure.template operator()<::cxx_qt::my_object::MyObject&>(self); + }, + type); +} +} // namespace rust::cxxqtgen1::cxx_qt::my_object + namespace cxx_qt::my_object { ::std::int32_t const& MyObject::getPrimitive() const @@ -29,36 +143,6 @@ MyObject::setTrivial(QPoint const& value) setTrivialWrapper(value); } -::QMetaObject::Connection -MyObject::primitiveChangedConnect(::rust::Fn func, - ::Qt::ConnectionType type) -{ - return ::QObject::connect( - this, - &MyObject::primitiveChanged, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); - }, - type); -} - -::QMetaObject::Connection -MyObject::trivialChangedConnect(::rust::Fn func, - ::Qt::ConnectionType type) -{ - return ::QObject::connect( - this, - &MyObject::trivialChanged, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); - }, - type); -} - MyObject::MyObject(QObject* parent) : QObject(parent) , ::rust::cxxqtlib1::CxxQtType( diff --git a/crates/cxx-qt-gen/test_outputs/properties.h b/crates/cxx-qt-gen/test_outputs/properties.h index 6f708d326..100dd0df6 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.h +++ b/crates/cxx-qt-gen/test_outputs/properties.h @@ -10,8 +10,38 @@ class MyObject; } // namespace cxx_qt::my_object +namespace rust::cxxqtgen1::cxx_qt::my_object { +using MyObjectCxxQtSignalHandlerprimitiveChanged = + ::rust::cxxqtlib1::SignalHandler< + struct MyObjectCxxQtSignalParamsprimitiveChanged*>; +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +using MyObjectCxxQtSignalHandlertrivialChanged = + ::rust::cxxqtlib1::SignalHandler< + struct MyObjectCxxQtSignalParamstrivialChanged*>; +} // namespace rust::cxxqtgen1::cxx_qt::my_object + #include "cxx-qt-gen/ffi.cxx.h" +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_primitiveChangedConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalHandlerprimitiveChanged closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_trivialChangedConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlertrivialChanged + closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::my_object + namespace cxx_qt::my_object { class MyObject : public QObject @@ -33,13 +63,7 @@ class MyObject QPoint const& getTrivial() const; Q_SLOT void setTrivial(QPoint const& value); Q_SIGNAL void primitiveChanged(); - ::QMetaObject::Connection primitiveChangedConnect( - ::rust::Fn func, - ::Qt::ConnectionType type); Q_SIGNAL void trivialChanged(); - ::QMetaObject::Connection trivialChangedConnect( - ::rust::Fn func, - ::Qt::ConnectionType type); explicit MyObject(QObject* parent = nullptr); private: diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index 206125dba..b56ee8974 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -52,38 +52,70 @@ mod ffi { } unsafe extern "C++" { #[doc = "Notify for the Q_PROPERTY"] - #[rust_name = "primitive_changed"] - fn primitiveChanged(self: Pin<&mut MyObject>); + #[cxx_name = "primitiveChanged"] + fn primitive_changed(self: Pin<&mut MyObject>); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "primitiveChanged"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + type MyObjectCxxQtSignalHandlerprimitiveChanged = cxx_qt::signalhandler::CxxQtSignalHandler< + super::MyObjectCxxQtSignalClosureprimitiveChanged, + >; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] #[must_use] - #[rust_name = "connect_primitive_changed"] - fn primitiveChangedConnect( - self: Pin<&mut MyObject>, - func: fn(Pin<&mut MyObject>), + #[rust_name = "MyObject_connect_primitive_changed"] + fn MyObject_primitiveChangedConnect( + self_value: Pin<&mut MyObject>, + signal_handler: MyObjectCxxQtSignalHandlerprimitiveChanged, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_primitiveChanged( + handler: MyObjectCxxQtSignalHandlerprimitiveChanged, + ); + #[doc(hidden)] + fn call_MyObject_signal_handler_primitiveChanged( + handler: &mut MyObjectCxxQtSignalHandlerprimitiveChanged, + self_value: Pin<&mut MyObject>, + ); + } unsafe extern "C++" { #[doc = "Notify for the Q_PROPERTY"] - #[rust_name = "trivial_changed"] - fn trivialChanged(self: Pin<&mut MyObject>); + #[cxx_name = "trivialChanged"] + fn trivial_changed(self: Pin<&mut MyObject>); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "trivialChanged"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + type MyObjectCxxQtSignalHandlertrivialChanged = cxx_qt::signalhandler::CxxQtSignalHandler< + super::MyObjectCxxQtSignalClosuretrivialChanged, + >; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] #[must_use] - #[rust_name = "connect_trivial_changed"] - fn trivialChangedConnect( - self: Pin<&mut MyObject>, - func: fn(Pin<&mut MyObject>), + #[rust_name = "MyObject_connect_trivial_changed"] + fn MyObject_trivialChangedConnect( + self_value: Pin<&mut MyObject>, + signal_handler: MyObjectCxxQtSignalHandlertrivialChanged, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_trivialChanged( + handler: MyObjectCxxQtSignalHandlertrivialChanged, + ); + #[doc(hidden)] + fn call_MyObject_signal_handler_trivialChanged( + handler: &mut MyObjectCxxQtSignalHandlertrivialChanged, + self_value: Pin<&mut MyObject>, + ); + } extern "Rust" { #[cxx_name = "createRs"] #[namespace = "cxx_qt::my_object::cxx_qt_my_object"] @@ -138,6 +170,19 @@ impl ffi::MyObject { self.as_mut().trivial_changed(); } } +impl ffi::MyObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "primitiveChanged"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_primitive_changed) + 'static>( + self: core::pin::Pin<&mut ffi::MyObject>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi :: MyObject_connect_primitive_changed (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < MyObjectCxxQtSignalClosureprimitiveChanged > :: new (Box :: new (closure)) , conn_type ,) + } +} impl ffi::MyObject { #[doc = "Connect the given function pointer to the signal "] #[doc = "primitiveChanged"] @@ -145,11 +190,51 @@ impl ffi::MyObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_primitive_changed( + pub fn on_primitive_changed) + 'static>( + self: core::pin::Pin<&mut ffi::MyObject>, + mut closure: F, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi :: MyObject_connect_primitive_changed (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < MyObjectCxxQtSignalClosureprimitiveChanged > :: new (Box :: new (closure)) , cxx_qt_lib :: ConnectionType :: AutoConnection ,) + } +} +#[doc(hidden)] +pub struct MyObjectCxxQtSignalClosureprimitiveChanged {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure + for MyObjectCxxQtSignalClosureprimitiveChanged +{ + type Id = cxx::type_id!( + "::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlerprimitiveChanged" + ); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::MyObject>); +} +use core::mem::drop as drop_MyObject_signal_handler_primitiveChanged; +fn call_MyObject_signal_handler_primitiveChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler< + MyObjectCxxQtSignalClosureprimitiveChanged, + >, + self_value: core::pin::Pin<&mut ffi::MyObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); +impl ffi::MyObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "trivialChanged"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_trivial_changed) + 'static>( self: core::pin::Pin<&mut ffi::MyObject>, - func: fn(core::pin::Pin<&mut ffi::MyObject>), + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_primitive_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi :: MyObject_connect_trivial_changed (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < MyObjectCxxQtSignalClosuretrivialChanged > :: new (Box :: new (closure)) , conn_type ,) } } impl ffi::MyObject { @@ -159,13 +244,38 @@ impl ffi::MyObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_trivial_changed( + pub fn on_trivial_changed) + 'static>( self: core::pin::Pin<&mut ffi::MyObject>, - func: fn(core::pin::Pin<&mut ffi::MyObject>), + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_trivial_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi :: MyObject_connect_trivial_changed (self , cxx_qt :: signalhandler :: CxxQtSignalHandler :: < MyObjectCxxQtSignalClosuretrivialChanged > :: new (Box :: new (closure)) , cxx_qt_lib :: ConnectionType :: AutoConnection ,) } } +#[doc(hidden)] +pub struct MyObjectCxxQtSignalClosuretrivialChanged {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosuretrivialChanged { + type Id = cxx::type_id!( + "::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlertrivialChanged" + ); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::MyObject>); +} +use core::mem::drop as drop_MyObject_signal_handler_trivialChanged; +fn call_MyObject_signal_handler_trivialChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler< + MyObjectCxxQtSignalClosuretrivialChanged, + >, + self_value: core::pin::Pin<&mut ffi::MyObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); impl cxx_qt::Locking for ffi::MyObject {} #[doc(hidden)] pub fn create_rs_my_object_rust() -> std::boxed::Box { diff --git a/crates/cxx-qt-gen/test_outputs/signals.cpp b/crates/cxx-qt-gen/test_outputs/signals.cpp index 7dbb1dcfc..875e5df79 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.cpp +++ b/crates/cxx-qt-gen/test_outputs/signals.cpp @@ -1,79 +1,286 @@ #include "cxx-qt-gen/ffi.cxxqt.h" -namespace cxx_qt::my_object { +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + QTimerCxxQtSignalParamstimeout*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_QTimer_signal_handler_timeout(::std::move(*this)); +} + +template<> +template<> void -MyObject::invokable() +SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::QTimerCxxQtSignalParamstimeout*>:: +operator()<::cxx_qt::my_object::QTimer&>(::cxx_qt::my_object::QTimer& self) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - invokableWrapper(); + call_QTimer_signal_handler_timeout(*this, self); } +static_assert( + alignof( + SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::QTimerCxxQtSignalParamstimeout*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof( + SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::QTimerCxxQtSignalParamstimeout*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::my_object { ::QMetaObject::Connection -MyObject::readyConnect(::rust::Fn func, - ::Qt::ConnectionType type) +QTimer_timeoutConnect( + ::cxx_qt::my_object::QTimer& self, + ::rust::cxxqtgen1::cxx_qt::my_object::QTimerCxxQtSignalHandlertimeout closure, + ::Qt::ConnectionType type) { return ::QObject::connect( - this, - &MyObject::ready, - this, - [&, func = ::std::move(func)]() { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this); + &self, + &::cxx_qt::my_object::QTimer::timeout, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::my_object::QTimer> + guard(self); + closure.template operator()<::cxx_qt::my_object::QTimer&>(self); }, type); } +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsready*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_MyObject_signal_handler_ready(::std::move(*this)); +} +template<> +template<> +void +SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalParamsready*>:: +operator()<::cxx_qt::my_object::MyObject&>(::cxx_qt::my_object::MyObject& self) +{ + call_MyObject_signal_handler_ready(*this, self); +} + +static_assert( + alignof( + SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalParamsready*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert( + sizeof( + SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalParamsready*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::my_object { ::QMetaObject::Connection -MyObject::dataChangedConnect(::rust::Fn second, - QPoint third, - QPoint const& fourth)> func, - ::Qt::ConnectionType type) +MyObject_readyConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlerready closure, + ::Qt::ConnectionType type) { return ::QObject::connect( - this, - &MyObject::dataChanged, - this, - [&, func = ::std::move(func)](::std::int32_t first, - ::std::unique_ptr second, - QPoint third, - QPoint const& fourth) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this, - ::std::move(first), - ::std::move(second), - ::std::move(third), - ::std::move(fourth)); + &self, + &::cxx_qt::my_object::MyObject::ready, + &self, + [&, closure = ::std::move(closure)]() mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::my_object::MyObject> + guard(self); + closure.template operator()<::cxx_qt::my_object::MyObject&>(self); }, type); } +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsdataChanged*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_MyObject_signal_handler_dataChanged(::std::move(*this)); +} + +template<> +template<> +void +SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalParamsdataChanged*>:: +operator()<::cxx_qt::my_object::MyObject&, + ::std::int32_t, + ::std::unique_ptr, + QPoint, + QPoint const&>(::cxx_qt::my_object::MyObject& self, + ::std::int32_t first, + ::std::unique_ptr second, + QPoint third, + QPoint const& fourth) +{ + call_MyObject_signal_handler_dataChanged(*this, + self, + ::std::move(first), + ::std::move(second), + ::std::move(third), + ::std::move(fourth)); +} +static_assert(alignof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsdataChanged*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsdataChanged*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::my_object { ::QMetaObject::Connection -MyObject::newDataConnect(::rust::Fn second, - QPoint third, - QPoint const& fourth)> func, - ::Qt::ConnectionType type) +MyObject_dataChangedConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlerdataChanged + closure, + ::Qt::ConnectionType type) { return ::QObject::connect( - this, - &MyObject::newData, - this, - [&, func = ::std::move(func)](::std::int32_t first, - ::std::unique_ptr second, - QPoint third, - QPoint const& fourth) { - const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); - func(*this, - ::std::move(first), - ::std::move(second), - ::std::move(third), - ::std::move(fourth)); + &self, + &::cxx_qt::my_object::MyObject::dataChanged, + &self, + [&, closure = ::std::move(closure)](::std::int32_t first, + ::std::unique_ptr second, + QPoint third, + QPoint const& fourth) mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::my_object::MyObject> + guard(self); + closure.template operator()<::cxx_qt::my_object::MyObject&, + ::std::int32_t, + ::std::unique_ptr, + QPoint, + QPoint const&>(self, + ::std::move(first), + ::std::move(second), + ::std::move(third), + ::std::move(fourth)); }, type); } +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust::cxxqtlib1 { +template<> +SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsnewData*>::~SignalHandler() +{ + if (data[0] == nullptr && data[1] == nullptr) { + return; + } + + drop_MyObject_signal_handler_newData(::std::move(*this)); +} + +template<> +template<> +void +SignalHandler< + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalParamsnewData*>:: +operator()<::cxx_qt::my_object::MyObject&, + ::std::int32_t, + ::std::unique_ptr, + QPoint, + QPoint const&>(::cxx_qt::my_object::MyObject& self, + ::std::int32_t first, + ::std::unique_ptr second, + QPoint third, + QPoint const& fourth) +{ + call_MyObject_signal_handler_newData(*this, + self, + ::std::move(first), + ::std::move(second), + ::std::move(third), + ::std::move(fourth)); +} + +static_assert(alignof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsnewData*>) <= + alignof(::std::size_t), + "unexpected aligment"); +static_assert(sizeof(SignalHandler<::rust::cxxqtgen1::cxx_qt::my_object:: + MyObjectCxxQtSignalParamsnewData*>) == + sizeof(::std::size_t[2]), + "unexpected size"); +} // namespace rust::cxxqtlib1 + +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_newDataConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlernewData + closure, + ::Qt::ConnectionType type) +{ + return ::QObject::connect( + &self, + &::cxx_qt::my_object::MyObject::newData, + &self, + [&, closure = ::std::move(closure)](::std::int32_t first, + ::std::unique_ptr second, + QPoint third, + QPoint const& fourth) mutable { + const ::rust::cxxqtlib1::MaybeLockGuard<::cxx_qt::my_object::MyObject> + guard(self); + closure.template operator()<::cxx_qt::my_object::MyObject&, + ::std::int32_t, + ::std::unique_ptr, + QPoint, + QPoint const&>(self, + ::std::move(first), + ::std::move(second), + ::std::move(third), + ::std::move(fourth)); + }, + type); +} +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace cxx_qt::my_object { +void +MyObject::invokable() +{ + const ::rust::cxxqtlib1::MaybeLockGuard guard(*this); + invokableWrapper(); +} MyObject::MyObject(QObject* parent) : QObject(parent) diff --git a/crates/cxx-qt-gen/test_outputs/signals.h b/crates/cxx-qt-gen/test_outputs/signals.h index 04d54a358..d5ac7cd7f 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.h +++ b/crates/cxx-qt-gen/test_outputs/signals.h @@ -10,8 +10,62 @@ class MyObject; } // namespace cxx_qt::my_object +namespace rust::cxxqtgen1::cxx_qt::my_object { +using MyObjectCxxQtSignalHandlerready = + ::rust::cxxqtlib1::SignalHandler; +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +using MyObjectCxxQtSignalHandlerdataChanged = ::rust::cxxqtlib1::SignalHandler< + struct MyObjectCxxQtSignalParamsdataChanged*>; +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +using MyObjectCxxQtSignalHandlernewData = + ::rust::cxxqtlib1::SignalHandler; +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +using QTimerCxxQtSignalHandlertimeout = + ::rust::cxxqtlib1::SignalHandler; +} // namespace rust::cxxqtgen1::cxx_qt::my_object + #include "cxx-qt-gen/ffi.cxx.h" +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +QTimer_timeoutConnect( + ::cxx_qt::my_object::QTimer& self, + ::rust::cxxqtgen1::cxx_qt::my_object::QTimerCxxQtSignalHandlertimeout closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_readyConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlerready closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_dataChangedConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlerdataChanged + closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::my_object + +namespace rust::cxxqtgen1::cxx_qt::my_object { +::QMetaObject::Connection +MyObject_newDataConnect( + ::cxx_qt::my_object::MyObject& self, + ::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlernewData + closure, + ::Qt::ConnectionType type); +} // namespace rust::cxxqtgen1::cxx_qt::my_object + namespace cxx_qt::my_object { class MyObject : public QObject @@ -25,26 +79,10 @@ class MyObject public: Q_INVOKABLE void invokable(); Q_SIGNAL void ready(); - ::QMetaObject::Connection readyConnect(::rust::Fn func, - ::Qt::ConnectionType type); Q_SIGNAL void dataChanged(::std::int32_t first, ::std::unique_ptr second, QPoint third, QPoint const& fourth); - ::QMetaObject::Connection dataChangedConnect( - ::rust::Fn second, - QPoint third, - QPoint const& fourth)> func, - ::Qt::ConnectionType type); - ::QMetaObject::Connection newDataConnect( - ::rust::Fn second, - QPoint third, - QPoint const& fourth)> func, - ::Qt::ConnectionType type); explicit MyObject(QObject* parent = nullptr); private: diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index 1413f9fe8..31c084fbd 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -40,53 +40,76 @@ mod ffi { fn invokable(self: Pin<&mut MyObject>); } unsafe extern "C++" { - #[rust_name = "ready"] + #[cxx_name = "ready"] fn ready(self: Pin<&mut MyObject>); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "ready"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + type MyObjectCxxQtSignalHandlerready = + cxx_qt::signalhandler::CxxQtSignalHandler; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] #[must_use] - #[rust_name = "connect_ready"] - fn readyConnect( - self: Pin<&mut MyObject>, - func: fn(Pin<&mut MyObject>), + #[rust_name = "MyObject_connect_ready"] + fn MyObject_readyConnect( + self_value: Pin<&mut MyObject>, + signal_handler: MyObjectCxxQtSignalHandlerready, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_ready(handler: MyObjectCxxQtSignalHandlerready); + #[doc(hidden)] + fn call_MyObject_signal_handler_ready( + handler: &mut MyObjectCxxQtSignalHandlerready, + self_value: Pin<&mut MyObject>, + ); + } unsafe extern "C++" { - #[rust_name = "data_changed"] - fn dataChanged( + #[cxx_name = "dataChanged"] + fn data_changed( self: Pin<&mut MyObject>, first: i32, second: UniquePtr, third: QPoint, - fourth: &'a QPoint, + fourth: &QPoint, ); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "dataChanged"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + type MyObjectCxxQtSignalHandlerdataChanged = + cxx_qt::signalhandler::CxxQtSignalHandler; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] #[must_use] - #[rust_name = "connect_data_changed"] - fn dataChangedConnect( - self: Pin<&mut MyObject>, - func: fn( - Pin<&mut MyObject>, - first: i32, - second: UniquePtr, - third: QPoint, - fourth: &'a QPoint, - ), + #[rust_name = "MyObject_connect_data_changed"] + fn MyObject_dataChangedConnect( + self_value: Pin<&mut MyObject>, + signal_handler: MyObjectCxxQtSignalHandlerdataChanged, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_dataChanged(handler: MyObjectCxxQtSignalHandlerdataChanged); + #[doc(hidden)] + fn call_MyObject_signal_handler_dataChanged( + handler: &mut MyObjectCxxQtSignalHandlerdataChanged, + self_value: Pin<&mut MyObject>, + first: i32, + second: UniquePtr, + third: QPoint, + fourth: &QPoint, + ); + } unsafe extern "C++" { #[cxx_name = "newData"] - #[rust_name = "base_class_new_data"] - fn newData( + fn base_class_new_data( self: Pin<&mut MyObject>, first: i32, second: UniquePtr, @@ -95,23 +118,34 @@ mod ffi { ); } unsafe extern "C++" { - #[doc = "Connect the given function pointer to the signal "] - #[doc = "newData"] - #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + type MyObjectCxxQtSignalHandlernewData = + cxx_qt::signalhandler::CxxQtSignalHandler; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] #[must_use] - #[rust_name = "connect_base_class_new_data"] - fn newDataConnect( - self: Pin<&mut MyObject>, - func: fn( - Pin<&mut MyObject>, - first: i32, - second: UniquePtr, - third: QPoint, - fourth: &'a QPoint, - ), + #[rust_name = "MyObject_connect_base_class_new_data"] + fn MyObject_newDataConnect( + self_value: Pin<&mut MyObject>, + signal_handler: MyObjectCxxQtSignalHandlernewData, conn_type: CxxQtConnectionType, ) -> CxxQtQMetaObjectConnection; } + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_MyObject_signal_handler_newData(handler: MyObjectCxxQtSignalHandlernewData); + #[doc(hidden)] + fn call_MyObject_signal_handler_newData( + handler: &mut MyObjectCxxQtSignalHandlernewData, + self_value: Pin<&mut MyObject>, + first: i32, + second: UniquePtr, + third: QPoint, + fourth: &'a QPoint, + ); + } extern "Rust" { #[cxx_name = "createRs"] #[namespace = "cxx_qt::my_object::cxx_qt_my_object"] @@ -127,6 +161,55 @@ mod ffi { #[doc(hidden)] fn cxx_qt_ffi_rust_mut(self: Pin<&mut MyObject>) -> Pin<&mut MyObjectRust>; } + unsafe extern "C++" { + include ! (< QtCore / QTimer >); + #[doc = " QTimer"] + type QTimer; + } + unsafe extern "C++" { + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + type QTimerCxxQtSignalHandlertimeout = + cxx_qt::signalhandler::CxxQtSignalHandler; + #[doc(hidden)] + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + #[must_use] + #[rust_name = "QTimer_connect_timeout"] + fn QTimer_timeoutConnect( + self_value: Pin<&mut QTimer>, + signal_handler: QTimerCxxQtSignalHandlertimeout, + conn_type: CxxQtConnectionType, + ) -> CxxQtQMetaObjectConnection; + } + #[namespace = "rust::cxxqtgen1::cxx_qt::my_object"] + extern "Rust" { + #[doc(hidden)] + fn drop_QTimer_signal_handler_timeout(handler: QTimerCxxQtSignalHandlertimeout); + #[doc(hidden)] + fn call_QTimer_signal_handler_timeout( + handler: &mut QTimerCxxQtSignalHandlertimeout, + self_value: Pin<&mut QTimer>, + ); + } +} +impl ffi::MyObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "ready"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_ready) + 'static>( + self: core::pin::Pin<&mut ffi::MyObject>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + conn_type, + ) + } } impl ffi::MyObject { #[doc = "Connect the given function pointer to the signal "] @@ -135,11 +218,66 @@ impl ffi::MyObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_ready( + pub fn on_ready) + 'static>( + self: core::pin::Pin<&mut ffi::MyObject>, + mut closure: F, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::MyObject_connect_ready( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + cxx_qt_lib::ConnectionType::AutoConnection, + ) + } +} +#[doc(hidden)] +pub struct MyObjectCxxQtSignalClosureready {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureready { + type Id = + cxx::type_id!("::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlerready"); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::MyObject>); +} +use core::mem::drop as drop_MyObject_signal_handler_ready; +fn call_MyObject_signal_handler_ready( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut ffi::MyObject>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); +impl ffi::MyObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "dataChanged"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_data_changed< + F: FnMut( + core::pin::Pin<&mut ffi::MyObject>, + i32, + cxx::UniquePtr, + ffi::QPoint, + &ffi::QPoint, + ) + 'static, + >( self: core::pin::Pin<&mut ffi::MyObject>, - func: fn(core::pin::Pin<&mut ffi::MyObject>), + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_ready(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_data_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + conn_type, + ) } } impl ffi::MyObject { @@ -149,17 +287,85 @@ impl ffi::MyObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_data_changed( + pub fn on_data_changed< + F: FnMut( + core::pin::Pin<&mut ffi::MyObject>, + i32, + cxx::UniquePtr, + ffi::QPoint, + &ffi::QPoint, + ) + 'static, + >( self: core::pin::Pin<&mut ffi::MyObject>, - func: fn( - core::pin::Pin<&mut ffi::MyObject>, - first: i32, - second: cxx::UniquePtr, - third: ffi::QPoint, - fourth: &'a ffi::QPoint, - ), + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_data_changed(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_data_changed( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + cxx_qt_lib::ConnectionType::AutoConnection, + ) + } +} +#[doc(hidden)] +pub struct MyObjectCxxQtSignalClosuredataChanged {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosuredataChanged { + type Id = cxx::type_id!( + "::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlerdataChanged" + ); + type FnType = dyn FnMut( + core::pin::Pin<&mut ffi::MyObject>, + i32, + cxx::UniquePtr, + ffi::QPoint, + &ffi::QPoint, + ); +} +use core::mem::drop as drop_MyObject_signal_handler_dataChanged; +fn call_MyObject_signal_handler_dataChanged( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut ffi::MyObject>, + first: i32, + second: cxx::UniquePtr, + third: ffi::QPoint, + fourth: &ffi::QPoint, +) { + handler.closure()(self_value, first, second, third, fourth); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); +impl ffi::MyObject { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "newData"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_base_class_new_data< + F: FnMut( + core::pin::Pin<&mut ffi::MyObject>, + i32, + cxx::UniquePtr, + ffi::QPoint, + &'a ffi::QPoint, + ) + 'static, + >( + self: core::pin::Pin<&mut ffi::MyObject>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::MyObject_connect_base_class_new_data( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + conn_type, + ) } } impl ffi::MyObject { @@ -169,19 +375,59 @@ impl ffi::MyObject { #[doc = "\n"] #[doc = "Note that this method uses a AutoConnection connection type."] #[must_use] - pub fn on_base_class_new_data( + pub fn on_base_class_new_data< + F: FnMut( + core::pin::Pin<&mut ffi::MyObject>, + i32, + cxx::UniquePtr, + ffi::QPoint, + &'a ffi::QPoint, + ) + 'static, + >( self: core::pin::Pin<&mut ffi::MyObject>, - func: fn( - core::pin::Pin<&mut ffi::MyObject>, - first: i32, - second: cxx::UniquePtr, - third: ffi::QPoint, - fourth: &'a ffi::QPoint, - ), + mut closure: F, ) -> cxx_qt_lib::QMetaObjectConnection { - self.connect_base_class_new_data(func, cxx_qt_lib::ConnectionType::AutoConnection) + ffi::MyObject_connect_base_class_new_data( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + cxx_qt_lib::ConnectionType::AutoConnection, + ) } } +#[doc(hidden)] +pub struct MyObjectCxxQtSignalClosurenewData {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosurenewData { + type Id = + cxx::type_id!("::rust::cxxqtgen1::cxx_qt::my_object::MyObjectCxxQtSignalHandlernewData"); + type FnType = dyn FnMut( + core::pin::Pin<&mut ffi::MyObject>, + i32, + cxx::UniquePtr, + ffi::QPoint, + &'a ffi::QPoint, + ); +} +use core::mem::drop as drop_MyObject_signal_handler_newData; +fn call_MyObject_signal_handler_newData( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut ffi::MyObject>, + first: i32, + second: cxx::UniquePtr, + third: ffi::QPoint, + fourth: &'a ffi::QPoint, +) { + handler.closure()(self_value, first, second, third, fourth); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +); impl cxx_qt::Locking for ffi::MyObject {} #[doc(hidden)] pub fn create_rs_my_object_rust() -> std::boxed::Box { @@ -202,3 +448,64 @@ impl cxx_qt::CxxQtType for ffi::MyObject { self.cxx_qt_ffi_rust_mut() } } +impl ffi::QTimer { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "timeout"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[must_use] + pub fn connect_timeout) + 'static>( + self: core::pin::Pin<&mut ffi::QTimer>, + mut closure: F, + conn_type: cxx_qt_lib::ConnectionType, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::QTimer_connect_timeout( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + conn_type, + ) + } +} +impl ffi::QTimer { + #[doc = "Connect the given function pointer to the signal "] + #[doc = "timeout"] + #[doc = ", so that when the signal is emitted the function pointer is executed."] + #[doc = "\n"] + #[doc = "Note that this method uses a AutoConnection connection type."] + #[must_use] + pub fn on_timeout) + 'static>( + self: core::pin::Pin<&mut ffi::QTimer>, + mut closure: F, + ) -> cxx_qt_lib::QMetaObjectConnection { + ffi::QTimer_connect_timeout( + self, + cxx_qt::signalhandler::CxxQtSignalHandler::::new( + Box::new(closure), + ), + cxx_qt_lib::ConnectionType::AutoConnection, + ) + } +} +#[doc(hidden)] +pub struct QTimerCxxQtSignalClosuretimeout {} +impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for QTimerCxxQtSignalClosuretimeout { + type Id = + cxx::type_id!("::rust::cxxqtgen1::cxx_qt::my_object::QTimerCxxQtSignalHandlertimeout"); + type FnType = dyn FnMut(core::pin::Pin<&mut ffi::QTimer>); +} +use core::mem::drop as drop_QTimer_signal_handler_timeout; +fn call_QTimer_signal_handler_timeout( + handler: &mut cxx_qt::signalhandler::CxxQtSignalHandler, + self_value: core::pin::Pin<&mut ffi::QTimer>, +) { + handler.closure()(self_value); +} +cxx_qt::static_assertions::assert_eq_align!( + cxx_qt::signalhandler::CxxQtSignalHandler, + usize +); +cxx_qt::static_assertions::assert_eq_size!( + cxx_qt::signalhandler::CxxQtSignalHandler, + [usize; 2] +);