diff options
Diffstat (limited to 'src/core/hle/result.h')
-rw-r--r-- | src/core/hle/result.h | 81 |
1 files changed, 63 insertions, 18 deletions
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 3807b9aa8..47a1b829b 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -1,6 +1,5 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -112,15 +111,16 @@ enum class ErrorModule : u32 { }; /// Encapsulates a Horizon OS error code, allowing it to be separated into its constituent fields. -union ResultCode { +union Result { u32 raw; BitField<0, 9, ErrorModule> module; BitField<9, 13, u32> description; - constexpr explicit ResultCode(u32 raw_) : raw(raw_) {} + Result() = default; + constexpr explicit Result(u32 raw_) : raw(raw_) {} - constexpr ResultCode(ErrorModule module_, u32 description_) + constexpr Result(ErrorModule module_, u32 description_) : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} [[nodiscard]] constexpr bool IsSuccess() const { @@ -131,19 +131,20 @@ union ResultCode { return !IsSuccess(); } }; +static_assert(std::is_trivial_v<Result>); -[[nodiscard]] constexpr bool operator==(const ResultCode& a, const ResultCode& b) { +[[nodiscard]] constexpr bool operator==(const Result& a, const Result& b) { return a.raw == b.raw; } -[[nodiscard]] constexpr bool operator!=(const ResultCode& a, const ResultCode& b) { +[[nodiscard]] constexpr bool operator!=(const Result& a, const Result& b) { return !operator==(a, b); } // Convenience functions for creating some common kinds of errors: -/// The default success `ResultCode`. -constexpr ResultCode ResultSuccess(0); +/// The default success `Result`. +constexpr Result ResultSuccess(0); /** * Placeholder result code used for unknown error codes. @@ -151,10 +152,52 @@ constexpr ResultCode ResultSuccess(0); * @note This should only be used when a particular error code * is not known yet. */ -constexpr ResultCode ResultUnknown(UINT32_MAX); +constexpr Result ResultUnknown(UINT32_MAX); /** - * This is an optional value type. It holds a `ResultCode` and, if that code is ResultSuccess, it + * A ResultRange defines an inclusive range of error descriptions within an error module. + * This can be used to check whether the description of a given Result falls within the range. + * The conversion function returns a Result with its description set to description_start. + * + * An example of how it could be used: + * \code + * constexpr ResultRange ResultCommonError{ErrorModule::Common, 0, 9999}; + * + * Result Example(int value) { + * const Result result = OtherExample(value); + * + * // This will only evaluate to true if result.module is ErrorModule::Common and + * // result.description is in between 0 and 9999 inclusive. + * if (ResultCommonError.Includes(result)) { + * // This returns Result{ErrorModule::Common, 0}; + * return ResultCommonError; + * } + * + * return ResultSuccess; + * } + * \endcode + */ +class ResultRange { +public: + consteval ResultRange(ErrorModule module, u32 description_start, u32 description_end_) + : code{module, description_start}, description_end{description_end_} {} + + [[nodiscard]] constexpr operator Result() const { + return code; + } + + [[nodiscard]] constexpr bool Includes(Result other) const { + return code.module == other.module && code.description <= other.description && + other.description <= description_end; + } + +private: + Result code; + u32 description_end; +}; + +/** + * This is an optional value type. It holds a `Result` and, if that code is ResultSuccess, it * also holds a result of type `T`. If the code is an error code (not ResultSuccess), then trying * to access the inner value with operator* is undefined behavior and will assert with Unwrap(). * Users of this class must be cognizant to check the status of the ResultVal with operator bool(), @@ -165,7 +208,7 @@ constexpr ResultCode ResultUnknown(UINT32_MAX); * ResultVal<int> Frobnicate(float strength) { * if (strength < 0.f || strength > 1.0f) { * // Can't frobnicate too weakly or too strongly - * return ResultCode{ErrorModule::Common, 1}; + * return Result{ErrorModule::Common, 1}; * } else { * // Frobnicated! Give caller a cookie * return 42; @@ -188,7 +231,9 @@ class ResultVal { public: constexpr ResultVal() : expected{} {} - constexpr ResultVal(ResultCode code) : expected{Common::Unexpected(code)} {} + constexpr ResultVal(Result code) : expected{Common::Unexpected(code)} {} + + constexpr ResultVal(ResultRange range) : expected{Common::Unexpected(range)} {} template <typename U> constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {} @@ -208,7 +253,7 @@ public: return expected.has_value(); } - [[nodiscard]] constexpr ResultCode Code() const { + [[nodiscard]] constexpr Result Code() const { return expected.has_value() ? ResultSuccess : expected.error(); } @@ -275,8 +320,8 @@ public: } private: - // TODO: Replace this with std::expected once it is standardized in the STL. - Common::Expected<T, ResultCode> expected; + // TODO (Morph): Replace this with C++23 std::expected. + Common::Expected<T, Result> expected; }; /** @@ -293,7 +338,7 @@ private: target = std::move(*CONCAT2(check_result_L, __LINE__)) /** - * Analogous to CASCADE_RESULT, but for a bare ResultCode. The code will be propagated if + * Analogous to CASCADE_RESULT, but for a bare Result. The code will be propagated if * non-success, or discarded otherwise. */ #define CASCADE_CODE(source) \ |