aboutsummaryrefslogtreecommitdiff
path: root/lib/Utils/src/ERRNO.cs
blob: 0a957801363dd42ffaa4831257c7c7a271b8a1b9 (plain)
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
* Copyright (c) 2024 Vaughn Nugent
* 
* Library: VNLib
* Package: VNLib.Utils
* File: ERRNO.cs 
*
* ERRNO.cs is part of VNLib.Utils which is part of the larger 
* VNLib collection of libraries and utilities.
*
* VNLib.Utils is free software: you can redistribute it and/or modify 
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License,
* or (at your option) any later version.
*
* VNLib.Utils is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License 
* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
*/

using System;
using System.Runtime.InteropServices;

namespace VNLib.Utils
{
    /// <summary>
    /// Implements a C style integer error code type. Size is platform dependent
    /// </summary>
    /// <remarks>
    /// Creates a new <see cref="ERRNO"/> from the specified error value
    /// </remarks>
    /// <param name="errno">The value of the error to represent</param>
    [StructLayout(LayoutKind.Sequential)]
    public readonly struct ERRNO(nint errno) : IEquatable<ERRNO>, ISpanFormattable, IFormattable
    {
        /// <summary>
        /// Represents a successfull error code (true)
        /// </summary>
        public static readonly ERRNO SUCCESS = true;

        /// <summary>
        /// Represents a failure error code (false)
        /// </summary>
        public static readonly ERRNO E_FAIL = false;
        
        private readonly nint ErrorCode = errno;

        /// <summary>
        /// Creates a new <see cref="ERRNO"/> from an <see cref="int"/> error code. null = 0 = false
        /// </summary>
        /// <param name="errorVal">Error code</param>
        public static implicit operator ERRNO(int errorVal) => new (errorVal);

        /// <summary>
        /// Creates a new <see cref="ERRNO"/> from an <see cref="int"/> error code. null = 0 = false
        /// </summary>
        /// <param name="errorVal">Error code</param>
        public static explicit operator ERRNO(int? errorVal) => new(errorVal ?? 0);

        /// <summary>
        /// Creates a new <see cref="ERRNO"/> from a booleam, 1 if true, 0 if false
        /// </summary>
        /// <param name="errorVal"></param>
        public static implicit operator ERRNO(bool errorVal) => new(errorVal ? 1 : 0);

        /// <summary>
        /// Creates a new <see cref="ERRNO"/> from a pointer value
        /// </summary>
        /// <param name="errno">The pointer value representing an error code</param>
        public static implicit operator ERRNO(nint errno) => new(errno);

        /// <summary>
        /// Error value as integer. Value of supplied error code or if cast from boolean 1 if true, 0 if false
        /// </summary>
        /// <param name="errorVal"><see cref="ERRNO"/> to get error code from</param>
        public static implicit operator int(ERRNO errorVal) => (int)errorVal.ErrorCode;

        /// <summary>
        /// C style boolean conversion. false if 0, true otherwise 
        /// </summary>
        /// <param name="errorVal"></param>
        public static implicit operator bool(ERRNO errorVal) => errorVal != 0;   

        /// <summary>
        /// Creates a new <c>nint</c> from the value if the stored error code 
        /// </summary>
        /// <param name="errno">The <see cref="ERRNO"/> contating the pointer value</param>
        public static implicit operator nint(ERRNO errno) => errno.ErrorCode;

        /// <summary>
        /// Compares the value of this error code to another and returns true if they are equal
        /// </summary>
        /// <param name="other">The value to compare</param>
        /// <returns>True if the ERRNO value is equal to the current value</returns>
        public readonly bool Equals(ERRNO other) => ErrorCode == other.ErrorCode;

        /// <summary>
        /// Compares the value of this error code to another and returns true if they are equal. 
        /// You should avoid this overload as it will box the value type.
        /// </summary>
        /// <param name="obj">The instance to compare</param>
        /// <returns>True if the ERRNO value is equal to the current value</returns>
        public readonly override bool Equals(object? obj) => obj is ERRNO other && Equals(other);

        /// <summary>
        /// Returns the hash code of the underlying value
        /// </summary>
        /// <returns>The hashcode of the current value</returns>
        public readonly override int GetHashCode() => ErrorCode.GetHashCode();

        /// <summary>
        /// Attempts to parse the value of the character sequence as a new error code
        /// </summary>
        /// <param name="value">The character sequence value to parse</param>
        /// <param name="result">The value </param>
        /// <returns>True if the value was successfully parsed, false othwerwise</returns>
        public static bool TryParse(ReadOnlySpan<char> value, out ERRNO result)
        {
            result = 0;
            if (nint.TryParse(value, out nint res))
            {
                result = new ERRNO(res);
                return true;
            }
            return false;
        }
#pragma warning disable CA1305 // Specify IFormatProvider

        /// <summary>
        /// The integer error value of the current instance in radix 10
        /// </summary>
        /// <returns>The radix 10 formatted error code</returns>

        public override readonly string ToString() => ErrorCode.ToString();
        /// <summary>
        /// Formats the internal nint error code as a string in specified format
        /// </summary>
        /// <param name="format">The format to use</param>
        /// <returns>The formatted error code</returns>
        public readonly string ToString(string format) => ErrorCode.ToString(format);

#pragma warning restore CA1305 // Specify IFormatProvider

        ///<inheritdoc/>
        public readonly bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) 
            => ErrorCode.TryFormat(destination, out charsWritten, format, provider);

        ///<inheritdoc/>
        public readonly string ToString(string? format, IFormatProvider? formatProvider) 
            => ErrorCode.ToString(format, formatProvider);

        public static ERRNO operator +(ERRNO err, int add) => new(err.ErrorCode + add);
        public static ERRNO operator +(ERRNO err, nint add) => new(err.ErrorCode + add);
        public static ERRNO operator ++(ERRNO err) => new(err.ErrorCode + 1);
        public static ERRNO operator --(ERRNO err) => new(err.ErrorCode - 1);
        public static ERRNO operator -(ERRNO err, int subtract) => new(err.ErrorCode - subtract);
        public static ERRNO operator -(ERRNO err, nint subtract) => new(err.ErrorCode - subtract);

        public static bool operator >(ERRNO err, ERRNO other) => err.ErrorCode > other.ErrorCode;
        public static bool operator <(ERRNO err, ERRNO other) => err.ErrorCode < other.ErrorCode;
        public static bool operator >=(ERRNO err, ERRNO other) => err.ErrorCode >= other.ErrorCode;
        public static bool operator <=(ERRNO err, ERRNO other) => err.ErrorCode <= other.ErrorCode;

        public static bool operator >(ERRNO err, int other) => err.ErrorCode > other;
        public static bool operator <(ERRNO err, int other) => err.ErrorCode < other;
        public static bool operator >=(ERRNO err, int other) => err.ErrorCode >= other;
        public static bool operator <=(ERRNO err, int other) => err.ErrorCode <= other;

        public static bool operator >(ERRNO err, nint other) => err.ErrorCode > other;
        public static bool operator <(ERRNO err, nint other) => err.ErrorCode < other;
        public static bool operator >=(ERRNO err, nint other) => err.ErrorCode >= other;
        public static bool operator <=(ERRNO err, nint other) => err.ErrorCode <= other;

        public static bool operator ==(ERRNO err, ERRNO other) => err.ErrorCode == other.ErrorCode;
        public static bool operator !=(ERRNO err, ERRNO other) => err.ErrorCode != other.ErrorCode;
        public static bool operator ==(ERRNO err, int other) => err.ErrorCode == other;
        public static bool operator !=(ERRNO err, int other) => err.ErrorCode != other;
        public static bool operator ==(ERRNO err, nint other) => err.ErrorCode == other;
        public static bool operator !=(ERRNO err, nint other) => err.ErrorCode != other;

        
    }
}