Skip to content

Commit

Permalink
Add optional onNone parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
bfriesen committed May 3, 2023
1 parent d936820 commit 03f5384
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 10 deletions.
24 changes: 24 additions & 0 deletions RandomSkunk.Results.UnitTests/Rescue_methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ public void Given_None_Returns_source()
actual.Should().Be(sourceResult);
}

[Fact]
public void Given_None_Returns_result_from_onNone_rescue_function()
{
var sourceResult = Maybe<int>.None;
var rescueResult = Maybe<int>.Fail("b");

var actual = sourceResult.Rescue(error => Maybe<int>.Fail("a"), () => rescueResult);

actual.Should().Be(rescueResult);
}

[Fact]
public void Given_IsFail_Returns_result_from_rescue_function()
{
Expand Down Expand Up @@ -257,6 +268,19 @@ public async Task Given_IsNone_Returns_source()
actual.Should().Be(sourceResult);
}

[Fact]
public async Task Given_IsNone_Returns_result_from_onNone_rescue_function()
{
var sourceResult = Maybe<int>.None;
var rescueResult = Maybe<int>.Fail("b");

var actual = await sourceResult.Rescue(
error => Task.FromResult(Maybe<int>.Fail("a")),
() => Task.FromResult(rescueResult));

actual.Should().Be(rescueResult);
}

[Fact]
public async Task Given_IsFail_Returns_result_from_rescue_function()
{
Expand Down
64 changes: 54 additions & 10 deletions RandomSkunk.Results/Operations/Rescue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,14 @@ public partial struct Maybe<T>
{
/// <summary>
/// Rescues a <c>Fail</c> result by returning the output of the <paramref name="onFail"/> function. If the current result is
/// <c>Success</c>, nothing happens and the current result is returned.
/// <c>Success</c>, nothing happens and the current result is returned. Rescues a <c>None</c> result if the optional
/// <paramref name="onNone"/> function is provided.
/// </summary>
/// <param name="onFail">The function that rescues a failed operation.</param>
/// <param name="onNone">An optional function that rescues a <c>None</c> result.</param>
/// <returns>The output of the <paramref name="onFail"/> function if the current result is <c>Fail</c>, or the same result if
/// it is <c>Success</c>.</returns>
public Maybe<T> Rescue(Func<Error, Maybe<T>> onFail)
public Maybe<T> Rescue(Func<Error, Maybe<T>> onFail, Func<Maybe<T>>? onNone = null)
{
if (onFail is null) throw new ArgumentNullException(nameof(onFail));

Expand All @@ -157,18 +159,35 @@ public Maybe<T> Rescue(Func<Error, Maybe<T>> onFail)
return Fail(ex, Error.GetMessageForExceptionThrownInCallback(nameof(onFail)));
}
}
else if (_outcome == Outcome.None && onNone is not null)
{
try
{
return onNone();
}
catch (TaskCanceledException ex)
{
return Errors.Canceled(ex);
}
catch (Exception ex)
{
return Fail(ex, Error.GetMessageForExceptionThrownInCallback(nameof(onNone)));
}
}

return this;
}

/// <summary>
/// Rescues a <c>Fail</c> result by returning the output of the <paramref name="onFail"/> function. If the current result is
/// <c>Success</c>, nothing happens and the current result is returned.
/// <c>Success</c>, nothing happens and the current result is returned. Rescues a <c>None</c> result if the optional
/// <paramref name="onNone"/> function is provided.
/// </summary>
/// <param name="onFail">The function that rescues a failed operation.</param>
/// <param name="onNone">An optional function that rescues a <c>None</c> result.</param>
/// <returns>The output of the <paramref name="onFail"/> function if the current result is <c>Fail</c>, or the same result if
/// it is <c>Success</c>.</returns>
public async Task<Maybe<T>> Rescue(Func<Error, Task<Maybe<T>>> onFail)
public async Task<Maybe<T>> Rescue(Func<Error, Task<Maybe<T>>> onFail, Func<Task<Maybe<T>>>? onNone = null)
{
if (onFail is null) throw new ArgumentNullException(nameof(onFail));

Expand All @@ -187,6 +206,21 @@ public async Task<Maybe<T>> Rescue(Func<Error, Task<Maybe<T>>> onFail)
return Fail(ex, Error.GetMessageForExceptionThrownInCallback(nameof(onFail)));
}
}
else if (_outcome == Outcome.None && onNone is not null)
{
try
{
return await onNone();
}
catch (TaskCanceledException ex)
{
return Errors.Canceled(ex);
}
catch (Exception ex)
{
return Fail(ex, Error.GetMessageForExceptionThrownInCallback(nameof(onNone)));
}
}

return this;
}
Expand Down Expand Up @@ -243,25 +277,35 @@ public static async Task<Result<T>> Rescue<T>(this Task<Result<T>> sourceResult,

/// <summary>
/// Rescues a <c>Fail</c> result by returning the output of the <paramref name="onFail"/> function. If the current result is
/// <c>Success</c>, nothing happens and the current result is returned.
/// <c>Success</c>, nothing happens and the current result is returned. Rescues a <c>None</c> result if the optional
/// <paramref name="onNone"/> function is provided.
/// </summary>
/// <typeparam name="T">The type of the source result value.</typeparam>
/// <param name="sourceResult">The source result.</param>
/// <param name="onFail">The function that rescues a failed operation.</param>
/// <param name="onNone">An optional function that rescues a <c>None</c> result.</param>
/// <returns>The output of the <paramref name="onFail"/> function if the current result is <c>Fail</c>, or the same result if
/// it is <c>Success</c>.</returns>
public static async Task<Maybe<T>> Rescue<T>(this Task<Maybe<T>> sourceResult, Func<Error, Maybe<T>> onFail) =>
(await sourceResult.ConfigureAwait(ContinueOnCapturedContext)).Rescue(onFail);
public static async Task<Maybe<T>> Rescue<T>(
this Task<Maybe<T>> sourceResult,
Func<Error, Maybe<T>> onFail,
Func<Maybe<T>>? onNone = null) =>
(await sourceResult.ConfigureAwait(ContinueOnCapturedContext)).Rescue(onFail, onNone);

/// <summary>
/// Rescues a <c>Fail</c> result by returning the output of the <paramref name="onFail"/> function. If the current result is
/// <c>Success</c>, nothing happens and the current result is returned.
/// <c>Success</c>, nothing happens and the current result is returned. Rescues a <c>None</c> result if the optional
/// <paramref name="onNone"/> function is provided.
/// </summary>
/// <typeparam name="T">The type of the source result value.</typeparam>
/// <param name="sourceResult">The source result.</param>
/// <param name="onFail">The function that rescues a failed operation.</param>
/// <param name="onNone">An optional function that rescues a <c>None</c> result.</param>
/// <returns>The output of the <paramref name="onFail"/> function if the current result is <c>Fail</c>, or the same result if
/// it is <c>Success</c>.</returns>
public static async Task<Maybe<T>> Rescue<T>(this Task<Maybe<T>> sourceResult, Func<Error, Task<Maybe<T>>> onFail) =>
await (await sourceResult.ConfigureAwait(ContinueOnCapturedContext)).Rescue(onFail).ConfigureAwait(ContinueOnCapturedContext);
public static async Task<Maybe<T>> Rescue<T>(
this Task<Maybe<T>> sourceResult,
Func<Error, Task<Maybe<T>>> onFail,
Func<Task<Maybe<T>>>? onNone = null) =>
await (await sourceResult.ConfigureAwait(ContinueOnCapturedContext)).Rescue(onFail, onNone).ConfigureAwait(ContinueOnCapturedContext);
}

0 comments on commit 03f5384

Please sign in to comment.