/* * 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; 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) -> 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; }; }