namespace Just.Railway; public static partial class ResultExtensions { #region Match (with fallback) public static T Match(this in Result result, Func fallback) { return result.State switch { ResultState.Success => result.Value, ResultState.Error => fallback(result.Error!), _ => throw new ResultNotInitializedException(nameof(result)) }; } public static async Task Match(this Result result, Func> fallback) { return result.State switch { ResultState.Success => result.Value, ResultState.Error => await fallback(result.Error!).ConfigureAwait(false), _ => throw new ResultNotInitializedException(nameof(result)) }; } public static async Task Match(this Task> resultTask, Func fallback) { var result = await resultTask.ConfigureAwait(false); return result.State switch { ResultState.Success => result.Value, ResultState.Error => fallback(result.Error!), _ => throw new ResultNotInitializedException(nameof(resultTask)) }; } public static async Task Match(this Task> resultTask, Func> fallback) { var result = await resultTask.ConfigureAwait(false); return result.State switch { ResultState.Success => result.Value, ResultState.Error => await fallback(result.Error!).ConfigureAwait(false), _ => throw new ResultNotInitializedException(nameof(resultTask)) }; } public static async ValueTask Match(this Result result, Func> fallback) { return result.State switch { ResultState.Success => result.Value, ResultState.Error => await fallback(result.Error!).ConfigureAwait(false), _ => throw new ResultNotInitializedException(nameof(result)) }; } public static async ValueTask Match(this ValueTask> resultTask, Func fallback) { var result = await resultTask.ConfigureAwait(false); return result.State switch { ResultState.Success => result.Value, ResultState.Error => fallback(result.Error!), _ => throw new ResultNotInitializedException(nameof(resultTask)) }; } public static async ValueTask Match(this ValueTask> resultTask, Func> fallback) { var result = await resultTask.ConfigureAwait(false); return result.State switch { ResultState.Success => result.Value, ResultState.Error => await fallback(result.Error!).ConfigureAwait(false), _ => throw new ResultNotInitializedException(nameof(resultTask)) }; } #endregion #region Merge public static Result Merge(this IEnumerable results) { List? errors = null; bool hasErrors = false; foreach (var result in results.OrderBy(x => x.State)) { switch (result.State) { case ResultState.Error: hasErrors = true; errors ??= new(4); errors.Add(result.Error!); break; case ResultState.Success: if (hasErrors) goto afterLoop; break; default: throw new ResultNotInitializedException(nameof(results)); } } afterLoop: return hasErrors ? new(new ManyErrors(errors!)) : new(null); } public static async Task Merge(this IEnumerable> tasks) { var results = await Task.WhenAll(tasks).ConfigureAwait(false); return results.Merge(); } public static Result> Merge(this IEnumerable> results) { List? values = null; List? errors = null; bool hasErrors = false; foreach (var result in results.OrderBy(x => x.State)) { switch (result.State) { case ResultState.Error: hasErrors = true; errors ??= new(4); errors.Add(result.Error!); break; case ResultState.Success: if (hasErrors) goto afterLoop; values ??= new(4); values.Add(result.Value); break; default: throw new ResultNotInitializedException(nameof(results)); } } afterLoop: return hasErrors ? new(new ManyErrors(errors!)) : new((IEnumerable?)values ?? Array.Empty()); } public static async Task>> Merge(this IEnumerable>> tasks) { var results = await Task.WhenAll(tasks).ConfigureAwait(false); return results.Merge(); } #endregion }