|
@@ -5,6 +5,7 @@
|
|
|
|
|
|
|
|
#include "common/assert.h"
|
|
#include "common/assert.h"
|
|
|
#include "common/bit_field.h"
|
|
#include "common/bit_field.h"
|
|
|
|
|
+#include "common/common_funcs.h"
|
|
|
#include "common/common_types.h"
|
|
#include "common/common_types.h"
|
|
|
#include "common/expected.h"
|
|
#include "common/expected.h"
|
|
|
|
|
|
|
@@ -130,6 +131,10 @@ union Result {
|
|
|
[[nodiscard]] constexpr bool IsError() const {
|
|
[[nodiscard]] constexpr bool IsError() const {
|
|
|
return !IsSuccess();
|
|
return !IsSuccess();
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ [[nodiscard]] constexpr bool IsFailure() const {
|
|
|
|
|
+ return !IsSuccess();
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
static_assert(std::is_trivial_v<Result>);
|
|
static_assert(std::is_trivial_v<Result>);
|
|
|
|
|
|
|
@@ -349,10 +354,110 @@ private:
|
|
|
} \
|
|
} \
|
|
|
} while (false)
|
|
} 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.
|
|
/// Evaluates a boolean expression, and returns a result unless that expression is true.
|
|
|
#define R_UNLESS(expr, res) \
|
|
#define R_UNLESS(expr, res) \
|
|
@@ -361,7 +466,7 @@ private:
|
|
|
if (res.IsError()) { \
|
|
if (res.IsError()) { \
|
|
|
LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \
|
|
LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \
|
|
|
} \
|
|
} \
|
|
|
- return res; \
|
|
|
|
|
|
|
+ R_THROW(res); \
|
|
|
} \
|
|
} \
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -369,7 +474,10 @@ private:
|
|
|
#define R_TRY(res_expr) \
|
|
#define R_TRY(res_expr) \
|
|
|
{ \
|
|
{ \
|
|
|
const auto _tmp_r_try_rc = (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)
|