123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- /*
- * Copyright (c) 2021, Kyle Pereira <hey@xylepereira.me>
- * Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
- * Copyright (c) 2021-2023, Ali Mohammad Pur <mpfard@serenityos.org>
- * Copyright (c) 2023, Gregory Bertilson <zaggy1024@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <AK/AtomicRefCounted.h>
- #include <AK/Concepts.h>
- #include <LibCore/EventLoop.h>
- #include <LibCore/EventReceiver.h>
- #include <LibThreading/Mutex.h>
- namespace Core {
- template<typename TResult, typename TError>
- class ThreadedPromise
- : public AtomicRefCounted<ThreadedPromise<TResult, TError>> {
- public:
- static NonnullRefPtr<ThreadedPromise<TResult, TError>> create()
- {
- return adopt_ref(*new ThreadedPromise<TResult, TError>());
- }
- using ResultType = Conditional<IsSame<TResult, void>, Empty, TResult>;
- using ErrorType = TError;
- void resolve(ResultType&& result)
- {
- when_error_handler_is_ready([self = NonnullRefPtr(*this), result = move(result)]() mutable {
- if (self->m_resolution_handler) {
- auto handler_result = self->m_resolution_handler(forward<ResultType>(result));
- if (handler_result.is_error())
- self->m_rejection_handler(handler_result.release_error());
- self->m_has_completed = true;
- }
- });
- }
- void resolve()
- requires IsSame<ResultType, Empty>
- {
- resolve(Empty());
- }
- void reject(ErrorType&& error)
- {
- when_error_handler_is_ready([this, error = move(error)]() mutable {
- m_rejection_handler(forward<ErrorType>(error));
- m_has_completed = true;
- });
- }
- void reject(ErrorType const& error)
- requires IsTriviallyCopyable<ErrorType>
- {
- reject(ErrorType(error));
- }
- bool has_completed()
- {
- Threading::MutexLocker locker { m_mutex };
- return m_has_completed;
- }
- void await()
- {
- while (!has_completed())
- Core::EventLoop::current().pump(EventLoop::WaitMode::PollForEvents);
- }
- // Set the callback to be called when the promise is resolved. A rejection callback
- // must also be provided before any callback will be called.
- template<CallableAs<ErrorOr<void>, ResultType&&> ResolvedHandler>
- ThreadedPromise& when_resolved(ResolvedHandler handler)
- {
- Threading::MutexLocker locker { m_mutex };
- VERIFY(!m_resolution_handler);
- m_resolution_handler = move(handler);
- return *this;
- }
- template<CallableAs<void, ResultType&&> ResolvedHandler>
- ThreadedPromise& when_resolved(ResolvedHandler handler)
- {
- return when_resolved([handler = move(handler)](ResultType&& result) -> ErrorOr<void> {
- handler(forward<ResultType>(result));
- return {};
- });
- }
- template<CallableAs<ErrorOr<void>> ResolvedHandler>
- ThreadedPromise& when_resolved(ResolvedHandler handler)
- {
- return when_resolved([handler = move(handler)](ResultType&&) -> ErrorOr<void> {
- return handler();
- });
- }
- template<CallableAs<void> ResolvedHandler>
- ThreadedPromise& when_resolved(ResolvedHandler handler)
- {
- return when_resolved([handler = move(handler)](ResultType&&) -> ErrorOr<void> {
- handler();
- return {};
- });
- }
- // Set the callback to be called when the promise is rejected. Setting this callback
- // will cause the promise fulfillment to be ready to be handled.
- template<CallableAs<void, ErrorType&&> RejectedHandler>
- ThreadedPromise& when_rejected(RejectedHandler when_rejected = [](ErrorType&) {})
- {
- Threading::MutexLocker locker { m_mutex };
- VERIFY(!m_rejection_handler);
- m_rejection_handler = move(when_rejected);
- return *this;
- }
- template<typename T, CallableAs<NonnullRefPtr<ThreadedPromise<T, ErrorType>>, ResultType&&> ChainedResolution>
- NonnullRefPtr<ThreadedPromise<T, ErrorType>> chain_promise(ChainedResolution chained_resolution)
- {
- auto new_promise = ThreadedPromise<T, ErrorType>::create();
- when_resolved([=, chained_resolution = move(chained_resolution)](ResultType&& result) mutable -> ErrorOr<void> {
- chained_resolution(forward<ResultType>(result))
- ->when_resolved([=](auto&& new_result) { new_promise->resolve(move(new_result)); })
- .when_rejected([=](ErrorType&& error) { new_promise->reject(move(error)); });
- return {};
- });
- when_rejected([=](ErrorType&& error) { new_promise->reject(move(error)); });
- return new_promise;
- }
- template<typename T, CallableAs<ErrorOr<T, ErrorType>, ResultType&&> MappingFunction>
- NonnullRefPtr<ThreadedPromise<T, ErrorType>> map(MappingFunction mapping_function)
- {
- auto new_promise = ThreadedPromise<T, ErrorType>::create();
- when_resolved([=, mapping_function = move(mapping_function)](ResultType&& result) -> ErrorOr<void> {
- new_promise->resolve(TRY(mapping_function(forward<ResultType>(result))));
- return {};
- });
- when_rejected([=](ErrorType&& error) { new_promise->reject(move(error)); });
- return new_promise;
- }
- private:
- template<typename F>
- static void deferred_handler_check(NonnullRefPtr<ThreadedPromise> self, F&& function)
- {
- Threading::MutexLocker locker { self->m_mutex };
- if (self->m_rejection_handler) {
- function();
- return;
- }
- EventLoop::current().deferred_invoke([self, function = forward<F>(function)]() mutable {
- deferred_handler_check(self, move(function));
- });
- }
- template<typename F>
- void when_error_handler_is_ready(F function)
- {
- if (EventLoop::is_running()) {
- deferred_handler_check(NonnullRefPtr(*this), move(function));
- } else {
- // NOTE: Handlers should always be set almost immediately, so we can expect this
- // to spin extremely briefly. Therefore, sleeping the thread should not be
- // necessary.
- while (true) {
- Threading::MutexLocker locker { m_mutex };
- if (m_rejection_handler)
- break;
- }
- VERIFY(m_rejection_handler);
- function();
- }
- }
- ThreadedPromise() = default;
- ThreadedPromise(EventReceiver* parent)
- : EventReceiver(parent)
- {
- }
- Function<ErrorOr<void>(ResultType&&)> m_resolution_handler;
- Function<void(ErrorType&&)> m_rejection_handler;
- Threading::Mutex m_mutex;
- bool m_has_completed;
- };
- }
|