From de13c71a0da611d53c77a2157c9a482a4513c087 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 26 Jan 2020 01:09:04 -0700 Subject: [PATCH] Add some Result XML docs --- src/LibHac/Result.cs | 69 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/LibHac/Result.cs b/src/LibHac/Result.cs index 9101d813..a189c463 100644 --- a/src/LibHac/Result.cs +++ b/src/LibHac/Result.cs @@ -6,11 +6,17 @@ using BaseType = System.UInt32; namespace LibHac { + /// + /// Represents a code used to report the result of a returned function. + /// [Serializable] - [DebuggerDisplay("{ToStringWithName(),nq}")] + [DebuggerDisplay("{" + nameof(ToStringWithName) + "(),nq}")] public struct Result : IEquatable { private const BaseType SuccessValue = default; + /// + /// The signifying success. + /// public static Result Success => new Result(SuccessValue); private static IResultLogger Logger { get; set; } @@ -31,11 +37,20 @@ namespace LibHac private readonly BaseType _value; + /// + /// Creates a new from the internal result value. + /// + /// The value used internally by . public Result(BaseType value) { _value = GetBitsValue(value, ModuleBitsOffset, ModuleBitsCount + DescriptionBitsCount); } + /// + /// Creates a new from a module and description. + /// + /// The module this result is from. Must be in the range 1 through 511. + /// The description value of the result. Must be in the range 0 through 8191. public Result(int module, int description) { Debug.Assert(ModuleBegin <= module && module < ModuleEnd, "Invalid Module"); @@ -103,6 +118,11 @@ namespace LibHac return resolver.TryResolveName(this, out name); } + /// + /// If a has been set via , attempts to + /// return the name and error code of this , otherwise it only returns . + /// + /// If a name was found, the name and error code, otherwise just the error code. public string ToStringWithName() { if (TryGetResultName(out string name)) @@ -122,11 +142,18 @@ namespace LibHac public static bool operator ==(Result left, Result right) => left.Equals(right); public static bool operator !=(Result left, Result right) => !left.Equals(right); + /// + /// Sets a to be called when is called in debug mode. + /// public static void SetLogger(IResultLogger logger) { Logger = logger; } + /// + /// Sets a that will be used by methods like + /// or to resolve the names of s. + /// public static void SetNameResolver(IResultNameResolver nameResolver) { NameResolver = nameResolver; @@ -156,13 +183,53 @@ namespace LibHac return ((uint)value & ~(~default(BaseType) << bitsCount)) << bitsOffset; } + /// + /// Represents a range of s. + /// This range is defined by a single module value and a range of description values. + /// See the documentation remarks for additional information. + /// + /// + /// Due to C# not having templates, we can't define results like Horizon and Atmosphere do. + /// Compared to those Result classes, this struct generates identical code and uses identical syntax. + ///
A Result definition should look like this: public static Result.Base PathNotFound => new Result.Base(ModuleFs, 1); + ///
Being a computed property like this will allow the compiler to do constant propagation to optimize comparisons. + ///

This is an example of how a Result should be returned from a function: return PathNotFound.Log(); + ///
The method will return the for the specified , and + /// will optionally log the returned Result when running in debug mode for easier debugging. All Result logging functionality + /// is removed from release builds. + /// If the is not being used as a return value, will get the Result without logging anything. + ///

is used to check if a provided is contained within the range of the . + /// If the is a computed property as shown above, the compiler will be able to properly optimize the code. + /// The following pairs of lines will produce the same code given Result result; + /// + /// bool a1 = ResultFs.TargetNotFound.Includes(result); // Comparing a single value + /// bool a2 = result.Value == 0x7D402; + /// + /// bool b1 = ResultFs.InsufficientFreeSpace.Includes(result); // Comparing a range of values + /// bool b2 = return result.Module == 2 && (result.Description - 30 <= 45 - 30); + /// + /// Unfortunately RyuJIT will not automatically inline the property when the compiled CIL is 16 bytes or larger as in cases like + /// new Result.Base(ModuleFs, 2000, 2499). The property will need to have the aggressive inlining flag set like so: + /// public static Result.Base SdCardAccessFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 2000, 2499); } + ///
public struct Base { private const int DescriptionEndBitsOffset = ReservedBitsOffset; private readonly ulong _value; + /// + /// Creates a Result containing a single value. + /// + /// The module this result is from. Must be in the range 1 through 511. + /// The description value of the result. Must be in the range 0 through 8191. public Base(int module, int description) : this(module, description, description) { } + /// + /// Creates a Result containing a range of values. + /// + /// The module this result is from. Must be in the range 1 through 511. + /// The inclusive start description value of the range. Must be in the range 0 through 8191. + /// The inclusive end description value of the range. Must be in the range 0 through 8191. public Base(int module, int descriptionStart, int descriptionEnd) { Debug.Assert(ModuleBegin <= module && module < ModuleEnd, "Invalid Module");