/* * Copyright (c) 2021, Kyle Pereira * Copyright (c) 2022, kleines Filmröllchen * Copyright (c) 2021-2023, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include namespace Core { template class Promise : public EventReceiver { C_OBJECT(Promise); public: using ErrorType = TError; Function(Result&)> on_resolution; Function on_rejection; template static NonnullRefPtr after(Vector>> promises) { auto promise = Promise::construct(); struct Resolved : RefCounted { explicit Resolved(size_t n) : needed(n) { } size_t count { 0 }; size_t needed { 0 }; Optional error; }; auto resolved = make_ref_counted(promises.size()); auto weak_promise = promise->template make_weak_ptr(); for (auto p : promises) { p->when_resolved([weak_promise, resolved](auto&&) -> ErrorOr { if (!weak_promise || weak_promise->is_rejected()) return {}; if (++resolved->count == resolved->needed) { if (resolved->error.has_value()) weak_promise->reject(resolved->error.release_value()); else weak_promise->resolve({}); } return {}; }); p->when_rejected([weak_promise, resolved](auto&& error) { resolved->error = move(error); if (!weak_promise) return; if (++resolved->count == resolved->needed) weak_promise->reject(resolved->error.release_value()); }); promise->add_child(*p); } return promise; } void resolve(Result&& result) { m_result_or_rejection = move(result); if (on_resolution) { auto handler_result = on_resolution(m_result_or_rejection->value()); possibly_handle_rejection(handler_result); } } void reject(ErrorType&& error) { m_result_or_rejection = move(error); possibly_handle_rejection(*m_result_or_rejection); } bool is_rejected() { return m_result_or_rejection.has_value() && m_result_or_rejection->is_error(); } bool is_resolved() const { return m_result_or_rejection.has_value() && !m_result_or_rejection->is_error(); } ErrorOr await() { while (!m_result_or_rejection.has_value()) Core::EventLoop::current().pump(); return m_result_or_rejection.release_value(); } // Converts a Promise to a Promise using a function func: A -> B template NonnullRefPtr> map(Function func) { NonnullRefPtr> new_promise = Promise::construct(); if (is_resolved()) new_promise->resolve(func(m_result_or_rejection->value())); if (is_rejected()) new_promise->reject(m_result_or_rejection->release_error()); on_resolution = [new_promise, func = move(func)](Result& result) -> ErrorOr { new_promise->resolve(func(result)); return {}; }; on_rejection = [new_promise](ErrorType& error) { new_promise->reject(move(error)); }; return new_promise; } template F> Promise& when_resolved(F handler) { return when_resolved([handler = move(handler)](Result& result) mutable -> ErrorOr { handler(result); return {}; }); } template, Result&> F> Promise& when_resolved(F handler) { on_resolution = move(handler); if (is_resolved()) { auto handler_result = on_resolution(m_result_or_rejection->value()); possibly_handle_rejection(handler_result); } return *this; } template F> Promise& when_rejected(F handler) { on_rejection = move(handler); if (is_rejected()) on_rejection(m_result_or_rejection->error()); return *this; } private: template void possibly_handle_rejection(ErrorOr& result) { if (result.is_error() && on_rejection) on_rejection(result.error()); } Promise() = default; Promise(EventReceiver* parent) : EventReceiver(parent) { } Optional> m_result_or_rejection; }; }