Skip to content

Commit

Permalink
Fix: Require Send on closures connected to signals
Browse files Browse the repository at this point in the history
The closures may be executed on a different thread, depending on where
the emitting object lives.

Also closes #577. We have determined that is indeed safe to queue a
deferred closure, as the closure will not be called if the object is
deleted, as we use the object itself as the context.
  • Loading branch information
LeonMatthesKDAB authored and ahayzen-kdab committed Oct 2, 2024
1 parent 9ae598f commit dff128f
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 85 deletions.
18 changes: 9 additions & 9 deletions crates/cxx-qt-gen/src/generator/rust/property/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ mod tests {
#[doc = "Connect the given function pointer to the signal "]
#[doc = "trivialPropertyChanged"]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
pub fn connect_trivial_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn connect_trivial_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_trivial_property_changed(
self,
Expand All @@ -343,7 +343,7 @@ mod tests {
#[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."]
pub fn on_trivial_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn on_trivial_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_trivial_property_changed(
self,
Expand All @@ -366,7 +366,7 @@ mod tests {
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 qobject::MyObject>, );
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + Send;
}
},
);
Expand Down Expand Up @@ -448,7 +448,7 @@ mod tests {
#[doc = "Connect the given function pointer to the signal "]
#[doc = "opaquePropertyChanged"]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
pub fn connect_opaque_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn connect_opaque_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_opaque_property_changed(
self,
Expand All @@ -468,7 +468,7 @@ mod tests {
#[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."]
pub fn on_opaque_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn on_opaque_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_opaque_property_changed(
self,
Expand All @@ -491,7 +491,7 @@ mod tests {
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 qobject::MyObject>, );
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + Send;
}
},
);
Expand Down Expand Up @@ -573,7 +573,7 @@ mod tests {
#[doc = "Connect the given function pointer to the signal "]
#[doc = "unsafePropertyChanged"]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
pub fn connect_unsafe_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn connect_unsafe_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_unsafe_property_changed(
self,
Expand All @@ -593,7 +593,7 @@ mod tests {
#[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."]
pub fn on_unsafe_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn on_unsafe_property_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_unsafe_property_changed(
self,
Expand All @@ -616,7 +616,7 @@ mod tests {
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 qobject::MyObject>, );
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + Send;
}
},
);
Expand Down
30 changes: 15 additions & 15 deletions crates/cxx-qt-gen/src/generator/rust/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ pub fn generate_rust_signal(
#[doc = "Connect the given function pointer to the signal "]
#[doc = #signal_name_cpp]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
pub fn #connect_ident_rust<F: FnMut(#self_type_qualified, #(#parameters_qualified_type),*) + 'static>(self: #self_type_qualified, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn #connect_ident_rust<F: FnMut(#self_type_qualified, #(#parameters_qualified_type),*) + 'static + Send>(self: #self_type_qualified, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(#module_ident::#free_connect_ident_rust(
self,
Expand All @@ -181,7 +181,7 @@ pub fn generate_rust_signal(
#[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."]
pub fn #on_ident_rust<F: FnMut(#self_type_qualified, #(#parameters_qualified_type),*) + 'static>(self: #self_type_qualified, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn #on_ident_rust<F: FnMut(#self_type_qualified, #(#parameters_qualified_type),*) + 'static + Send>(self: #self_type_qualified, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(#module_ident::#free_connect_ident_rust(
self,
Expand All @@ -198,7 +198,7 @@ pub fn generate_rust_signal(
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),*);
type FnType = dyn FnMut(#self_type_qualified, #(#parameters_qualified_type),*) + Send;
}
},
quote! {
Expand Down Expand Up @@ -302,7 +302,7 @@ 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."]
pub fn connect_ready<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn connect_ready<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_ready(
self,
Expand All @@ -322,7 +322,7 @@ mod tests {
#[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."]
pub fn on_ready<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn on_ready<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_ready(
self,
Expand All @@ -345,7 +345,7 @@ mod tests {
quote! {
impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureready {
type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerready");
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, );
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + Send;
}
},
);
Expand Down Expand Up @@ -475,7 +475,7 @@ mod tests {
#[doc = "Connect the given function pointer to the signal "]
#[doc = "dataChanged"]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
pub fn connect_data_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, i32, cxx::UniquePtr<QColor>) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn connect_data_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, i32, cxx::UniquePtr<QColor>) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_data_changed(
self,
Expand All @@ -495,7 +495,7 @@ mod tests {
#[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."]
pub fn on_data_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, i32, cxx::UniquePtr<QColor>) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn on_data_changed<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, i32, cxx::UniquePtr<QColor>) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_data_changed(
self,
Expand All @@ -518,7 +518,7 @@ mod tests {
quote! {
impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosuredataChanged {
type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerdataChanged");
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, i32, cxx::UniquePtr<QColor>);
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, i32, cxx::UniquePtr<QColor>) + Send;
}
},
);
Expand Down Expand Up @@ -616,7 +616,7 @@ mod tests {
#[doc = "Connect the given function pointer to the signal "]
#[doc = "unsafeSignal"]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
pub fn connect_unsafe_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, *mut T) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn connect_unsafe_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, *mut T) + 'static +Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_unsafe_signal(
self,
Expand All @@ -636,7 +636,7 @@ mod tests {
#[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."]
pub fn on_unsafe_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, *mut T) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn on_unsafe_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, *mut T) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_unsafe_signal(
self,
Expand All @@ -659,7 +659,7 @@ mod tests {
quote! {
impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosureunsafeSignal {
type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerunsafeSignal");
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, *mut T);
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, *mut T) + Send;
}
},
);
Expand Down Expand Up @@ -759,7 +759,7 @@ mod tests {
#[doc = "Connect the given function pointer to the signal "]
#[doc = "baseName"]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
pub fn connect_existing_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
pub fn connect_existing_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F, conn_type: cxx_qt::ConnectionType) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_existing_signal(
self,
Expand All @@ -779,7 +779,7 @@ mod tests {
#[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."]
pub fn on_existing_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
pub fn on_existing_signal<F: FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + 'static + Send>(self: core::pin::Pin<&mut qobject::MyObject>, mut closure: F) -> cxx_qt::QMetaObjectConnectionGuard
{
cxx_qt::QMetaObjectConnectionGuard::from(qobject::MyObject_connect_existing_signal(
self,
Expand All @@ -802,7 +802,7 @@ mod tests {
quote! {
impl cxx_qt::signalhandler::CxxQtSignalHandlerClosure for MyObjectCxxQtSignalClosurebaseName {
type Id = cxx::type_id!("::rust::cxxqtgen1::MyObjectCxxQtSignalHandlerbaseName");
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, );
type FnType = dyn FnMut(core::pin::Pin<&mut qobject::MyObject>, ) + Send;
}
},
);
Expand Down
Loading

0 comments on commit dff128f

Please sign in to comment.