11using ObjectLayoutInspector ;
2+ using System . Diagnostics ;
3+ using System . Diagnostics . CodeAnalysis ;
4+ using System . Runtime . CompilerServices ;
25using System . Runtime . InteropServices ;
36
47namespace StructTest ;
@@ -8,7 +11,7 @@ internal static class StructTest
811
912 #region Constants & Statics
1013
11- public static void Test ( )
14+ public static void Simple_Test ( )
1215 {
1316 var box = new BoxStruct ( false , 0 , new InnerStruct ( 100 , true ) ) ;
1417
@@ -63,8 +66,15 @@ public static void Test()
6366
6467 #endregion
6568
69+ public static void Complex_Test ( )
70+ {
71+ var r = new Result < BaseError > ( new BaseError ( ) ) ;
72+ TypeLayout . PrintLayout ( r . GetType ( ) , true ) ;
73+ }
6674}
6775
76+ #region Simple Structs
77+
6878[ StructLayout ( LayoutKind . Sequential ) ]
6979public readonly record struct BoxStruct
7080{
@@ -93,3 +103,221 @@ public InnerStruct(int intField, bool boolField)
93103 _boolField = boolField ;
94104 }
95105}
106+
107+ #endregion
108+
109+ #region Complex
110+
111+ //[StructLayout(LayoutKind.Auto, Pack = 1)]
112+ [ StructLayout ( LayoutKind . Sequential , Pack = 1 ) ]
113+ [ SuppressMessage ( "Style" , "IDE1006:Naming Styles" , Justification = "<Pending>" ) ]
114+ public readonly record struct Result < TError >
115+ where TError : struct
116+ {
117+
118+ #region Constants & Statics
119+
120+ /// <summary>
121+ /// No errors, just return.
122+ /// </summary>
123+ private static readonly Result < TError > Ok = new ( true ) ;
124+
125+ #endregion
126+
127+ /// <summary>
128+ /// Gets the error.
129+ /// </summary>
130+ internal readonly TError _error ;
131+
132+ internal readonly bool _hasError ;
133+
134+ #pragma warning disable IDE0060 // Remove unused parameter
135+ private Result ( bool isOk )
136+ #pragma warning restore IDE0060 // Remove unused parameter
137+ {
138+ // just use for Ok
139+ _hasError = false ;
140+ }
141+
142+ /// <summary>
143+ /// Initializes a new instance of the <see cref="Result{TError}"/> with default <typeparamref name="TError"/>.
144+ /// </summary>
145+ public Result ( ) : this ( new TError ( ) )
146+ {
147+ }
148+
149+ /// <summary>
150+ /// Initializes a new instance of the <see cref="Result{TData, TError}"/> with error.
151+ /// The result is failed.
152+ /// </summary>
153+ /// <param name="error">The error.</param>
154+ public Result ( in TError error )
155+ {
156+ _error = error ;
157+ _hasError = true ;
158+ }
159+
160+ #region Methods
161+
162+ [ UnscopedRef ]
163+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
164+ internal ref readonly TError UnwrapErrorWithoutCheck ( )
165+ {
166+ Debug . Assert ( _hasError , $ "{ nameof ( _hasError ) } is true") ;
167+ return ref _error ;
168+ }
169+
170+ /// <summary>
171+ /// Determines whether this instance is error.
172+ /// </summary>
173+ /// <returns>
174+ /// <c>true</c> if this instance is error; otherwise <c>false</c>.
175+ /// </returns>
176+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
177+ public readonly bool IsError ( )
178+ {
179+ return _hasError ;
180+ }
181+
182+ /// <summary>
183+ /// Determines whether this instance is error.
184+ /// </summary>
185+ /// <returns>
186+ /// <c>true</c> if this instance is error, and error must not be null; otherwise, <c>false</c>.
187+ /// </returns>
188+ [ SuppressMessage (
189+ "Critical Code Smell" ,
190+ "S3874:\" out\" and \" ref\" parameters should not be used" ,
191+ Justification = "<Pending>" ) ]
192+ public readonly bool IsError ( [ NotNullWhen ( true ) ] out TError ? error )
193+ {
194+ error = null ;
195+
196+ if ( _hasError )
197+ {
198+ error = _error ;
199+ return true ;
200+ }
201+
202+ return false ;
203+ }
204+
205+ #endregion
206+
207+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
208+ public static implicit operator Result < TError > ( in TError error ) => new ( in error ) ;
209+ }
210+
211+ //[StructLayout(LayoutKind.Auto, Pack = 1)]
212+ [ StructLayout ( LayoutKind . Sequential , Pack = 1 ) ]
213+ public readonly record struct BaseError ( BaseErrorCode Code , string ? Reason = null /*, Exception? Exception = null*/ )
214+ //: IBaseError<BaseError, BaseErrorCode>
215+ {
216+ public BaseError ( ) : this ( BaseErrorCode . Failed )
217+ {
218+ }
219+
220+ #region IBaseError implementations
221+
222+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
223+ public static Result < BaseError > Result ( BaseErrorCode code , string ? reason = null , Exception ? exception = null )
224+ {
225+ return new BaseError ( code , reason /*, exception*/ ) ;
226+ }
227+
228+ #endregion
229+
230+ #region IError implementations
231+
232+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
233+ public static Result < BaseError > Result ( )
234+ {
235+ return new BaseError ( ) ;
236+ }
237+
238+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
239+ public static Result < BaseError > Result ( BaseErrorCode code )
240+ {
241+ return new BaseError ( code ) ;
242+ }
243+
244+ #endregion
245+
246+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
247+ public static implicit operator BaseError ( BaseErrorCode errorCode ) => new ( errorCode ) ;
248+ }
249+
250+ public interface IError < TError , TCode >
251+ where TError : struct
252+ {
253+
254+ #region Constants & Statics
255+
256+ /// <summary>
257+ /// Create a default result.
258+ /// </summary>
259+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
260+ public static abstract Result < TError > Result ( ) ;
261+
262+ /// <summary>
263+ /// Create a result with the specified code.
264+ /// </summary>
265+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
266+ public static abstract Result < TError > Result ( TCode code ) ;
267+
268+ #endregion
269+
270+ #region Properties
271+
272+ /// <summary>
273+ /// Gets the error code.
274+ /// </summary>
275+ public TCode Code { get ; }
276+
277+ #endregion
278+
279+ }
280+
281+ public interface IBaseError < TError , TCode > : IError < TError , TCode >
282+ where TError : struct
283+ {
284+
285+ #region Constants & Statics
286+
287+ /// <summary>
288+ /// Create a result with the specified code, reason and exception.
289+ /// </summary>
290+ /// <param name="code">The code.</param>
291+ /// <param name="reason">The reason.</param>
292+ /// <param name="exception">The exception.</param>
293+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
294+ public static abstract Result < TError > Result ( TCode code , string ? reason = null , Exception ? exception = null ) ;
295+
296+ #endregion
297+
298+ #region Properties
299+
300+ /// <summary>
301+ /// Gets the exception.
302+ /// </summary>
303+ public Exception ? Exception { get ; }
304+
305+ /// <summary>
306+ /// Gets the reason.
307+ /// </summary>
308+ public string ? Reason { get ; }
309+
310+ #endregion
311+
312+ }
313+
314+ public enum BaseErrorCode
315+ {
316+ Failure = 0 ,
317+
318+ Failed = 10 ,
319+
320+ NotFound = 99
321+ }
322+
323+ #endregion
0 commit comments