1 /*---------------------------------------------------------------------------* 2 3 Copyright (C) Nintendo. All rights reserved. 4 5 These coded instructions, statements, and computer programs contain 6 proprietary information of Nintendo of America Inc. and/or Nintendo 7 Company Ltd., and are protected by Federal copyright law. They may 8 not be disclosed to third parties or copied or duplicated in any form, 9 in whole or in part, without the prior written consent of Nintendo. 10 11 *---------------------------------------------------------------------------*/ 12 13 /*! 14 @file 15 @brief These are <tt>Result</tt> class declarations. 16 17 :include nn/Result.h 18 */ 19 20 #ifndef NN_RESULT_H__ 21 #define NN_RESULT_H__ 22 23 #include <nn/types.h> 24 25 //------------------------------------------------------------------- 26 // For C / C++ 27 28 /* 29 @addtogroup nn_root 30 @{ 31 */ 32 33 /* 34 @defgroup nn_Result_c Result (C) 35 36 @brief C interface module for <tt>nn::Result</tt>, which indicates the result of an operation. 37 38 @{ 39 */ 40 41 42 #ifdef __cplusplus 43 extern "C" { 44 #endif // ifdef __cplusplus 45 46 /* 47 @brief Structure that indicates the result of an operation. Used by C member functions. 48 */ 49 typedef struct nnResult 50 { 51 bit32 value; 52 } 53 nnResult; 54 55 #ifdef __cplusplus 56 } 57 #endif // ifdef __cplusplus 58 59 /* 60 } 61 */ 62 /* 63 } 64 */ 65 66 67 //------------------------------------------------------------------- 68 // For C++ 69 70 #ifdef __cplusplus 71 72 namespace nn { 73 74 /*! 75 @brief Class that indicates the result of an operation. 76 77 Functions in the <tt>@ref nn</tt> namespace return instances of the <tt>@ref nn::Result</tt> class. 78 79 For information about the handling of the <tt>Result</tt> codes returned by the different libraries, see the library and API reference manuals. 80 This section gives a general description of handling <tt>Result</tt> codes. 81 82 83 @section descriptionOfValues Description of Values 84 85 <tt>Result</tt> contains a 32-bit value that includes information about the error level, the module where the error occurred, and the error type. 86 This information is only used to determine the cause of problems during debugging, and must not be used in any error handling code in the application. 87 A future SDK update will provide details on how to get this information. 88 89 90 @section hierarchy Hierarchy 91 92 The result values defined by each library are organized in a hierarchy, with each <tt>Result</tt> object potentially having parents and children. 93 In error handling, a higher-level <tt>Result</tt> code is regarded as including the lower-level <tt>Result</tt> codes. 94 95 This hierarchical organization makes it possible to identify the causes of errors by coding error handling using the less numerous high-level <tt>Result</tt> codes, and then referring to the more numerous low-level <tt>Result</tt> codes during debugging. 96 97 This resembles the exception inheritance mechanics used in C++ and other languages. 98 99 Use the <tt><=</tt> and <tt>>=</tt> operators or the <tt>Includes</tt> member function to determine inclusion. 100 101 @section exampleOfErrorHandling Example of Error Handling 102 103 The following sample code shows typical error handling using <tt>Result</tt> codes. 104 105 \code 106 107 nn::Result result = nn::lib::SomeApi(); 108 109 if( result.IsFailure() ) 110 { 111 if( result <= nn::lib::ResultNotFound() ) 112 { 113 // Code would branch from here for all errors that occur when something is not found. 114 // Using file access as an example, this could apply to <tt>ResultDirectoryNotFound</tt> or <tt>ResultFileNotFound</tt>. 115 } 116 else if( result <= nn::lib::ResultConnectionError() ) 117 { 118 // Code would branch from here for all connection errors. 119 // Using server access as an example, this could apply to errors caused when a server cannot be found or when there is no response from the server. 120 } 121 else 122 { 123 // Code would branch from here for all other errors. 124 125 // Code would presumably branch from here when individual error handling is not required, or when an unexpected error is returned. 126 127 // Handling differs by library, but there are two basic approaches. 128 // - Inform the user of failure, and return to the previous sequence. 129 // - A fatal system problem might have occurred. Display an error and halt the application. 130 } 131 } 132 133 \endcode 134 135 Note the following. 136 137 @subsection identifyingExecutionFailures Identifying Execution Failures 138 139 System updates might define additional result values that were not defined when an application was developed. In such cases, you can call the <tt>nn::Result::IsSuccess</tt> and <tt>nn::Result::IsFailure</tt> functions to determine whether a process succeeded or failed. 140 141 We recommend not just using matching result values without also checking for success, as this entails the risk of falsely determining success in cases of unexpected errors. 142 143 @subsection explicitlySpecifyingNamespaces Explicitly Specifying Namespaces 144 145 Some result codes are defined with the same names but different values in different libraries. Always specify the namespace explicitly so that your application does not mishandle unexpected errors. 146 147 @subsection determiningInclusion Determining Inclusion 148 149 Use the following method to determine the definition of each result and what it includes. 150 151 @code 152 if(result <= nn::fs::ResultNotFound()) 153 { 154 // This can also catch <tt>nn::fs::ResultMediaNotFound</tt>. 155 } 156 @endcode 157 158 @code 159 if(nn::fs::ResultNotFound::Includes(result)) 160 { 161 ... 162 } 163 @endcode 164 165 @code 166 if(nn::fs::ResultNotFound() >= result) 167 { 168 ... 169 } 170 @endcode 171 172 @attention Do not directly handle any <tt>Result</tt> codes not mentioned in the API Reference. 173 174 @section errorsNotAllowedInRetailProducts Errors Not Allowed in Retail Products 175 176 The following <tt>Result</tt> codes indicate errors caused by application bugs or other problems. 177 You must fix your program so that none of these errors occur in retail products. 178 179 <tt>Result</tt> codes other than these may be caused by user operations or may be impossible to entirely eliminate during development. You must handle any errors that can be caused by the user. 180 For more information, see the API Reference. 181 182 @section handlingUnexpectedErrors Handling Unexpected Errors 183 184 System updates might define additional result values that were not defined when an application was developed. 185 You almost always need to implement code to handle unexpected errors. 186 187 For more information about handling, see the reference materials for the relevant libraries. 188 We recommend contacting support if no handling method is described in the documentation. 189 190 @section unrecoverableFatalErrors Unrecoverable Fatal Errors 191 192 A <I>fatal error</I> is an error caused by a hardware bug or another error that should not arise in the retail product. The system cannot recover from such an error and there is no means of handling the error. 193 194 As a general rule, when a fatal error occurs, the error is not passed to the application but instead the system halts and displays FATAL ERROR on the screen. When this error occurs, check the manual according to the message that displays. If the problem cannot be resolved, contact Nintendo Support as a last resort. 195 196 The system just halts if it cannot even display the error. 197 198 */ 199 class Result 200 { 201 202 private: 203 static const bit32 MASK_FAIL_BIT = 0x80000000u; // Most Significant Bit 204 205 static const s32 SIZE_DESCRIPTION = 20; 206 static const s32 SIZE_MODULE = 9; 207 static const s32 SIZE_LEVEL = 3; 208 209 static const s32 SHIFTS_DESCRIPTION = 0; 210 static const s32 SHIFTS_MODULE = SHIFTS_DESCRIPTION + SIZE_DESCRIPTION; 211 static const s32 SHIFTS_LEVEL = SHIFTS_MODULE + SIZE_MODULE; 212 //NN_STATIC_ASSERT( SHIFTS_LEVEL + SIZE_LEVEL == 32 ); 213 214 static const u32 MASK_NEGATIVE_LEVEL = (~0u) << SIZE_LEVEL; 215 216 #define NN_RESULT_H_MAKE_MASK(size, shift) (((~0u) >> (32 - (size))) << (shift)) 217 #define NN_RESULT_H_MAKE_MASK_HELPER(c) \ 218 static const u32 MASK_ ## c = NN_RESULT_H_MAKE_MASK(SIZE_ ## c, SHIFTS_ ## c) 219 NN_RESULT_H_MAKE_MASK_HELPER(DESCRIPTION); 220 NN_RESULT_H_MAKE_MASK_HELPER(MODULE); 221 NN_RESULT_H_MAKE_MASK_HELPER(LEVEL); 222 #undef NN_RESULT_H_MAKE_MASK_HELPER 223 #undef NN_RESULT_H_MAKE_MASK 224 225 #define NN_RESULT_H_MAKE_MAX(size) ((~0u) >> (32 - (size))) 226 #define NN_RESULT_H_MAKE_MAX_HELPER(c) \ 227 static const s32 MAX_ ## c = NN_RESULT_H_MAKE_MAX(SIZE_ ## c) 228 NN_RESULT_H_MAKE_MAX_HELPER(DESCRIPTION); 229 NN_RESULT_H_MAKE_MAX_HELPER(MODULE); 230 NN_RESULT_H_MAKE_MAX_HELPER(LEVEL); 231 #undef NN_RESULT_H_MAKE_MAX_HELPER 232 #undef NN_RESULT_H_MAKE_MAX 233 234 public: 235 /* 236 * @brief Enumeration type indicating the severity of an error. (Do not use this type for error handling.) 237 */ 238 enum LevelImpl 239 { 240 LEVEL_SUCCESS = 0, 241 LEVEL_FATAL = -1, 242 LEVEL_USAGE = -2, 243 LEVEL_STATUS = -3, 244 245 LEVEL_END = -7 246 }; 247 typedef int Level; 248 249 enum 250 { 251 MODULE_APPLICATION = MAX_MODULE - 1, // These values are not used. 252 MODULE_INVALID_RESULT_VALUE = MAX_MODULE // These values are not used. 253 }; 254 255 /* 256 * @brief Enumeration type that indicates the details of errors. (Do not use this type for error handling.) 257 */ 258 enum 259 { 260 DESCRIPTION_SUCCESS = 0, // Succeeded. 261 DESCRIPTION_INVALID_RESULT_VALUE = MAX_DESCRIPTION - 0 // These values are not used. 262 }; 263 264 private: 265 266 u32 m_Code; 267 268 friend struct ResultSuccess; 269 template <Result::Level TLevel, int TModule, int TDescription> friend struct ConstRangeBase; Result(u32 code)270 explicit Result(u32 code) : m_Code(code) {} 271 272 public: Result()273 Result() 274 : m_Code( static_cast<u32>( 275 ((static_cast<u32>(MAX_LEVEL) << SHIFTS_LEVEL) & MASK_LEVEL) | 276 ((static_cast<u32>(MAX_MODULE) << SHIFTS_MODULE) & MASK_MODULE) | 277 ((static_cast<u32>(MAX_DESCRIPTION) << SHIFTS_DESCRIPTION) & MASK_DESCRIPTION) )) 278 { 279 } 280 Result(Level level,int module,int description)281 Result(Level level, int module, int description) 282 : m_Code( static_cast<u32>( 283 ((static_cast<u32>(level) << SHIFTS_LEVEL) & MASK_LEVEL) | 284 ((static_cast<u32>(module) << SHIFTS_MODULE) & MASK_MODULE) | 285 ((static_cast<u32>(description) << SHIFTS_DESCRIPTION) & MASK_DESCRIPTION) )) 286 { 287 /* 288 NN_ASSERT(-3 <= level && level <= 0); 289 NN_ASSERT(0 <= module && module < MAX_MODULE); 290 NN_ASSERT(0 <= description && description < MAX_DESCRIPTION); 291 */ 292 } 293 Result(nnResult result)294 Result(nnResult result) : m_Code(result.value) {} 295 /*! 296 @name Determinations 297 @{ 298 */ 299 /*! 300 * @brief Returns <tt>true</tt> if the operation failed, or <tt>false</tt> if it succeeded. 301 */ IsFailure()302 bool IsFailure() const 303 { 304 return (m_Code & MASK_FAIL_BIT) != 0; 305 } 306 307 /*! 308 * @brief Returns <tt>true</tt> if the operation succeeded, or <tt>false</tt> if it failed. 309 */ IsSuccess()310 bool IsSuccess() const 311 { 312 return !IsFailure(); 313 } 314 /*! 315 @} 316 */ 317 /* 318 * @brief Returns a <tt>Level</tt> enumerated type indicating the severity of the error. 319 * 320 * Enumeration type definitions will change in the future. Do not use them for any purpose other than checking the content of errors during development. 321 */ GetLevel()322 Level GetLevel() const 323 { 324 // TODO: Create a platform-dependent arithmetic shift inline function and call it. 325 u32 level; 326 if ( IsLegacy() ) 327 { 328 level = GetLegacyLevel(); 329 } 330 else 331 { 332 level = GetCodeBits(MASK_LEVEL, SHIFTS_LEVEL); 333 } 334 335 if(m_Code & MASK_FAIL_BIT) 336 { 337 return static_cast<Level>( level | MASK_NEGATIVE_LEVEL); 338 } 339 else 340 { 341 return static_cast<Level>( level ); 342 } 343 } 344 345 /* 346 * @brief Returns a <tt>Module</tt> enumerated type indicating the module in which the error occurred. 347 * 348 * Enumeration type definitions will change in the future. Do not use them for any purpose other than checking the content of errors during development. 349 */ GetModule()350 int GetModule() const 351 { 352 if ( IsLegacy() ) 353 { 354 return GetLegacyModule(); 355 } 356 else 357 { 358 return GetCodeBits(MASK_MODULE, SHIFTS_MODULE); 359 } 360 } 361 362 /* 363 * @brief Returns a <tt>Description</tt> enumeration type indicating the details of the error. 364 * 365 * Enumeration type definitions will change in the future. Do not use them for any purpose other than checking the content of errors during development. 366 */ GetDescription()367 int GetDescription() const 368 { 369 if(IsLegacy()) 370 { 371 return GetLegacyDescription(); 372 } 373 else 374 { 375 return static_cast<int>( GetCodeBits(MASK_DESCRIPTION, SHIFTS_DESCRIPTION) ); 376 } 377 } 378 GetValue()379 u32 GetValue() const { return m_Code; } 380 nnResult()381 operator nnResult() const 382 { 383 nnResult r = {m_Code}; 384 return r; 385 } 386 387 /*! 388 @name Development Support 389 @{ 390 */ 391 /*! 392 * @brief Converts a <tt>Result</tt> code into a 32-bit array. 393 */ GetPrintableBits()394 u32 GetPrintableBits() const { return m_Code; } 395 396 /*! 397 @} 398 */ 399 /* 400 @name Determinations 401 @{ 402 */ 403 /* 404 * @brief Checks for equality. 405 * 406 * Use to handle some errors for libraries other than <tt>@ref nn::fs</tt>. For information about error handling in <tt>@ref nn::fs</tt>, see the <tt>@ref nn::fs</tt> library reference. 407 * 408 * 409 * @param[in] rhs Specifies the right-hand operand. 410 * @return Returns <tt>true</tt> if the operands are equal, and <tt>false</tt> otherwise. 411 */ 412 bool operator ==(const Result& rhs) const { return this->m_Code == rhs.m_Code; } 413 414 /* 415 * @brief Checks for inequality. 416 * 417 * Use to handle some errors for libraries other than <tt>@ref nn::fs</tt>. For information about error handling in <tt>@ref nn::fs</tt>, see the <tt>@ref nn::fs</tt> library reference. 418 * 419 * 420 * @param[in] rhs Specifies the right-hand operand. 421 * @return Returns <tt>true</tt> if the operands are not equal, and <tt>false</tt> otherwise. 422 */ 423 bool operator !=(const Result& rhs) const { return this->m_Code != rhs.m_Code; } 424 /*! 425 @} 426 */ 427 428 template <Result::Level TLevel, int TModule, int TDescription> struct ConstRangeBase; 429 template <Result::Level TLevel, int TModule, int TDescription, int TDescriptionStart, int TDescriptionEnd> struct ConstRange; 430 template <class Result1, class Result2> struct ConstRangePlus; 431 432 #include "./Result.legacy.inclass.h" 433 434 private: GetCodeBits(u32 mask,s32 shift)435 u32 GetCodeBits(u32 mask, s32 shift) const 436 { 437 return ((m_Code & mask) >> shift); 438 } 439 }; 440 441 struct ResultSuccess 442 { ResultResultSuccess443 operator Result() const { return Result(0); } nnResultResultSuccess444 operator nnResult() const { return Result(0); } 445 }; 446 447 template <Result::Level TLevel, int TModule, int TDescription> 448 struct Result::ConstRangeBase 449 { 450 static const Result::Level Level = TLevel; 451 static const int Module = TModule; 452 static const int Description = TDescription; 453 454 static const u32 Value = static_cast<u32>( 455 ((static_cast<u32>(TLevel) << SHIFTS_LEVEL) & MASK_LEVEL) | 456 ((TModule << SHIFTS_MODULE) & MASK_MODULE) | 457 ((TDescription << SHIFTS_DESCRIPTION) & MASK_DESCRIPTION) ); 458 ResultConstRangeBase459 operator Result() const { return Result(Value); } nnResultConstRangeBase460 operator nnResult() const { return Result(Value); } 461 462 }; 463 464 template <Result::Level TLevel, int TModule> 465 struct Result::ConstRangeBase<TLevel, TModule, -1> 466 { 467 static const Result::Level Level = TLevel; 468 static const int Module = TModule; 469 }; 470 471 template <Result::Level TLevel, int TModule, int TDescription, int TDescriptionStart, int TDescriptionEnd> 472 struct Result::ConstRange : public Result::ConstRangeBase<TLevel, TModule, TDescription> 473 { 474 static const int DescriptionStart = TDescriptionStart; 475 static const int DescriptionEnd = TDescriptionEnd; 476 477 static bool Includes(Result result) 478 { 479 return result.GetModule() == TModule && (TDescriptionStart <= result.GetDescription() && result.GetDescription() < TDescriptionEnd); 480 } 481 482 friend bool operator<=(Result lhs, const ConstRange&) { return ConstRange::Includes(lhs); } 483 friend bool operator>=(const ConstRange&, Result rhs) { return ConstRange::Includes(rhs); } 484 485 template <Result::Level TLevel2, int TModule2, int TDescription2, int TDescriptionStart2, int TDescriptionEnd2> 486 friend Result::ConstRangePlus< 487 Result::ConstRange<TLevel, TModule, TDescription, TDescriptionStart, TDescriptionEnd>, 488 Result::ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2> > 489 operator+(const Result::ConstRange<TLevel, TModule, TDescription, TDescriptionStart, TDescriptionEnd>&, 490 const Result::ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2>&) 491 { 492 return Result::ConstRangePlus< 493 Result::ConstRange<TLevel, TModule, TDescription, TDescriptionStart, TDescriptionEnd>, 494 Result::ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2> >(); 495 } 496 }; 497 498 template <class Result1, class Result2> 499 struct Result::ConstRangePlus 500 { 501 static bool Includes(Result result) { return Result1::Includes(result) || Result2::Includes(result); } 502 friend bool operator<=(Result lhs, const ConstRangePlus&) { return ConstRangePlus::Includes(lhs); } 503 friend bool operator>=(const ConstRangePlus&, Result rhs) { return ConstRangePlus::Includes(rhs); } 504 505 template <class Result3, class Result4> 506 friend Result::ConstRangePlus<ConstRangePlus, Result::ConstRangePlus<Result3, Result4> > operator+(const Result::ConstRangePlus<Result1, Result2>&, const Result::ConstRangePlus<Result3, Result4>&) { return ConstRangePlus<ConstRangePlus<Result1, Result2>, ConstRangePlus<Result3, Result4> >(); } 507 508 template <Result::Level TLevel2, int TModule2, int TDescription2, int TDescriptionStart2, int TDescriptionEnd2> 509 friend Result::ConstRangePlus<ConstRangePlus, Result::ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2> > operator+(const Result::ConstRangePlus<Result1, Result2>&, const ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2>&) { return ConstRangePlus<ConstRangePlus, Result::ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2> >(); } 510 511 template <Result::Level TLevel2, int TModule2, int TDescription2, int TDescriptionStart2, int TDescriptionEnd2> 512 friend Result::ConstRangePlus<ConstRangePlus, Result::ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2> > operator+(const Result::ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2>&, const Result::ConstRangePlus<Result1, Result2>&) { return ConstRangePlus<ConstRangePlus, ConstRange<TLevel2, TModule2, TDescription2, TDescriptionStart2, TDescriptionEnd2> >(); } 513 }; 514 515 #include "./Result.legacy.h" 516 517 } 518 519 #define NN_DEFINE_RESULT_CONST_RANGE(name, level, module, description, descriptionMin, descriptionMax) \ 520 typedef ::nn::Result::ConstRange<(level), (module), (description), (descriptionMin), (descriptionMax)> name 521 522 #define NN_RESULT_THROW_IF_FAILED(result) \ 523 do \ 524 { \ 525 ::nn::Result _nn_result_throw_if_failed_tmp_ = (result); \ 526 if (_nn_result_throw_if_failed_tmp_.IsFailure()) \ 527 { \ 528 return _nn_result_throw_if_failed_tmp_; \ 529 } \ 530 } while(0) 531 532 #define NN_RESULT_RETURN(value) \ 533 do \ 534 { \ 535 *pOut = (value); \ 536 return ::nn::ResultSuccess(); \ 537 } while (0) 538 539 #define NN_RESULT_SUCCESS \ 540 do \ 541 { \ 542 return ::nn::ResultSuccess(); \ 543 } while (0) 544 545 #define NN_RESULT_THROW(result) return (result) 546 547 #define NN_RESULT_THROW_UNLESS(cond, result) \ 548 if (cond) {} else NN_RESULT_THROW(result) 549 550 #define NN_RESULT_TRY(result) { ::nn::Result _nn_result_try_tmp_ = (result); if (0) {} 551 # define NN_RESULT_CATCH(type) else if (_nn_result_try_tmp_ <= type()) 552 # define NN_RESULT_CATCH_ALL else if (_nn_result_try_tmp_.IsFailure()) 553 # define NN_RESULT_RETHROW NN_RESULT_THROW(_nn_result_try_tmp_) 554 #define NN_RESULT_END_TRY NN_RESULT_CATCH_ALL NN_RESULT_RETHROW; } 555 556 #endif // __cplusplus 557 558 #endif /* NN_RESULT_H_ */ 559