Merge pull request #9034 from liamwhite/result-macros
kernel: add expanded result macros
This commit is contained in:
commit
64c2ccb0cb
1 changed files with 114 additions and 6 deletions
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue