From f45d4166ebe2e86bdce9044cb9e643fab328b71f Mon Sep 17 00:00:00 2001
From: Alex Barney <thealexbarney@gmail.com>
Date: Sun, 9 Jun 2019 11:25:00 -0500
Subject: [PATCH] Add HorizonResultException

---
 src/LibHac/Fs/ResultsFs.cs           | 11 ++++
 src/LibHac/HorizonResultException.cs | 79 ++++++++++++++++++++++++++++
 src/LibHac/MissingKeyException.cs    |  3 ++
 src/LibHac/Result.cs                 |  6 ++-
 src/LibHac/ThrowHelper.cs            |  8 +++
 5 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 src/LibHac/Fs/ResultsFs.cs
 create mode 100644 src/LibHac/HorizonResultException.cs
 create mode 100644 src/LibHac/ThrowHelper.cs

diff --git a/src/LibHac/Fs/ResultsFs.cs b/src/LibHac/Fs/ResultsFs.cs
new file mode 100644
index 00000000..92a20d0c
--- /dev/null
+++ b/src/LibHac/Fs/ResultsFs.cs
@@ -0,0 +1,11 @@
+namespace LibHac.Fs
+{
+    public class ResultsFs
+    {
+        public const int ModuleFs = 2;
+
+        public static Result ResultFsMountNameAlreadyExists => new Result(ModuleFs, 60);
+        public static Result ResultFsWritableFileOpen => new Result(ModuleFs, 6457);
+        public static Result ResultFsMountNameNotFound => new Result(ModuleFs, 6905);
+    }
+}
diff --git a/src/LibHac/HorizonResultException.cs b/src/LibHac/HorizonResultException.cs
new file mode 100644
index 00000000..136e7709
--- /dev/null
+++ b/src/LibHac/HorizonResultException.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace LibHac
+{
+    [Serializable]
+    public class HorizonResultException : LibHacException, ISerializable
+    {
+        /// <summary>
+        /// The result code of the error.
+        /// </summary>
+        public Result ResultValue { get; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HorizonResultException"/> class. 
+        /// </summary>
+        /// <param name="result">The result code for the reason for the exception.</param>
+        public HorizonResultException(Result result)
+        {
+            ResultValue = result;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HorizonResultException"/> class with a specified error message.
+        /// </summary>
+        /// <param name="result">The result code for the reason for the exception.</param>
+        /// <param name="message">The error message that explains the reason for the exception.</param>
+        public HorizonResultException(Result result, string message)
+            : base(message)
+        {
+            ResultValue = result;
+        }
+
+        /// <summary>
+        ///  Initializes a new instance of the <see cref="HorizonResultException"/> class with a specified error message
+        ///  and a reference to the inner exception that is the cause of this exception.
+        /// </summary>
+        /// <param name="result">The result code for the reason for the exception.</param>
+        /// <param name="message">The error message that explains the reason for the exception.</param>
+        /// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
+        public HorizonResultException(Result result, string message, Exception innerException)
+            : base(message, innerException)
+        {
+            ResultValue = result;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MissingKeyException"/> class with serialized data.
+        /// </summary>
+        /// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
+        /// <param name="context">The <see cref="StreamingContext"/>  that contains contextual information about the source or destination.</param>
+        protected HorizonResultException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        {
+            ResultValue = (Result)info.GetValue(nameof(ResultValue), ResultValue.GetType());
+        }
+
+        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            base.GetObjectData(info, context);
+            info.AddValue(nameof(ResultValue), ResultValue);
+        }
+
+        public override string Message
+        {
+            get
+            {
+                string baseMessage = base.Message;
+
+                if (!string.IsNullOrWhiteSpace(baseMessage))
+                {
+                    return $"{ResultValue.ErrorCode}: {baseMessage}";
+                }
+
+                return ResultValue.ErrorCode;
+            }
+        }
+    }
+}
diff --git a/src/LibHac/MissingKeyException.cs b/src/LibHac/MissingKeyException.cs
index f9272dc9..806785c9 100644
--- a/src/LibHac/MissingKeyException.cs
+++ b/src/LibHac/MissingKeyException.cs
@@ -68,12 +68,15 @@ namespace LibHac
         protected MissingKeyException(SerializationInfo info, StreamingContext context)
             : base(info, context)
         {
+            Name = info.GetString(nameof(Name));
+            Type = (KeyType)info.GetValue(nameof(Type), Type.GetType());
         }
 
         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
         {
             base.GetObjectData(info, context);
             info.AddValue(nameof(Name), Name);
+            info.AddValue(nameof(Type), Type);
         }
 
         public override string Message
diff --git a/src/LibHac/Result.cs b/src/LibHac/Result.cs
index d21cddde..a9bf220d 100644
--- a/src/LibHac/Result.cs
+++ b/src/LibHac/Result.cs
@@ -1,5 +1,8 @@
-namespace LibHac
+using System;
+
+namespace LibHac
 {
+    [Serializable]
     public struct Result
     {
         public readonly int Value;
@@ -16,6 +19,7 @@
 
         public int Description => (Value >> 9) & 0x1FFF;
         public int Module => Value & 0x1FF;
+        public string ErrorCode => $"{2000 + Module:d4}-{Description:d4}";
 
         public bool IsSuccess() => Value == 0;
         public bool IsFailure() => Value != 0;
diff --git a/src/LibHac/ThrowHelper.cs b/src/LibHac/ThrowHelper.cs
new file mode 100644
index 00000000..2a642fcb
--- /dev/null
+++ b/src/LibHac/ThrowHelper.cs
@@ -0,0 +1,8 @@
+namespace LibHac
+{
+    internal static class ThrowHelper
+    {
+        public static void ThrowResult(Result result) => throw new HorizonResultException(result);
+        public static void ThrowResult(Result result, string message) => throw new HorizonResultException(result, message);
+    }
+}