diff options
Diffstat (limited to 'src/core/hle/result.h')
| -rw-r--r-- | src/core/hle/result.h | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/src/core/hle/result.h b/src/core/hle/result.h new file mode 100644 index 000000000..15c4a2677 --- /dev/null +++ b/src/core/hle/result.h | |||
| @@ -0,0 +1,400 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cassert> | ||
| 8 | #include <cstddef> | ||
| 9 | #include <type_traits> | ||
| 10 | #include <utility> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/bit_field.h" | ||
| 14 | |||
| 15 | // All the constants in this file come from http://3dbrew.org/wiki/Error_codes | ||
| 16 | |||
| 17 | /// Detailed description of the error. This listing is likely incomplete. | ||
| 18 | enum class ErrorDescription : u32 { | ||
| 19 | Success = 0, | ||
| 20 | InvalidSection = 1000, | ||
| 21 | TooLarge = 1001, | ||
| 22 | NotAuthorized = 1002, | ||
| 23 | AlreadyDone = 1003, | ||
| 24 | InvalidSize = 1004, | ||
| 25 | InvalidEnumValue = 1005, | ||
| 26 | InvalidCombination = 1006, | ||
| 27 | NoData = 1007, | ||
| 28 | Busy = 1008, | ||
| 29 | MisalignedAddress = 1009, | ||
| 30 | MisalignedSize = 1010, | ||
| 31 | OutOfMemory = 1011, | ||
| 32 | NotImplemented = 1012, | ||
| 33 | InvalidAddress = 1013, | ||
| 34 | InvalidPointer = 1014, | ||
| 35 | InvalidHandle = 1015, | ||
| 36 | NotInitialized = 1016, | ||
| 37 | AlreadyInitialized = 1017, | ||
| 38 | NotFound = 1018, | ||
| 39 | CancelRequested = 1019, | ||
| 40 | AlreadyExists = 1020, | ||
| 41 | OutOfRange = 1021, | ||
| 42 | Timeout = 1022, | ||
| 43 | InvalidResultValue = 1023, | ||
| 44 | }; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Identifies the module which caused the error. Error codes can be propagated through a call | ||
| 48 | * chain, meaning that this doesn't always correspond to the module where the API call made is | ||
| 49 | * contained. | ||
| 50 | */ | ||
| 51 | enum class ErrorModule : u32 { | ||
| 52 | Common = 0, | ||
| 53 | Kernel = 1, | ||
| 54 | Util = 2, | ||
| 55 | FileServer = 3, | ||
| 56 | LoaderServer = 4, | ||
| 57 | TCB = 5, | ||
| 58 | OS = 6, | ||
| 59 | DBG = 7, | ||
| 60 | DMNT = 8, | ||
| 61 | PDN = 9, | ||
| 62 | GX = 10, | ||
| 63 | I2C = 11, | ||
| 64 | GPIO = 12, | ||
| 65 | DD = 13, | ||
| 66 | CODEC = 14, | ||
| 67 | SPI = 15, | ||
| 68 | PXI = 16, | ||
| 69 | FS = 17, | ||
| 70 | DI = 18, | ||
| 71 | HID = 19, | ||
| 72 | CAM = 20, | ||
| 73 | PI = 21, | ||
| 74 | PM = 22, | ||
| 75 | PM_LOW = 23, | ||
| 76 | FSI = 24, | ||
| 77 | SRV = 25, | ||
| 78 | NDM = 26, | ||
| 79 | NWM = 27, | ||
| 80 | SOC = 28, | ||
| 81 | LDR = 29, | ||
| 82 | ACC = 30, | ||
| 83 | RomFS = 31, | ||
| 84 | AM = 32, | ||
| 85 | HIO = 33, | ||
| 86 | Updater = 34, | ||
| 87 | MIC = 35, | ||
| 88 | FND = 36, | ||
| 89 | MP = 37, | ||
| 90 | MPWL = 38, | ||
| 91 | AC = 39, | ||
| 92 | HTTP = 40, | ||
| 93 | DSP = 41, | ||
| 94 | SND = 42, | ||
| 95 | DLP = 43, | ||
| 96 | HIO_LOW = 44, | ||
| 97 | CSND = 45, | ||
| 98 | SSL = 46, | ||
| 99 | AM_LOW = 47, | ||
| 100 | NEX = 48, | ||
| 101 | Friends = 49, | ||
| 102 | RDT = 50, | ||
| 103 | Applet = 51, | ||
| 104 | NIM = 52, | ||
| 105 | PTM = 53, | ||
| 106 | MIDI = 54, | ||
| 107 | MC = 55, | ||
| 108 | SWC = 56, | ||
| 109 | FatFS = 57, | ||
| 110 | NGC = 58, | ||
| 111 | CARD = 59, | ||
| 112 | CARDNOR = 60, | ||
| 113 | SDMC = 61, | ||
| 114 | BOSS = 62, | ||
| 115 | DBM = 63, | ||
| 116 | Config = 64, | ||
| 117 | PS = 65, | ||
| 118 | CEC = 66, | ||
| 119 | IR = 67, | ||
| 120 | UDS = 68, | ||
| 121 | PL = 69, | ||
| 122 | CUP = 70, | ||
| 123 | Gyroscope = 71, | ||
| 124 | MCU = 72, | ||
| 125 | NS = 73, | ||
| 126 | News = 74, | ||
| 127 | RO_1 = 75, | ||
| 128 | GD = 76, | ||
| 129 | CardSPI = 77, | ||
| 130 | EC = 78, | ||
| 131 | RO_2 = 79, | ||
| 132 | WebBrowser = 80, | ||
| 133 | Test = 81, | ||
| 134 | ENC = 82, | ||
| 135 | PIA = 83, | ||
| 136 | |||
| 137 | Application = 254, | ||
| 138 | InvalidResult = 255 | ||
| 139 | }; | ||
| 140 | |||
| 141 | /// A less specific error cause. | ||
| 142 | enum class ErrorSummary : u32 { | ||
| 143 | Success = 0, | ||
| 144 | NothingHappened = 1, | ||
| 145 | WouldBlock = 2, | ||
| 146 | OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to | ||
| 147 | ///< execute the operation. | ||
| 148 | NotFound = 4, ///< A file or resource was not found. | ||
| 149 | InvalidState = 5, | ||
| 150 | NotSupported = 6, ///< The operation is not supported or not implemented. | ||
| 151 | InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime | ||
| 152 | ///< context. (Invalid handle, out-of-bounds pointer or size, etc.) | ||
| 153 | WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use | ||
| 154 | ///< with the function. (E.g. Invalid enum value) | ||
| 155 | Canceled = 9, | ||
| 156 | StatusChanged = 10, | ||
| 157 | Internal = 11, | ||
| 158 | |||
| 159 | InvalidResult = 63 | ||
| 160 | }; | ||
| 161 | |||
| 162 | /// The severity of the error. | ||
| 163 | enum class ErrorLevel : u32 { | ||
| 164 | Success = 0, | ||
| 165 | Info = 1, | ||
| 166 | |||
| 167 | Status = 25, | ||
| 168 | Temporary = 26, | ||
| 169 | Permanent = 27, | ||
| 170 | Usage = 28, | ||
| 171 | Reinitialize = 29, | ||
| 172 | Reset = 30, | ||
| 173 | Fatal = 31 | ||
| 174 | }; | ||
| 175 | |||
| 176 | /// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields. | ||
| 177 | union ResultCode { | ||
| 178 | u32 raw; | ||
| 179 | |||
| 180 | BitField<0, 10, ErrorDescription> description; | ||
| 181 | BitField<10, 8, ErrorModule> module; | ||
| 182 | |||
| 183 | BitField<21, 6, ErrorSummary> summary; | ||
| 184 | BitField<27, 5, ErrorLevel> level; | ||
| 185 | |||
| 186 | // The last bit of `level` is checked by apps and the kernel to determine if a result code is an error | ||
| 187 | BitField<31, 1, u32> is_error; | ||
| 188 | |||
| 189 | explicit ResultCode(u32 raw) : raw(raw) {} | ||
| 190 | ResultCode(ErrorDescription description_, ErrorModule module_, | ||
| 191 | ErrorSummary summary_, ErrorLevel level_) : raw(0) { | ||
| 192 | description = description_; | ||
| 193 | module = module_; | ||
| 194 | summary = summary_; | ||
| 195 | level = level_; | ||
| 196 | } | ||
| 197 | |||
| 198 | ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; } | ||
| 199 | |||
| 200 | bool IsSuccess() const { | ||
| 201 | return is_error == 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | bool IsError() const { | ||
| 205 | return is_error == 1; | ||
| 206 | } | ||
| 207 | }; | ||
| 208 | |||
| 209 | inline bool operator==(const ResultCode a, const ResultCode b) { | ||
| 210 | return a.raw == b.raw; | ||
| 211 | } | ||
| 212 | |||
| 213 | inline bool operator!=(const ResultCode a, const ResultCode b) { | ||
| 214 | return a.raw != b.raw; | ||
| 215 | } | ||
| 216 | |||
| 217 | // Convenience functions for creating some common kinds of errors: | ||
| 218 | |||
| 219 | /// The default success `ResultCode`. | ||
| 220 | const ResultCode RESULT_SUCCESS(0); | ||
| 221 | |||
| 222 | /// Might be returned instead of a dummy success for unimplemented APIs. | ||
| 223 | inline ResultCode UnimplementedFunction(ErrorModule module) { | ||
| 224 | return ResultCode(ErrorDescription::NotImplemented, module, | ||
| 225 | ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||
| 226 | } | ||
| 227 | /// Returned when a function is passed an invalid handle. | ||
| 228 | inline ResultCode InvalidHandle(ErrorModule module) { | ||
| 229 | return ResultCode(ErrorDescription::InvalidHandle, module, | ||
| 230 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, | ||
| 235 | * also holds a result of type `T`. If the code is an error code then trying to access the inner | ||
| 236 | * value fails, thus ensuring that the ResultCode of functions is always checked properly before | ||
| 237 | * their return value is used. It is similar in concept to the `std::optional` type | ||
| 238 | * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in | ||
| 239 | * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html). | ||
| 240 | * | ||
| 241 | * An example of how it could be used: | ||
| 242 | * \code | ||
| 243 | * ResultVal<int> Frobnicate(float strength) { | ||
| 244 | * if (strength < 0.f || strength > 1.0f) { | ||
| 245 | * // Can't frobnicate too weakly or too strongly | ||
| 246 | * return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common, | ||
| 247 | * ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 248 | * } else { | ||
| 249 | * // Frobnicated! Give caller a cookie | ||
| 250 | * return MakeResult<int>(42); | ||
| 251 | * } | ||
| 252 | * } | ||
| 253 | * \endcode | ||
| 254 | * | ||
| 255 | * \code | ||
| 256 | * ResultVal<int> frob_result = Frobnicate(0.75f); | ||
| 257 | * if (frob_result) { | ||
| 258 | * // Frobbed ok | ||
| 259 | * printf("My cookie is %d\n", *frob_result); | ||
| 260 | * } else { | ||
| 261 | * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex); | ||
| 262 | * } | ||
| 263 | * \endcode | ||
| 264 | */ | ||
| 265 | template <typename T> | ||
| 266 | class ResultVal { | ||
| 267 | public: | ||
| 268 | /// Constructs an empty `ResultVal` with the given error code. The code must not be a success code. | ||
| 269 | ResultVal(ResultCode error_code = ResultCode(-1)) | ||
| 270 | : result_code(error_code) | ||
| 271 | { | ||
| 272 | assert(error_code.IsError()); | ||
| 273 | UpdateDebugPtr(); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * Similar to the non-member function `MakeResult`, with the exception that you can manually | ||
| 278 | * specify the success code. `success_code` must not be an error code. | ||
| 279 | */ | ||
| 280 | template <typename... Args> | ||
| 281 | static ResultVal WithCode(ResultCode success_code, Args&&... args) { | ||
| 282 | ResultVal<T> result; | ||
| 283 | result.emplace(success_code, std::forward<Args>(args)...); | ||
| 284 | return result; | ||
| 285 | } | ||
| 286 | |||
| 287 | ResultVal(const ResultVal& o) | ||
| 288 | : result_code(o.result_code) | ||
| 289 | { | ||
| 290 | if (!o.empty()) { | ||
| 291 | new (&storage) T(*o.GetPointer()); | ||
| 292 | } | ||
| 293 | UpdateDebugPtr(); | ||
| 294 | } | ||
| 295 | |||
| 296 | ResultVal(ResultVal&& o) | ||
| 297 | : result_code(o.result_code) | ||
| 298 | { | ||
| 299 | if (!o.empty()) { | ||
| 300 | new (&storage) T(std::move(*o.GetPointer())); | ||
| 301 | } | ||
| 302 | UpdateDebugPtr(); | ||
| 303 | } | ||
| 304 | |||
| 305 | ~ResultVal() { | ||
| 306 | if (!empty()) { | ||
| 307 | GetPointer()->~T(); | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | ResultVal& operator=(const ResultVal& o) { | ||
| 312 | if (*this) { | ||
| 313 | if (o) { | ||
| 314 | *GetPointer() = *o.GetPointer(); | ||
| 315 | } else { | ||
| 316 | GetPointer()->~T(); | ||
| 317 | } | ||
| 318 | } else { | ||
| 319 | if (o) { | ||
| 320 | new (&storage) T(*o.GetPointer()); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | result_code = o.result_code; | ||
| 324 | UpdateDebugPtr(); | ||
| 325 | |||
| 326 | return *this; | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * Replaces the current result with a new constructed result value in-place. The code must not | ||
| 331 | * be an error code. | ||
| 332 | */ | ||
| 333 | template <typename... Args> | ||
| 334 | void emplace(ResultCode success_code, Args&&... args) { | ||
| 335 | assert(success_code.IsSuccess()); | ||
| 336 | if (!empty()) { | ||
| 337 | GetPointer()->~T(); | ||
| 338 | } | ||
| 339 | new (&storage) T(std::forward<Args>(args)...); | ||
| 340 | result_code = success_code; | ||
| 341 | UpdateDebugPtr(); | ||
| 342 | } | ||
| 343 | |||
| 344 | /// Returns true if the `ResultVal` contains an error code and no value. | ||
| 345 | bool empty() const { return result_code.IsError(); } | ||
| 346 | |||
| 347 | /// Returns true if the `ResultVal` contains a return value. | ||
| 348 | bool Succeeded() const { return result_code.IsSuccess(); } | ||
| 349 | /// Returns true if the `ResultVal` contains an error code and no value. | ||
| 350 | bool Failed() const { return empty(); } | ||
| 351 | |||
| 352 | ResultCode Code() const { return result_code; } | ||
| 353 | |||
| 354 | const T& operator* () const { return *GetPointer(); } | ||
| 355 | T& operator* () { return *GetPointer(); } | ||
| 356 | const T* operator->() const { return GetPointer(); } | ||
| 357 | T* operator->() { return GetPointer(); } | ||
| 358 | |||
| 359 | /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. | ||
| 360 | template <typename U> | ||
| 361 | T ValueOr(U&& value) const { | ||
| 362 | return !empty() ? *GetPointer() : std::move(value); | ||
| 363 | } | ||
| 364 | |||
| 365 | private: | ||
| 366 | typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; | ||
| 367 | |||
| 368 | StorageType storage; | ||
| 369 | ResultCode result_code; | ||
| 370 | #if _DEBUG | ||
| 371 | // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the | ||
| 372 | // need to cast `storage` to a pointer or pay attention to `result_code`. | ||
| 373 | const T* debug_ptr; | ||
| 374 | #endif | ||
| 375 | |||
| 376 | void UpdateDebugPtr() { | ||
| 377 | #if _DEBUG | ||
| 378 | debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage)); | ||
| 379 | #endif | ||
| 380 | } | ||
| 381 | |||
| 382 | const T* GetPointer() const { | ||
| 383 | assert(!empty()); | ||
| 384 | return static_cast<const T*>(static_cast<const void*>(&storage)); | ||
| 385 | } | ||
| 386 | |||
| 387 | T* GetPointer() { | ||
| 388 | assert(!empty()); | ||
| 389 | return static_cast<T*>(static_cast<void*>(&storage)); | ||
| 390 | } | ||
| 391 | }; | ||
| 392 | |||
| 393 | /** | ||
| 394 | * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct | ||
| 395 | * `T` with and creates a success `ResultVal` contained the constructed value. | ||
| 396 | */ | ||
| 397 | template <typename T, typename... Args> | ||
| 398 | ResultVal<T> MakeResult(Args&&... args) { | ||
| 399 | return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); | ||
| 400 | } | ||