// clang-format off // SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company // clang-format on // SPDX-FileContributor: Andrew Hayzen // // SPDX-License-Identifier: MIT OR Apache-2.0 #pragma once #include #include #include #include #include #include #include "rust/cxx.h" namespace rust { namespace cxxqt1 { template class CxxQtGuardedPointer final { public: explicit CxxQtGuardedPointer(T* ptr) : ptr(ptr) { } T* ptr; ::std::shared_mutex mutex; }; template class CxxQtThread final { public: CxxQtThread(::std::shared_ptr> obj) : m_obj(obj) { } ~CxxQtThread() = default; CxxQtThread(const CxxQtThread& other) = default; CxxQtThread(CxxQtThread&& other) = default; bool isDestroyed() const { const auto guard = ::std::shared_lock(m_obj->mutex); return m_obj->ptr == nullptr; } template void queue(::rust::Fn arg)> func, ::rust::Box 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) { throw ::std::runtime_error( "Cannot queue function pointer as object has been destroyed"); return; } // Construct the lambda auto obj = m_obj; auto lambda = [obj = ::std::move(obj), func = ::std::move(func), arg = ::std::move(arg)]() mutable { // Ensure that we can read the pointer and it's not being written to const auto guard = ::std::shared_lock(obj->mutex); if (obj->ptr) { func(*obj->ptr, ::std::move(arg)); } else { qWarning() << "Could not call the function pointer as object has been destroyed"; } }; // Add the lambda to the queue if (!QMetaObject::invokeMethod( m_obj->ptr, ::std::move(lambda), Qt::QueuedConnection)) { throw ::std::runtime_error( "Cannot queue function pointer as invokeMethod on object failed"); } } private: ::std::shared_ptr> m_obj; }; template CxxQtThread cxxQtThreadClone(const CxxQtThread& cxxQtThread) { return CxxQtThread(cxxQtThread); } template void cxxQtThreadDrop(CxxQtThread& cxxQtThread) { cxxQtThread.~CxxQtThread(); } template void cxxQtThreadQueue(const CxxQtThread& cxxQtThread, ::rust::Fn arg)> func, ::rust::Box arg) { cxxQtThread.queue(::std::move(func), ::std::move(arg)); } template bool cxxQtThreadIsDestroyed(const CxxQtThread& cxxQtThread) { return cxxQtThread.isDestroyed(); } } // namespace cxxqt1 } // namespace rust // Define namespace otherwise we hit a GCC bug // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 namespace rust { template struct IsRelocatable<::rust::cxxqt1::CxxQtThread> : ::std::true_type {}; } // namespace rust