|
|
|
@ -5,6 +5,7 @@ |
|
|
|
|
|
|
|
#include "common/assert.h" |
|
|
|
#include "common/bit_field.h" |
|
|
|
#include "common/common_funcs.h" |
|
|
|
#include "common/common_types.h" |
|
|
|
#include "common/expected.h" |
|
|
|
|
|
|
|
@ -130,6 +131,10 @@ union Result { |
|
|
|
[[nodiscard]] constexpr bool IsError() const { |
|
|
|
return !IsSuccess(); |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] constexpr bool IsFailure() const { |
|
|
|
return !IsSuccess(); |
|
|
|
} |
|
|
|
}; |
|
|
|
static_assert(std::is_trivial_v<Result>); |
|
|
|
|
|
|
|
@ -349,10 +354,110 @@ private: |
|
|
|
} \ |
|
|
|
} while (false) |
|
|
|
|
|
|
|
#define R_SUCCEEDED(res) (res.IsSuccess()) |
|
|
|
#define R_SUCCEEDED(res) (static_cast<Result>(res).IsSuccess()) |
|
|
|
#define R_FAILED(res) (static_cast<Result>(res).IsFailure()) |
|
|
|
|
|
|
|
/// Evaluates a boolean expression, and succeeds if that expression is true. |
|
|
|
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess) |
|
|
|
namespace ResultImpl { |
|
|
|
template <auto EvaluateResult, class F> |
|
|
|
class ScopedResultGuard { |
|
|
|
YUZU_NON_COPYABLE(ScopedResultGuard); |
|
|
|
YUZU_NON_MOVEABLE(ScopedResultGuard); |
|
|
|
|
|
|
|
private: |
|
|
|
Result& m_ref; |
|
|
|
F m_f; |
|
|
|
|
|
|
|
public: |
|
|
|
constexpr ScopedResultGuard(Result& ref, F f) : m_ref(ref), m_f(std::move(f)) {} |
|
|
|
constexpr ~ScopedResultGuard() { |
|
|
|
if (EvaluateResult(m_ref)) { |
|
|
|
m_f(); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
template <auto EvaluateResult> |
|
|
|
class ResultReferenceForScopedResultGuard { |
|
|
|
private: |
|
|
|
Result& m_ref; |
|
|
|
|
|
|
|
public: |
|
|
|
constexpr ResultReferenceForScopedResultGuard(Result& r) : m_ref(r) {} |
|
|
|
constexpr operator Result&() const { |
|
|
|
return m_ref; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
template <auto EvaluateResult, typename F> |
|
|
|
constexpr ScopedResultGuard<EvaluateResult, F> operator+( |
|
|
|
ResultReferenceForScopedResultGuard<EvaluateResult> ref, F&& f) { |
|
|
|
return ScopedResultGuard<EvaluateResult, F>(static_cast<Result&>(ref), std::forward<F>(f)); |
|
|
|
} |
|
|
|
|
|
|
|
constexpr bool EvaluateResultSuccess(const Result& r) { |
|
|
|
return R_SUCCEEDED(r); |
|
|
|
} |
|
|
|
constexpr bool EvaluateResultFailure(const Result& r) { |
|
|
|
return R_FAILED(r); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
|
|
constexpr void UpdateCurrentResultReference(T result_reference, Result result) { |
|
|
|
ASSERT(false); |
|
|
|
} |
|
|
|
|
|
|
|
template <> |
|
|
|
constexpr void UpdateCurrentResultReference<Result&>(Result& result_reference, Result result) { |
|
|
|
result_reference = result; |
|
|
|
} |
|
|
|
|
|
|
|
template <> |
|
|
|
constexpr void UpdateCurrentResultReference<Result>(Result result_reference, Result result) {} |
|
|
|
} // namespace ResultImpl |
|
|
|
|
|
|
|
#define DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(COUNTER_VALUE) \ |
|
|
|
[[maybe_unused]] constexpr bool HasPrevRef_##COUNTER_VALUE = \ |
|
|
|
std::same_as<decltype(__TmpCurrentResultReference), Result&>; \ |
|
|
|
[[maybe_unused]] auto& PrevRef_##COUNTER_VALUE = __TmpCurrentResultReference; \ |
|
|
|
[[maybe_unused]] Result __tmp_result_##COUNTER_VALUE = ResultSuccess; \ |
|
|
|
Result& __TmpCurrentResultReference = \ |
|
|
|
HasPrevRef_##COUNTER_VALUE ? PrevRef_##COUNTER_VALUE : __tmp_result_##COUNTER_VALUE |
|
|
|
|
|
|
|
#define ON_RESULT_RETURN_IMPL(...) \ |
|
|
|
static_assert(std::same_as<decltype(__TmpCurrentResultReference), Result&>); \ |
|
|
|
auto RESULT_GUARD_STATE_##__COUNTER__ = \ |
|
|
|
ResultImpl::ResultReferenceForScopedResultGuard<__VA_ARGS__>( \ |
|
|
|
__TmpCurrentResultReference) + \ |
|
|
|
[&]() |
|
|
|
|
|
|
|
#define ON_RESULT_FAILURE_2 ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateResultFailure) |
|
|
|
|
|
|
|
#define ON_RESULT_FAILURE \ |
|
|
|
DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ |
|
|
|
ON_RESULT_FAILURE_2 |
|
|
|
|
|
|
|
#define ON_RESULT_SUCCESS_2 ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateResultSuccess) |
|
|
|
|
|
|
|
#define ON_RESULT_SUCCESS \ |
|
|
|
DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ |
|
|
|
ON_RESULT_SUCCESS_2 |
|
|
|
|
|
|
|
constexpr inline Result __TmpCurrentResultReference = ResultSuccess; |
|
|
|
|
|
|
|
/// Returns a result. |
|
|
|
#define R_RETURN(res_expr) \ |
|
|
|
{ \ |
|
|
|
const Result _tmp_r_throw_rc = (res_expr); \ |
|
|
|
ResultImpl::UpdateCurrentResultReference<decltype(__TmpCurrentResultReference)>( \ |
|
|
|
__TmpCurrentResultReference, _tmp_r_throw_rc); \ |
|
|
|
return _tmp_r_throw_rc; \ |
|
|
|
} |
|
|
|
|
|
|
|
/// Returns ResultSuccess() |
|
|
|
#define R_SUCCEED() R_RETURN(ResultSuccess) |
|
|
|
|
|
|
|
/// Throws a result. |
|
|
|
#define R_THROW(res_expr) R_RETURN(res_expr) |
|
|
|
|
|
|
|
/// Evaluates a boolean expression, and returns a result unless that expression is true. |
|
|
|
#define R_UNLESS(expr, res) \ |
|
|
|
@ -361,7 +466,7 @@ private: |
|
|
|
if (res.IsError()) { \ |
|
|
|
LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \ |
|
|
|
} \ |
|
|
|
return res; \ |
|
|
|
R_THROW(res); \ |
|
|
|
} \ |
|
|
|
} |
|
|
|
|
|
|
|
@ -369,7 +474,10 @@ private: |
|
|
|
#define R_TRY(res_expr) \ |
|
|
|
{ \ |
|
|
|
const auto _tmp_r_try_rc = (res_expr); \ |
|
|
|
if (_tmp_r_try_rc.IsError()) { \ |
|
|
|
return _tmp_r_try_rc; \ |
|
|
|
if (R_FAILED(_tmp_r_try_rc)) { \ |
|
|
|
R_THROW(_tmp_r_try_rc); \ |
|
|
|
} \ |
|
|
|
} |
|
|
|
|
|
|
|
/// Evaluates a boolean expression, and succeeds if that expression is true. |
|
|
|
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess) |