Skip to content

Commit

Permalink
threading: do not use exceptions and instead use return values
Browse files Browse the repository at this point in the history
  • Loading branch information
ahayzen-kdab committed Nov 22, 2024
1 parent 1273600 commit ba8a355
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 36 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ syn = { version = "2.0", features = ["extra-traits", "full"] }
quote = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"

[workspace.lints.clippy]
incompatible_msrv = "deny"
incompatible_msrv = "deny"
18 changes: 12 additions & 6 deletions crates/cxx-qt-gen/src/generator/rust/threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub fn generate(
cxx_qt_thread: &#cxx_qt_thread_ident,
func: fn(Pin<&mut #cpp_struct_ident>, Box<#cxx_qt_thread_queued_fn_ident>),
arg: Box<#cxx_qt_thread_queued_fn_ident>,
) -> Result<()>;
) -> u8;

#[doc(hidden)]
#(#thread_clone_attrs)*
Expand Down Expand Up @@ -121,7 +121,7 @@ pub fn generate(
}

#[doc(hidden)]
fn queue<F>(cxx_qt_thread: &#module_ident::#cxx_qt_thread_ident, f: F) -> std::result::Result<(), cxx::Exception>
fn queue<F>(cxx_qt_thread: &#module_ident::#cxx_qt_thread_ident, f: F) -> std::result::Result<(), cxx_qt::ThreadingQueueError>
where
F: FnOnce(core::pin::Pin<&mut #qualified_impl>),
F: Send + 'static,
Expand All @@ -138,7 +138,10 @@ pub fn generate(
(arg.inner)(obj)
}
let arg = #cxx_qt_thread_queued_fn_ident { inner: std::boxed::Box::new(f) };
#thread_queue_qualified(cxx_qt_thread, func, std::boxed::Box::new(arg))
match #thread_queue_qualified(cxx_qt_thread, func, std::boxed::Box::new(arg)) {
0 => Ok(()),
others => Err(others.into()),
}
}

#[doc(hidden)]
Expand Down Expand Up @@ -221,7 +224,7 @@ mod tests {
cxx_qt_thread: &MyObjectCxxQtThread,
func: fn(Pin<&mut MyObject>, Box<MyObjectCxxQtThreadQueuedFn>),
arg: Box<MyObjectCxxQtThreadQueuedFn>,
) -> Result<()>;
) -> u8;

#[doc(hidden)]
#[cxx_name = "cxxQtThreadClone"]
Expand Down Expand Up @@ -269,7 +272,7 @@ mod tests {
}

#[doc(hidden)]
fn queue<F>(cxx_qt_thread: &qobject::MyObjectCxxQtThread, f: F) -> std::result::Result<(), cxx::Exception>
fn queue<F>(cxx_qt_thread: &qobject::MyObjectCxxQtThread, f: F) -> std::result::Result<(), cxx_qt::ThreadingQueueError>
where
F: FnOnce(core::pin::Pin<&mut qobject::MyObject>),
F: Send + 'static,
Expand All @@ -286,7 +289,10 @@ mod tests {
(arg.inner)(obj)
}
let arg = MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box::new(f) };
qobject::cxx_qt_ffi_MyObject_cxxQtThreadQueue(cxx_qt_thread, func, std::boxed::Box::new(arg))
match qobject::cxx_qt_ffi_MyObject_cxxQtThreadQueue(cxx_qt_thread, func, std::boxed::Box::new(arg)) {
0 => Ok(()),
others => Err(others.into()),
}
}

#[doc(hidden)]
Expand Down
13 changes: 10 additions & 3 deletions crates/cxx-qt-gen/test_outputs/invokables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ mod ffi {
cxx_qt_thread: &MyObjectCxxQtThread,
func: fn(Pin<&mut MyObject>, Box<MyObjectCxxQtThreadQueuedFn>),
arg: Box<MyObjectCxxQtThreadQueuedFn>,
) -> Result<()>;
) -> u8;
#[doc(hidden)]
#[cxx_name = "cxxQtThreadClone"]
#[namespace = "rust::cxxqt1"]
Expand Down Expand Up @@ -262,7 +262,7 @@ impl cxx_qt::Threading for ffi::MyObject {
fn queue<F>(
cxx_qt_thread: &ffi::MyObjectCxxQtThread,
f: F,
) -> std::result::Result<(), cxx::Exception>
) -> std::result::Result<(), cxx_qt::ThreadingQueueError>
where
F: FnOnce(core::pin::Pin<&mut ffi::MyObject>),
F: Send + 'static,
Expand All @@ -278,7 +278,14 @@ impl cxx_qt::Threading for ffi::MyObject {
let arg = MyObjectCxxQtThreadQueuedFn {
inner: std::boxed::Box::new(f),
};
ffi::cxx_qt_ffi_MyObject_cxxQtThreadQueue(cxx_qt_thread, func, std::boxed::Box::new(arg))
match ffi::cxx_qt_ffi_MyObject_cxxQtThreadQueue(
cxx_qt_thread,
func,
std::boxed::Box::new(arg),
) {
0 => Ok(()),
others => Err(others.into()),
}
}
#[doc(hidden)]
fn threading_clone(cxx_qt_thread: &ffi::MyObjectCxxQtThread) -> ffi::MyObjectCxxQtThread {
Expand Down
1 change: 1 addition & 0 deletions crates/cxx-qt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ links = "cxx-qt"
cxx.workspace = true
cxx-qt-macro.workspace = true
static_assertions = "1.1.0"
thiserror.workspace = true

[build-dependencies]
cxx-qt-build.workspace = true
Expand Down
31 changes: 9 additions & 22 deletions crates/cxx-qt/include/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <cstdint>
#include <iostream>
#include <memory>
#include <mutex>
Expand Down Expand Up @@ -53,21 +54,13 @@ class CxxQtThread final
}

template<typename A>
void queue(::rust::Fn<void(T& self, ::rust::Box<A> arg)> func,
::rust::Box<A> arg) const
::std::uint8_t queue(::rust::Fn<void(T& self, ::rust::Box<A> arg)> func,
::rust::Box<A> arg) const
{
// Ensure that we can read the pointer and it's not being written to
const auto guard = ::std::shared_lock(m_obj->mutex);
if (!m_obj->ptr) {
#if defined(RUST_CXX_NO_EXCEPTIONS)
std::cerr << "Cannot queue function pointer as object has been destroyed"
<< std::endl;
std::abort();
#else
throw ::std::runtime_error(
"Cannot queue function pointer as object has been destroyed");
#endif
return;
return 1;
}

// Construct the lambda
Expand All @@ -88,16 +81,10 @@ class CxxQtThread final
// Add the lambda to the queue
if (!QMetaObject::invokeMethod(
m_obj->ptr, ::std::move(lambda), Qt::QueuedConnection)) {
#if defined(RUST_CXX_NO_EXCEPTIONS)
std::cerr
<< "Cannot queue function pointer as invokeMethod on object failed"
<< std::endl;
std::abort();
#else
throw ::std::runtime_error(
"Cannot queue function pointer as invokeMethod on object failed");
#endif
return 2;
}

return 0;
}

private:
Expand All @@ -119,12 +106,12 @@ cxxQtThreadDrop(CxxQtThread<T>& cxxQtThread)
}

template<typename A, typename T>
void
::std::uint8_t
cxxQtThreadQueue(const CxxQtThread<T>& cxxQtThread,
::rust::Fn<void(T& self, ::rust::Box<A> arg)> func,
::rust::Box<A> arg)
{
cxxQtThread.queue(::std::move(func), ::std::move(arg));
return cxxQtThread.queue(::std::move(func), ::std::move(arg));
}

template<typename T>
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use cxx_qt_macro::qobject;

pub use connection::{ConnectionType, QMetaObjectConnection};
pub use connectionguard::QMetaObjectConnectionGuard;
pub use threading::CxxQtThread;
pub use threading::{CxxQtThread, ThreadingQueueError};

// Export static assertions that can then be used in cxx-qt-gen generation
//
Expand Down Expand Up @@ -109,7 +109,7 @@ pub trait Threading: Sized {
fn is_destroyed(cxx_qt_thread: &CxxQtThread<Self>) -> bool;

#[doc(hidden)]
fn queue<F>(cxx_qt_thread: &CxxQtThread<Self>, f: F) -> Result<(), cxx::Exception>
fn queue<F>(cxx_qt_thread: &CxxQtThread<Self>, f: F) -> Result<(), ThreadingQueueError>
where
F: FnOnce(core::pin::Pin<&mut Self>),
F: Send + 'static;
Expand Down
28 changes: 27 additions & 1 deletion crates/cxx-qt/src/threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,35 @@

use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin};
use cxx::ExternType;
use thiserror::Error;

use crate::Threading;

/// Errors that can occur from CXX-Qt
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ThreadingQueueError {
/// Threading failed as the object has been destroyed
#[error("Cannot queue function pointer as object has been destroyed")]
ObjectDestroyed,
/// Threading failed calling invokeMethod on the object
#[error("Cannot queue function pointer as invokeMethod on object failed")]
InvokeMethodFailed,
/// Threading failed with unknown error
#[error("Cannot queue as an unknown error occurred")]
Unknown,
}

impl From<u8> for ThreadingQueueError {
fn from(value: u8) -> Self {
match value {
1 => Self::ObjectDestroyed,
2 => Self::InvokeMethodFailed,
_others => Self::Unknown,
}
}
}

/// A threading helper which is created from a QObject that implements [Threading].
///
/// This allows for queueing closures onto the Qt event loop from a background thread
Expand Down Expand Up @@ -73,7 +99,7 @@ where
///
/// The first argument of the closure is a pinned mutable reference to the QObject.
/// With this parameter, you can then update the QObject to reflect any state changes that have occured in the background thread.
pub fn queue<F>(&self, f: F) -> Result<(), cxx::Exception>
pub fn queue<F>(&self, f: F) -> Result<(), crate::ThreadingQueueError>
where
F: FnOnce(Pin<&mut T>),
F: Send + 'static,
Expand Down
2 changes: 1 addition & 1 deletion crates/qt-build-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ rust-version.workspace = true
[dependencies]
cc.workspace = true
versions = "6.3"
thiserror = "1.0"
thiserror.workspace = true

[features]
# When Cargo links an executable, whether a bin crate or test executable,
Expand Down

0 comments on commit ba8a355

Please sign in to comment.