aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Horizon.Common/Result.cs
blob: 4b120b847b82484555f5c3777e9c6c0df6366c66 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System;

namespace Ryujinx.Horizon.Common
{
    public struct Result : IEquatable<Result>
    {
        private const int ModuleBits = 9;
        private const int DescriptionBits = 13;
        private const int ModuleMax = 1 << ModuleBits;
        private const int DescriptionMax = 1 << DescriptionBits;

        public static Result Success { get; } = new Result(0, 0);

        public int ErrorCode { get; }

        public readonly bool IsSuccess => ErrorCode == 0;
        public readonly bool IsFailure => ErrorCode != 0;

        public readonly int Module => ErrorCode & (ModuleMax - 1);
        public readonly int Description => (ErrorCode >> ModuleBits) & (DescriptionMax - 1);

        public readonly string PrintableResult => $"{2000 + Module:D4}-{Description:D4}";

        public Result(int module, int description)
        {
            if ((uint)module >= ModuleMax)
            {
                throw new ArgumentOutOfRangeException(nameof(module));
            }

            if ((uint)description >= DescriptionMax)
            {
                throw new ArgumentOutOfRangeException(nameof(description));
            }

            ErrorCode = module | (description << ModuleBits);
        }

        public Result(int errorCode)
        {
            ErrorCode = errorCode;
        }

        public readonly override bool Equals(object obj)
        {
            return obj is Result result && result.Equals(this);
        }

        public readonly bool Equals(Result other)
        {
            return other.ErrorCode == ErrorCode;
        }

        public readonly override int GetHashCode()
        {
            return ErrorCode;
        }

        public static bool operator ==(Result lhs, Result rhs)
        {
            return lhs.Equals(rhs);
        }

        public static bool operator !=(Result lhs, Result rhs)
        {
            return !lhs.Equals(rhs);
        }

        public readonly bool InRange(int minInclusive, int maxInclusive)
        {
            return (uint)(Description - minInclusive) <= (uint)(maxInclusive - minInclusive);
        }

        public void AbortOnSuccess()
        {
            if (IsSuccess)
            {
                ThrowInvalidResult();
            }
        }

        public void AbortOnFailure()
        {
            if (this == KernelResult.ThreadTerminating)
            {
                throw new ThreadTerminatedException();
            }

            AbortUnless(Success);
        }

        public void AbortUnless(Result result)
        {
            if (this != result)
            {
                ThrowInvalidResult();
            }
        }

        public void AbortUnless(Result result, Result result2)
        {
            if (this != result && this != result2)
            {
                ThrowInvalidResult();
            }
        }

        private void ThrowInvalidResult()
        {
            throw new InvalidResultException(this);
        }

        public readonly override string ToString()
        {
            if (ResultNames.TryGet(ErrorCode, out string name))
            {
                return name;
            }

            return PrintableResult;
        }
    }
}