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));
}
}
}
}