namespace StevanFreeborn.Results { /// /// Provides async extension methods for and . /// public static class ResultAsyncExtensions { /// /// Maps the value to a new type asynchronously if the result is successful. /// /// The type of the value. /// The new type. /// The type of the error. /// The result. /// The async function to map the value. /// A task containing a new with the mapped value if successful, otherwise the current error. /// Thrown when result or mapper is null. public static async Task> MapAsync(this Result result, Func> mapper) where TError : IError { if (result is null) { throw new ArgumentNullException(nameof(result)); } if (mapper is null) { throw new ArgumentNullException(nameof(mapper)); } return result.IsSuccess ? await mapper(result.Value).ConfigureAwait(false) : result.Error; } /// /// Maps the error to a new error asynchronously if the result is a failure. /// /// The type of the value. /// The type of the error. /// The new error type. /// The result. /// The async function to map the error. /// A task containing a new with the mapped error if failed, otherwise the current result. /// Thrown when result or mapper is null. public static async Task> MapErrorAsync(this Result result, Func> mapper) where TError : IError where TNewError : IError { if (result is null) { throw new ArgumentNullException(nameof(result)); } if (mapper is null) { throw new ArgumentNullException(nameof(mapper)); } return result.IsFailure ? await mapper(result.Error).ConfigureAwait(false) : Result.Ok(result.Value); } /// /// Executes the specified async action if the result is successful, and returns the current result. /// /// The type of the error. /// The result. /// The async action to execute on success. /// A task containing the result. /// Thrown when result or onSuccess is null. public static async Task> MapAsync(this Result result, Func onSuccess) where TError : IError { if (result is null) { throw new ArgumentNullException(nameof(result)); } if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } if (result.IsSuccess) { await onSuccess(result.Value).ConfigureAwait(false); } return result; } /// /// Binds to a new async result if the current result is successful. /// /// The type of the error. /// The result. /// The async function to execute and bind to on success. /// A task containing the result of the binder function if successful, otherwise the current result. /// Thrown when result or onSuccess is null. public static async Task> BindAsync(this Result result, Func>> onSuccess) where TError : IError { if (result is null) { throw new ArgumentNullException(nameof(result)); } if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } return result.IsSuccess ? await onSuccess(result.Value).ConfigureAwait(false) : result; } /// /// Matches the result asynchronously and returns a value based on success or failure. /// /// The type of the result. /// The type of the error. /// The result. /// The async function to execute on success. /// The async function to execute on failure. /// A task containing the result of the appropriate function. /// Thrown when result, onSuccess, or onFailure is null. public static async Task MatchAsync(this Result result, Func> onSuccess, Func> onFailure) where TError : IError { if (result is null) { throw new ArgumentNullException(nameof(result)); } if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } if (onFailure is null) { throw new ArgumentNullException(nameof(onFailure)); } return result.IsSuccess ? await onSuccess(result.Value).ConfigureAwait(false) : await onFailure(result.Error).ConfigureAwait(false); } /// /// Executes the specified async action and wraps the result in a . /// /// The async action to execute. /// A task containing a successful result if no exception is thrown; otherwise, a failed result. public static Task> TryAsync(Func action) { return TryAsync(action, ex => new Error("UnexpectedError", ex.Message)); } /// /// Executes the specified async action and wraps the result in a using the specified error handler. /// /// The async action to execute. /// The function to convert exceptions to errors. /// A task containing a successful result if no exception is thrown; otherwise, a failed result. /// Thrown when action or errorHandler is null. public static async Task> TryAsync(Func action, Func errorHandler) { if (action is null) { throw new ArgumentNullException(nameof(action)); } if (errorHandler is null) { throw new ArgumentNullException(nameof(errorHandler)); } try { await action().ConfigureAwait(false); return Result.Ok(default); } catch (Exception ex) { return Result.Fail(errorHandler(ex)); } } /// /// Binds to a new async result if the current result is successful. /// /// The type of the value. /// The new result type. /// The type of the error. /// The result. /// The async function to bind to on success. /// A task containing the result of the binder function if successful, otherwise the current error. /// Thrown when result or binder is null. public static async Task> BindAsync(this Result result, Func>> binder) where TError : IError { if (result is null) { throw new ArgumentNullException(nameof(result)); } if (binder is null) { throw new ArgumentNullException(nameof(binder)); } return result.IsSuccess ? await binder(result.Value).ConfigureAwait(false) : Result.Fail(result.Error); } /// /// Matches the result asynchronously and returns a value based on success or failure. /// /// The type of the value. /// The type of the result. /// The type of the error. /// The result. /// The async function to execute on success. /// The async function to execute on failure. /// A task containing the result of the appropriate function. /// Thrown when result, onSuccess, or onFailure is null. public static async Task MatchAsync(this Result result, Func> onSuccess, Func> onFailure) where TError : IError { if (result is null) { throw new ArgumentNullException(nameof(result)); } if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } if (onFailure is null) { throw new ArgumentNullException(nameof(onFailure)); } return result.IsSuccess ? await onSuccess(result.Value).ConfigureAwait(false) : await onFailure(result.Error).ConfigureAwait(false); } /// /// Executes the specified async function and wraps the result in a . /// /// The type of the value. /// The async function to execute. /// A task containing a successful result with the return value if no exception is thrown; otherwise, a failed result. public static Task> TryAsync(Func> func) { return TryAsync(func, ex => new Error("UnexpectedError", ex.Message)); } /// /// Executes the specified async function and wraps the result in a using the specified error handler. /// /// The type of the value. /// The async function to execute. /// The function to convert exceptions to errors. /// A task containing a successful result with the return value if no exception is thrown; otherwise, a failed result. /// Thrown when func or errorHandler is null. public static async Task> TryAsync(Func> func, Func errorHandler) { if (func is null) { throw new ArgumentNullException(nameof(func)); } if (errorHandler is null) { throw new ArgumentNullException(nameof(errorHandler)); } try { return Result.Ok(await func().ConfigureAwait(false)); } catch (Exception ex) { return Result.Fail(errorHandler(ex)); } } } }