diff options
-rw-r--r-- | src/core/hle/result.h | 120 |
1 files changed, 114 insertions, 6 deletions
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 47a1b829b..e20e0bfee 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -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) |