mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
133 lines
3.5 KiB
C++
133 lines
3.5 KiB
C++
/*
|
|
* 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>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Concepts.h>
|
|
#include <LibCore/EventLoop.h>
|
|
#include <LibCore/EventReceiver.h>
|
|
|
|
namespace Core {
|
|
|
|
template<typename Result, typename TError>
|
|
class Promise : public EventReceiver {
|
|
C_OBJECT(Promise);
|
|
|
|
public:
|
|
using ErrorType = TError;
|
|
|
|
Function<ErrorOr<void>(Result&)> on_resolution;
|
|
Function<void(ErrorType&)> 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<Result, ErrorType> await()
|
|
{
|
|
while (!m_result_or_rejection.has_value())
|
|
Core::EventLoop::current().pump();
|
|
|
|
return m_result_or_rejection.release_value();
|
|
}
|
|
|
|
// Converts a Promise<A> to a Promise<B> using a function func: A -> B
|
|
template<typename T>
|
|
NonnullRefPtr<Promise<T>> map(Function<T(Result&)> func)
|
|
{
|
|
NonnullRefPtr<Promise<T>> new_promise = Promise<T>::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<void> {
|
|
new_promise->resolve(func(result));
|
|
return {};
|
|
};
|
|
on_rejection = [new_promise](ErrorType& error) {
|
|
new_promise->reject(move(error));
|
|
};
|
|
return new_promise;
|
|
}
|
|
|
|
template<CallableAs<void, Result&> F>
|
|
Promise& when_resolved(F handler)
|
|
{
|
|
on_resolution = [handler = move(handler)](Result& result) { return handler(result); };
|
|
if (is_resolved()) {
|
|
auto handler_result = on_resolution(m_result_or_rejection->value());
|
|
possibly_handle_rejection(handler_result);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<CallableAs<ErrorOr<void>, 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<CallableAs<void, ErrorType&> F>
|
|
Promise& when_rejected(F handler)
|
|
{
|
|
on_rejection = move(handler);
|
|
if (is_rejected())
|
|
on_rejection(m_result_or_rejection->error());
|
|
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
template<typename T>
|
|
void possibly_handle_rejection(ErrorOr<T>& result)
|
|
{
|
|
if (result.is_error() && on_rejection)
|
|
on_rejection(result.error());
|
|
}
|
|
|
|
Promise() = default;
|
|
Promise(EventReceiver* parent)
|
|
: EventReceiver(parent)
|
|
{
|
|
}
|
|
|
|
Optional<ErrorOr<Result, ErrorType>> m_result_or_rejection;
|
|
};
|
|
|
|
}
|