1 /*---------------------------------------------------------------------------*
2 
3   Copyright (C) 2012 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 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
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 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 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 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 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 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 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 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