7
7
8
8
namespace DotNext ;
9
9
10
+ using System ;
11
+ using DotNext . Threading . Tasks ;
10
12
using Runtime . CompilerServices ;
11
13
using Intrinsics = Runtime . Intrinsics ;
12
14
@@ -68,17 +70,6 @@ public static class Result
68
70
/// <returns>The value encapsulated by <see cref="Result{T}"/>.</returns>
69
71
public static Result < T > FromValue < T > ( T value ) => new ( value ) ;
70
72
71
- /// <summary>
72
- /// Creates a new instance of <see cref="Result{T}"/> from the specified value.
73
- /// </summary>
74
- /// <typeparam name="T">The type of the value.</typeparam>
75
- /// <typeparam name="TError">The type of the error code. Default value must represent the successful result.</typeparam>
76
- /// <param name="value">The value to be placed to the container.</param>
77
- /// <returns>The value encapsulated by <see cref="Result{T, TError}"/>.</returns>
78
- public static Result < T , TError > FromValue < T , TError > ( T value )
79
- where TError : struct , Enum
80
- => new ( value ) ;
81
-
82
73
/// <summary>
83
74
/// Creates a new instance of <see cref="Result{T}"/> from the specified exception.
84
75
/// </summary>
@@ -98,6 +89,30 @@ public static Result<T, TError> FromError<T, TError>(TError e)
98
89
where TError : struct , Enum
99
90
=> new ( e ) ;
100
91
92
+ private static AwaitableResult < TResult > TransformAwaitableResult < T , TResult > ( this AwaitableResult < T > task , Converter < Result < T > , Result < TResult > > converter )
93
+ {
94
+ async Task < TResult > ConvertInternal ( )
95
+ {
96
+ var result = await task . ConfigureAwait ( false ) ;
97
+ var conversionResult = converter ( result ) ;
98
+ return conversionResult . IsSuccessful ? conversionResult . Value : throw conversionResult . Error ;
99
+ }
100
+
101
+ return ConvertInternal ( ) . SuspendException ( ) ;
102
+ }
103
+
104
+ private static AwaitableResult < TResult > TransformAwaitableResult < T , TResult > ( this AwaitableResult < T > task , Converter < Result < T > , AwaitableResult < TResult > > converter )
105
+ {
106
+ async Task < TResult > ConvertInternal ( )
107
+ {
108
+ var result = await task . ConfigureAwait ( false ) ;
109
+ var conversionResult = await converter ( result ) ;
110
+ return conversionResult . IsSuccessful ? conversionResult . Value : throw conversionResult . Error ;
111
+ }
112
+
113
+ return ConvertInternal ( ) . SuspendException ( ) ;
114
+ }
115
+
101
116
/// <summary>
102
117
/// If successful result is present, apply the provided mapping function hiding any exception
103
118
/// caused by the converter.
@@ -107,8 +122,8 @@ public static Result<T, TError> FromError<T, TError>(TError e)
107
122
/// <typeparam name="T">The type of the value.</typeparam>
108
123
/// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
109
124
/// <returns>The conversion result.</returns>
110
- public static async Task < Result < TResult > > Convert < T , TResult > ( this Task < Result < T > > task , Converter < T , TResult > converter )
111
- => ( await task . ConfigureAwait ( false ) ) . Convert ( converter ) ;
125
+ public static AwaitableResult < TResult > Convert < T , TResult > ( this AwaitableResult < T > task , Converter < T , TResult > converter )
126
+ => task . TransformAwaitableResult ( ( result ) => result . Convert ( converter ) ) ;
112
127
113
128
/// <summary>
114
129
/// If successful result is present, apply the provided mapping function. If not,
@@ -119,8 +134,8 @@ public static async Task<Result<TResult>> Convert<T, TResult>(this Task<Result<T
119
134
/// <typeparam name="T">The type of the value.</typeparam>
120
135
/// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
121
136
/// <returns>The conversion result.</returns>
122
- public static async Task < Result < TResult > > Convert < T , TResult > ( this Task < Result < T > > task , Converter < T , Result < TResult > > converter )
123
- => ( await task . ConfigureAwait ( false ) ) . Convert ( converter ) ;
137
+ public static AwaitableResult < TResult > Convert < T , TResult > ( this AwaitableResult < T > task , Converter < T , Result < TResult > > converter )
138
+ => task . TransformAwaitableResult ( ( result ) => result . Convert ( converter ) ) ;
124
139
125
140
/// <summary>
126
141
/// If successful result is present, apply the provided mapping function. If not,
@@ -131,50 +146,32 @@ public static async Task<Result<TResult>> Convert<T, TResult>(this Task<Result<T
131
146
/// <typeparam name="T">The type of the value.</typeparam>
132
147
/// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
133
148
/// <returns>The conversion result.</returns>
134
- public static async Task < Result < TResult > > Convert < T , TResult > ( this Task < Result < T > > task , Converter < T , Task < Result < TResult > > > converter )
135
- => await ( await task . ConfigureAwait ( false ) ) . Convert ( converter ) . ConfigureAwait ( false ) ;
136
-
137
- /// <summary>
138
- /// If successful result is present, apply the provided mapping function hiding any exception
139
- /// caused by the converter.
140
- /// </summary>
141
- /// <param name="task">The task containing Result value.</param>
142
- /// <param name="converter">A mapping function to be applied to the value, if present.</param>
143
- /// <typeparam name="T">The type of the value.</typeparam>
144
- /// <typeparam name="TError">The type of the error code. Default value must represent the successful result.</typeparam>
145
- /// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
146
- /// <returns>The conversion result.</returns>
147
- public static async Task < Result < TResult , TError > > Convert < T , TError , TResult > ( this Task < Result < T , TError > > task , Converter < T , TResult > converter )
148
- where TError : struct , Enum
149
- => ( await task . ConfigureAwait ( false ) ) . Convert ( converter ) ;
149
+ public static AwaitableResult < TResult > Convert < T , TResult > ( this AwaitableResult < T > task , Converter < T , Task < TResult > > converter )
150
+ => task . TransformAwaitableResult ( ( result ) => result . Convert ( converter ) ) ;
150
151
151
152
/// <summary>
152
153
/// If successful result is present, apply the provided mapping function. If not,
153
- /// forward the error .
154
+ /// forward the exception .
154
155
/// </summary>
155
156
/// <param name="task">The task containing Result value.</param>
156
157
/// <param name="converter">A mapping function to be applied to the value, if present.</param>
157
158
/// <typeparam name="T">The type of the value.</typeparam>
158
- /// <typeparam name="TError">The type of the error code. Default value must represent the successful result.</typeparam>
159
159
/// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
160
160
/// <returns>The conversion result.</returns>
161
- public static async Task < Result < TResult , TError > > Convert < T , TError , TResult > ( this Task < Result < T , TError > > task , Converter < T , Result < TResult , TError > > converter )
162
- where TError : struct , Enum
163
- => ( await task . ConfigureAwait ( false ) ) . Convert ( converter ) ;
161
+ public static AwaitableResult < TResult > Convert < T , TResult > ( this AwaitableResult < T > task , Converter < T , Task < Result < TResult > > > converter )
162
+ => task . TransformAwaitableResult ( ( result ) => result . Convert ( converter ) ) ;
164
163
165
164
/// <summary>
166
165
/// If successful result is present, apply the provided mapping function. If not,
167
- /// forward the error .
166
+ /// forward the exception .
168
167
/// </summary>
169
168
/// <param name="task">The task containing Result value.</param>
170
169
/// <param name="converter">A mapping function to be applied to the value, if present.</param>
171
170
/// <typeparam name="T">The type of the value.</typeparam>
172
- /// <typeparam name="TError">The type of the error code. Default value must represent the successful result.</typeparam>
173
171
/// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
174
172
/// <returns>The conversion result.</returns>
175
- public static async Task < Result < TResult , TError > > Convert < T , TError , TResult > ( this Task < Result < T , TError > > task , Converter < T , Task < Result < TResult , TError > > > converter )
176
- where TError : struct , Enum
177
- => await ( await task . ConfigureAwait ( false ) ) . Convert ( converter ) . ConfigureAwait ( false ) ;
173
+ public static AwaitableResult < TResult > Convert < T , TResult > ( this AwaitableResult < T > task , Converter < T , AwaitableResult < TResult > > converter )
174
+ => task . TransformAwaitableResult ( ( result ) => result . Convert ( converter ) ) ;
178
175
179
176
/// <summary>
180
177
/// Converts the result into <see cref="Optional{T}"/>.
@@ -183,6 +180,13 @@ public static async Task<Result<TResult, TError>> Convert<T, TError, TResult>(th
183
180
public static async Task < Optional < T > > TryGet < T > ( this Task < Result < T > > task )
184
181
=> ( await task . ConfigureAwait ( false ) ) . TryGet ( ) ;
185
182
183
+ /// <summary>
184
+ /// Converts the awaitable Result into a task holding <see cref="Optional{T}"/>.
185
+ /// </summary>
186
+ /// <returns>A task holding an Option monad representing value in this monad.</returns>
187
+ public static async Task < Optional < T > > TryGet < T > ( this AwaitableResult < T > awaitableResult )
188
+ => ( await awaitableResult . ConfigureAwait ( false ) ) . TryGet ( ) ;
189
+
186
190
/// <summary>
187
191
/// Converts the result into <see cref="Optional{T}"/>.
188
192
/// </summary>
@@ -341,24 +345,72 @@ private Result<TResult> ConvertResult<TResult, TConverter>(TConverter converter)
341
345
}
342
346
343
347
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
344
- private Task < Result < TResult > > ConvertResultTask < TResult , TConverter > ( TConverter converter )
345
- where TConverter : struct , ISupplier < T , Task < Result < TResult > > >
348
+ private AwaitableResult < TResult > ConvertTask < TResult , TConverter > ( TConverter converter )
349
+ where TConverter : struct , ISupplier < T , Task < TResult > >
346
350
{
347
- Task < Result < TResult > > result ;
351
+ AwaitableResult < TResult > result ;
348
352
if ( exception is null )
349
353
{
350
354
try
351
355
{
352
- result = converter . Invoke ( value ) ;
356
+ result = converter . Invoke ( value ) . SuspendException ( ) ;
353
357
}
354
358
catch ( Exception e )
355
359
{
356
- result = Task . FromResult ( new Result < TResult > ( e ) ) ;
360
+ result = new ( Task . FromException < TResult > ( e ) ) ;
357
361
}
358
362
}
359
363
else
360
364
{
361
- result = Task . FromResult ( new Result < TResult > ( exception ) ) ;
365
+ result = new ( Task . FromException < TResult > ( exception . SourceException ) ) ;
366
+ }
367
+
368
+ return result ;
369
+ }
370
+
371
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
372
+ private AwaitableResult < TResult > ConvertResultTask < TResult , TConverter > ( TConverter converter )
373
+ where TConverter : struct , ISupplier < T , Task < Result < TResult > > >
374
+ {
375
+ AwaitableResult < TResult > result ;
376
+ if ( exception is null )
377
+ {
378
+ var valueCopy = value ;
379
+ async Task < TResult > GetConversionResult ( )
380
+ {
381
+ var conversionResult = await converter . Invoke ( valueCopy ) . ConfigureAwait ( false ) ;
382
+ return conversionResult . IsSuccessful ? conversionResult . Value : throw conversionResult . Error ;
383
+ }
384
+
385
+ result = new ( GetConversionResult ( ) ) ;
386
+ }
387
+ else
388
+ {
389
+ result = new ( Task . FromException < TResult > ( exception . SourceException ) ) ;
390
+ }
391
+
392
+ return result ;
393
+ }
394
+
395
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
396
+ private AwaitableResult < TResult > ConvertAwaitableResult < TResult , TConverter > ( TConverter converter )
397
+ where TConverter : struct , ISupplier < T , AwaitableResult < TResult > >
398
+ {
399
+ AwaitableResult < TResult > result ;
400
+ if ( exception is null )
401
+ {
402
+ var valueCopy = value ;
403
+ async Task < TResult > GetConversionResult ( )
404
+ {
405
+ var conversionResult = await converter . Invoke ( valueCopy ) . ConfigureAwait ( false ) ;
406
+ return conversionResult . IsSuccessful ? conversionResult . Value : throw conversionResult . Error ;
407
+ }
408
+
409
+ result = new ( GetConversionResult ( ) ) ;
410
+ }
411
+ else
412
+ {
413
+ result = new ( Task . FromException < TResult > ( exception . SourceException ) ) ;
362
414
}
363
415
364
416
return result ;
@@ -391,9 +443,29 @@ public Result<TResult> Convert<TResult>(Converter<T, Result<TResult>> converter)
391
443
/// <param name="converter">A mapping function to be applied to the value, if present.</param>
392
444
/// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
393
445
/// <returns>The conversion result.</returns>
394
- public Task < Result < TResult > > Convert < TResult > ( Converter < T , Task < Result < TResult > > > converter )
446
+ public AwaitableResult < TResult > Convert < TResult > ( Converter < T , Task < TResult > > converter )
447
+ => ConvertTask < TResult , DelegatingConverter < T , Task < TResult > > > ( converter ) ;
448
+
449
+ /// <summary>
450
+ /// If successful result is present, apply the provided mapping function. If not,
451
+ /// forward the exception.
452
+ /// </summary>
453
+ /// <param name="converter">A mapping function to be applied to the value, if present.</param>
454
+ /// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
455
+ /// <returns>The conversion result.</returns>
456
+ public AwaitableResult < TResult > Convert < TResult > ( Converter < T , Task < Result < TResult > > > converter )
395
457
=> ConvertResultTask < TResult , DelegatingConverter < T , Task < Result < TResult > > > > ( converter ) ;
396
458
459
+ /// <summary>
460
+ /// If successful result is present, apply the provided mapping function. If not,
461
+ /// forward the exception.
462
+ /// </summary>
463
+ /// <param name="converter">A mapping function to be applied to the value, if present.</param>
464
+ /// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
465
+ /// <returns>The conversion result.</returns>
466
+ public AwaitableResult < TResult > Convert < TResult > ( Converter < T , AwaitableResult < TResult > > converter )
467
+ => ConvertAwaitableResult < TResult , DelegatingConverter < T , AwaitableResult < TResult > > > ( converter ) ;
468
+
397
469
/// <summary>
398
470
/// If successful result is present, apply the provided mapping function hiding any exception
399
471
/// caused by the converter.
@@ -424,9 +496,31 @@ public unsafe Result<TResult> Convert<TResult>(delegate*<T, Result<TResult>> con
424
496
/// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
425
497
/// <returns>The conversion result.</returns>
426
498
[ CLSCompliant ( false ) ]
427
- public unsafe Task < Result < TResult > > Convert < TResult > ( delegate * < T , Task < Result < TResult > > > converter )
499
+ public unsafe AwaitableResult < TResult > Convert < TResult > ( delegate * < T , Task < TResult > > converter )
500
+ => ConvertTask < TResult , Supplier < T , Task < TResult > > > ( converter ) ;
501
+
502
+ /// <summary>
503
+ /// If successful result is present, apply the provided mapping function. If not,
504
+ /// forward the exception.
505
+ /// </summary>
506
+ /// <param name="converter">A mapping function to be applied to the value, if present.</param>
507
+ /// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
508
+ /// <returns>The conversion result.</returns>
509
+ [ CLSCompliant ( false ) ]
510
+ public unsafe AwaitableResult < TResult > Convert < TResult > ( delegate * < T , Task < Result < TResult > > > converter )
428
511
=> ConvertResultTask < TResult , Supplier < T , Task < Result < TResult > > > > ( converter ) ;
429
512
513
+ /// <summary>
514
+ /// If successful result is present, apply the provided mapping function. If not,
515
+ /// forward the exception.
516
+ /// </summary>
517
+ /// <param name="converter">A mapping function to be applied to the value, if present.</param>
518
+ /// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
519
+ /// <returns>The conversion result.</returns>
520
+ [ CLSCompliant ( false ) ]
521
+ public unsafe AwaitableResult < TResult > Convert < TResult > ( delegate * < T , AwaitableResult < TResult > > converter )
522
+ => ConvertAwaitableResult < TResult , Supplier < T , AwaitableResult < TResult > > > ( converter ) ;
523
+
430
524
/// <summary>
431
525
/// Attempts to extract value from container if it is present.
432
526
/// </summary>
@@ -527,6 +621,13 @@ public ValueTask<T> AsTask()
527
621
{ } error => ValueTask . FromException < T > ( error ) ,
528
622
} ;
529
623
624
+ /// <summary>
625
+ /// Converts this result to <see cref="AwaitableResult{TResult}"/>.
626
+ /// </summary>
627
+ /// <returns>The completed task representing the result.</returns>
628
+ public AwaitableResult < T > ToAwaitable ( )
629
+ => IsSuccessful ? new ( Task . FromResult ( value ) ) : new ( Task . FromException < T > ( Error ) ) ;
630
+
530
631
/// <summary>
531
632
/// Converts the result to <see cref="Task{TResult}"/>.
532
633
/// </summary>
@@ -747,11 +848,6 @@ private Result<TResult, TError> ConvertResult<TResult, TConverter>(TConverter co
747
848
where TConverter : struct , ISupplier < T , Result < TResult , TError > >
748
849
=> IsSuccessful ? converter . Invoke ( value ) : new ( Error ) ;
749
850
750
- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
751
- private Task < Result < TResult , TError > > ConvertResultTask < TResult , TConverter > ( TConverter converter )
752
- where TConverter : struct , ISupplier < T , Task < Result < TResult , TError > > >
753
- => IsSuccessful ? converter . Invoke ( value ) : Task . FromResult ( new Result < TResult , TError > ( Error ) ) ;
754
-
755
851
/// <summary>
756
852
/// If successful result is present, apply the provided mapping function hiding any exception
757
853
/// caused by the converter.
@@ -772,16 +868,6 @@ public Result<TResult, TError> Convert<TResult>(Converter<T, TResult> converter)
772
868
public Result < TResult , TError > Convert < TResult > ( Converter < T , Result < TResult , TError > > converter )
773
869
=> ConvertResult < TResult , DelegatingConverter < T , Result < TResult , TError > > > ( converter ) ;
774
870
775
- /// <summary>
776
- /// If successful result is present, apply the provided mapping function. If not,
777
- /// forward the error.
778
- /// </summary>
779
- /// <param name="converter">A mapping function to be applied to the value, if present.</param>
780
- /// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
781
- /// <returns>The conversion result.</returns>
782
- public Task < Result < TResult , TError > > Convert < TResult > ( Converter < T , Task < Result < TResult , TError > > > converter )
783
- => ConvertResultTask < TResult , DelegatingConverter < T , Task < Result < TResult , TError > > > > ( converter ) ;
784
-
785
871
/// <summary>
786
872
/// If successful result is present, apply the provided mapping function hiding any exception
787
873
/// caused by the converter.
@@ -804,17 +890,6 @@ public unsafe Result<TResult, TError> Convert<TResult>(delegate*<T, TResult> con
804
890
public unsafe Result < TResult , TError > Convert < TResult > ( delegate * < T , Result < TResult , TError > > converter )
805
891
=> ConvertResult < TResult , Supplier < T , Result < TResult , TError > > > ( converter ) ;
806
892
807
- /// <summary>
808
- /// If successful result is present, apply the provided mapping function. If not,
809
- /// forward the error.
810
- /// </summary>
811
- /// <param name="converter">A mapping function to be applied to the value, if present.</param>
812
- /// <typeparam name="TResult">The type of the result of the mapping function.</typeparam>
813
- /// <returns>The conversion result.</returns>
814
- [ CLSCompliant ( false ) ]
815
- public unsafe Task < Result < TResult , TError > > Convert < TResult > ( delegate * < T , Task < Result < TResult , TError > > > converter )
816
- => ConvertResultTask < TResult , Supplier < T , Task < Result < TResult , TError > > > > ( converter ) ;
817
-
818
893
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
819
894
private T OrInvoke < TSupplier > ( TSupplier defaultFunc )
820
895
where TSupplier : struct , ISupplier < T >
0 commit comments