// Copyright 2014 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include "common/assert.h" #include "common/bit_field.h" #include "common/common_types.h" // All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes /** * Identifies the module which caused the error. Error codes can be propagated through a call * chain, meaning that this doesn't always correspond to the module where the API call made is * contained. */ enum class ErrorModule : u32 { Common = 0, Kernel = 1, FS = 2, OS = 3, // used for Memory, Thread, Mutex, Nvidia HTCS = 4, NCM = 5, DD = 6, LR = 8, Loader = 9, CMIF = 10, HIPC = 11, PM = 15, NS = 16, HTC = 18, NCMContent = 20, SM = 21, RO = 22, SDMMC = 24, OVLN = 25, SPL = 26, ETHC = 100, I2C = 101, GPIO = 102, UART = 103, Settings = 105, WLAN = 107, XCD = 108, NIFM = 110, Hwopus = 111, Bluetooth = 113, VI = 114, NFP = 115, Time = 116, FGM = 117, OE = 118, PCIe = 120, Friends = 121, BCAT = 122, SSLSrv = 123, Account = 124, News = 125, Mii = 126, NFC = 127, AM = 128, PlayReport = 129, AHID = 130, Qlaunch = 132, PCV = 133, OMM = 134, BPC = 135, PSM = 136, NIM = 137, PSC = 138, TC = 139, USB = 140, NSD = 141, PCTL = 142, BTM = 143, ETicket = 145, NGC = 146, ERPT = 147, APM = 148, Profiler = 150, ErrorUpload = 151, Audio = 153, NPNS = 154, NPNSHTTPSTREAM = 155, ARP = 157, SWKBD = 158, BOOT = 159, NFCMifare = 161, UserlandAssert = 162, Fatal = 163, NIMShop = 164, SPSM = 165, BGTC = 167, UserlandCrash = 168, SREPO = 180, Dauth = 181, HID = 202, LDN = 203, Irsensor = 205, Capture = 206, Manu = 208, ATK = 209, GRC = 212, Migration = 216, MigrationLdcServ = 217, GeneralWebApplet = 800, WifiWebAuthApplet = 809, WhitelistedApplet = 810, ShopN = 811, }; /// Encapsulates a Horizon OS error code, allowing it to be separated into its constituent fields. union ResultCode { u32 raw; BitField<0, 9, ErrorModule> module; BitField<9, 13, u32> description; constexpr explicit ResultCode(u32 raw_) : raw(raw_) {} constexpr ResultCode(ErrorModule module_, u32 description_) : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} [[nodiscard]] constexpr bool IsSuccess() const { return raw == 0; } [[nodiscard]] constexpr bool IsError() const { return !IsSuccess(); } }; [[nodiscard]] constexpr bool operator==(const ResultCode& a, const ResultCode& b) { return a.raw == b.raw; } [[nodiscard]] constexpr bool operator!=(const ResultCode& a, const ResultCode& b) { return !operator==(a, b); } // Convenience functions for creating some common kinds of errors: /// The default success `ResultCode`. constexpr ResultCode ResultSuccess(0); /** * Placeholder result code used for unknown error codes. * * @note This should only be used when a particular error code * is not known yet. */ constexpr ResultCode ResultUnknown(UINT32_MAX); /** * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, * also holds a result of type `T`. If the code is an error code then trying to access the inner * value fails, thus ensuring that the ResultCode of functions is always checked properly before * their return value is used. It is similar in concept to the `std::optional` type * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html). * * An example of how it could be used: * \code * ResultVal Frobnicate(float strength) { * if (strength < 0.f || strength > 1.0f) { * // Can't frobnicate too weakly or too strongly * return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common, * ErrorSummary::InvalidArgument, ErrorLevel::Permanent); * } else { * // Frobnicated! Give caller a cookie * return MakeResult(42); * } * } * \endcode * * \code * ResultVal frob_result = Frobnicate(0.75f); * if (frob_result) { * // Frobbed ok * printf("My cookie is %d\n", *frob_result); * } else { * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex); * } * \endcode */ template class ResultVal { public: /// Constructs an empty `ResultVal` with the given error code. The code must not be a success /// code. ResultVal(ResultCode error_code = ResultUnknown) : result_code(error_code) { ASSERT(error_code.IsError()); } /** * Similar to the non-member function `MakeResult`, with the exception that you can manually * specify the success code. `success_code` must not be an error code. */ template [[nodiscard]] static ResultVal WithCode(ResultCode success_code, Args&&... args) { ResultVal result; result.emplace(success_code, std::forward(args)...); return result; } ResultVal(const ResultVal& o) noexcept : result_code(o.result_code) { if (!o.empty()) { new (&object) T(o.object); } } ResultVal(ResultVal&& o) noexcept : result_code(o.result_code) { if (!o.empty()) { new (&object) T(std::move(o.object)); } } ~ResultVal() { if (!empty()) { object.~T(); } } ResultVal& operator=(const ResultVal& o) noexcept { if (this == &o) { return *this; } if (!empty()) { if (!o.empty()) { object = o.object; } else { object.~T(); } } else { if (!o.empty()) { new (&object) T(o.object); } } result_code = o.result_code; return *this; } ResultVal& operator=(ResultVal&& o) noexcept { if (this == &o) { return *this; } if (!empty()) { if (!o.empty()) { object = std::move(o.object); } else { object.~T(); } } else { if (!o.empty()) { new (&object) T(std::move(o.object)); } } result_code = o.result_code; return *this; } /** * Replaces the current result with a new constructed result value in-place. The code must not * be an error code. */ template void emplace(ResultCode success_code, Args&&... args) { ASSERT(success_code.IsSuccess()); if (!empty()) { object.~T(); } new (&object) T(std::forward(args)...); result_code = success_code; } /// Returns true if the `ResultVal` contains an error code and no value. [[nodiscard]] bool empty() const { return result_code.IsError(); } /// Returns true if the `ResultVal` contains a return value. [[nodiscard]] bool Succeeded() const { return result_code.IsSuccess(); } /// Returns true if the `ResultVal` contains an error code and no value. [[nodiscard]] bool Failed() const { return empty(); } [[nodiscard]] ResultCode Code() const { return result_code; } [[nodiscard]] const T& operator*() const { return object; } [[nodiscard]] T& operator*() { return object; } [[nodiscard]] const T* operator->() const { return &object; } [[nodiscard]] T* operator->() { return &object; } /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. template [[nodiscard]] T ValueOr(U&& value) const { return !empty() ? object : std::move(value); } /// Asserts that the result succeeded and returns a reference to it. [[nodiscard]] T& Unwrap() & { ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); return **this; } [[nodiscard]] T&& Unwrap() && { ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); return std::move(**this); } private: // A union is used to allocate the storage for the value, while allowing us to construct and // destruct it at will. union { T object; }; ResultCode result_code; }; /** * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct * `T` with and creates a success `ResultVal` contained the constructed value. */ template [[nodiscard]] ResultVal MakeResult(Args&&... args) { return ResultVal::WithCode(ResultSuccess, std::forward(args)...); } /** * Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just * copy or move constructing. */ template [[nodiscard]] ResultVal> MakeResult(Arg&& arg) { return ResultVal>::WithCode(ResultSuccess, std::forward(arg)); } /** * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps * the contained value and assigns it to `target`, which can be either an l-value expression or a * variable declaration. If it fails the return code is returned from the current function. Thus it * can be used to cascade errors out, achieving something akin to exception handling. */ #define CASCADE_RESULT(target, source) \ auto CONCAT2(check_result_L, __LINE__) = source; \ if (CONCAT2(check_result_L, __LINE__).Failed()) { \ return CONCAT2(check_result_L, __LINE__).Code(); \ } \ target = std::move(*CONCAT2(check_result_L, __LINE__)) /** * Analogous to CASCADE_RESULT, but for a bare ResultCode. The code will be propagated if * non-success, or discarded otherwise. */ #define CASCADE_CODE(source) \ do { \ auto CONCAT2(check_result_L, __LINE__) = source; \ if (CONCAT2(check_result_L, __LINE__).IsError()) { \ return CONCAT2(check_result_L, __LINE__); \ } \ } while (false) #define R_SUCCEEDED(res) (res.IsSuccess()) /// Evaluates a boolean expression, and succeeds if that expression is true. #define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess) /// Evaluates a boolean expression, and returns a result unless that expression is true. #define R_UNLESS(expr, res) \ { \ if (!(expr)) { \ if (res.IsError()) { \ LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \ } \ return res; \ } \ } /// Evaluates an expression that returns a result, and returns the result if it would fail. #define R_TRY(res_expr) \ { \ const auto _tmp_r_try_rc = (res_expr); \ if (_tmp_r_try_rc.IsError()) { \ return _tmp_r_try_rc; \ } \ }