using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Sony.Filtr.Functional { public static class ResultExtensions { public static T FirstOrDefaultTryCatch(this IEnumerable source, Func predicate) { var safePredicate = predicate.TryCatch(); return source.FirstOrDefault(t => { var result = safePredicate(t); return result.IsOk && result.Value; }); } public static async Task> Prompt(this Result result, Func>[] prompts, Func isAcceptable) { if (result.IsFailed) { return Result.FromException(result.Exception); } foreach (var prompt in prompts) { var promptResult = await prompt.TryCatch()(result.Value); if (promptResult.IsOk && isAcceptable(promptResult.Value)) { return promptResult; } } return Result.FromException(new Exception("All prompts failed")); } public static Result ToResult(this T value) { return Result.Success(value); } public static T Flatten(this Result result) { return result.IsFailed ? throw result.Exception : result.Value; } public static async Task Flatten(this Task> resultTask) { Result result = await resultTask; return result.IsFailed ? throw result.Exception : result.Value; } public static async Task Flatten(this Task> resultTask, Func exceptionTransform) { Result result = await resultTask; return result.IsFailed ? exceptionTransform(result.Exception) : result.Value; } public static Task> ToTask(this Result result) { return Task.FromResult(result); } public static Result Bind(this Result result, Func> func) { return result.IsOk ? func(result.Value) : Result.FromException(result.Exception); } public static Result BindMany(this Result result, Func func) { if (result.IsFailed) { return Result.FromException(result.Exception); } return result.Value.Select(item => func(item)).ToArray().ToResult(); } public static Result Bind(this Result result, Func func) { return result.Bind(func.TryCatch()); } public static async Task> Bind(this Task> input, Func> f) { var result = await input; if (result.IsOk) { return f(result.Value); } return Result.FromException(result.Exception); } public static async Task> Bind(this Task> input, Func f) { return await input.Bind(f.TryCatch()); } public static async Task> BindFinalize(this Task> input, Func func, Action finalizer) { var result = await input; if (result.IsOk) { var toReturn = func.TryCatch()(result.Value); finalizer(result.Value); return toReturn; } return Result.FromException(result.Exception); } public static async Task> TapAsync(this Result result, Func action) { if (result.IsFailed) { return result; } Func> func = async input => { await action(input); return true; }; await func.TryCatch()(result.Value); return result; } public static async Task> BindAndTupleAsync(this Task> sourceResult, Func> func) { var source = await sourceResult; if (source.IsFailed) { return Result<(T, T1)>.FromException(source.Exception); } var result = await func.TryCatch()(source.Value); return result.IsOk ? (source.Value, result.Value) : Result<(T, T1)>.FromException(result.Exception); } public static async Task> BindAsync(this Result result, Func> func) { if (result.IsFailed) { Result.FromException(result.Exception); } return await func.TryCatch()(result.Value); } public static async Task> BindAsync(this Result result, Func>> func) { if (result.IsFailed) { Result.FromException(result.Exception); } return await func(result.Value); } public static async Task> BindAsync(this Task> input, Func>> f) { var result = await input; if (result.IsOk) { return await f(result.Value); } return Result.FromException(result.Exception); } public static async Task>> BindManyAsync(this Task>> input, Func f) { var result = await input; if (result.IsOk) { return result.Value .Select(v => f(v)) .ToList(); } return Result>.FromException(result.Exception); } public static async Task> BindAsync(this Task> input, Func> f) { return await input.BindAsync(f.TryCatch()); } public static async Task> TapAsync(this Task> resultTask, Action action) { var result = await resultTask; if (result.IsOk) { action(); } return result; } public static async Task> TapAsync(this Task> resultTask, Func action) { var result = await resultTask; if (result.IsOk) { await action(); } return result; } public static async Task> TapAsync(this Task> resultTask, Action action) { var result = await resultTask; if (result.IsOk) { action(result.Value); } return result; } public static async Task> TapAsync(this Task> resultTask, Func action) { var result = await resultTask; if (result.IsOk) { await action(result.Value); } return result; } public static async Task> TapAsync(this Task> resultTask, Func action, Func mapper) { var result = await resultTask; if (result.IsOk) { await action(mapper(result.Value)); } return result; } public static Result Tap(this Result result, Action action) { if (result.IsOk) { action(result.Value); } return result; } public static Result OnFailure(this Result result, Action action) { if (result.IsFailed) { action(result.Exception); } return result; } public static Result OnSuccess(this Result result, Action action) { if (result.IsOk) { action(result.Value); } return result; } } }