Skip to content

Commit

Permalink
Merge pull request #563 from marcinjahn/add-maybe-match-async
Browse files Browse the repository at this point in the history
Add async overloads of Maybe.Match
  • Loading branch information
vkhorikov authored Sep 8, 2024
2 parents 298d914 + eca46f7 commit 2776408
Show file tree
Hide file tree
Showing 4 changed files with 412 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CSharpFunctionalExtensions.Tests.ResultTests.Extensions;
using FluentAssertions;
using Xunit;

namespace CSharpFunctionalExtensions.Tests.MaybeTests.Extensions;

public class MatchTests_Task : MatchTestsBase
{
[Fact]
public async Task Match_follows_some_branch_where_there_is_a_value()
{
Maybe<T> maybe = T.Value;
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (value, ct) =>
{
ct.Should().Be(cancellationToken);
value.Should().Be(T.Value);

return Task.CompletedTask;
},
None: _ => throw new FieldAccessException("Accessed None path while maybe has value"),
cancellationToken
);
}

[Fact]
public async Task Match_follows_none_branch_where_is_no_value()
{
Maybe<T> maybe = null;
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (_, __) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ct) =>
{
ct.Should().Be(cancellationToken);
return Task.CompletedTask;
},
cancellationToken
);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_no_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.From(
new KeyValuePair<int, string>(42, "Matrix")
);
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (intValue, stringValue, ct) =>
{
intValue.Should().Be(42);
stringValue.Should().Be("Matrix");

return Task.CompletedTask;
},
None: _ => throw new FieldAccessException("Accessed None path while maybe has value"),
cancellationToken
);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_none_branch_where_is_no_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.None;
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (_, __, ___) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ct) =>
{
ct.Should().Be(cancellationToken);
return Task.CompletedTask;
},
cancellationToken
);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_a_return_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.From(
new KeyValuePair<int, string>(42, "Matrix")
);
var cancellationToken = GetCancellationToken();

var returnValue = await maybe.Match(
Some: (intValue, stringValue, ct) =>
{
intValue.Should().Be(42);
stringValue.Should().Be("Matrix");

return Task.FromResult(intValue);
},
None: _ => throw new FieldAccessException("Accessed None path while maybe has value"),
cancellationToken
);

42.Should().Be(returnValue);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_none_branch_where_is_a_return_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.None;
var cancellationToken = GetCancellationToken();

var returnValue = await maybe.Match(
Some: (_, __, ___) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ct) =>
{
ct.Should().Be(cancellationToken);
return Task.FromResult(-1);
},
cancellationToken
);

(-1).Should().Be(returnValue);
}

private static CancellationToken GetCancellationToken() => new(canceled: true);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CSharpFunctionalExtensions.Tests.ResultTests.Extensions;
using FluentAssertions;
using Xunit;

namespace CSharpFunctionalExtensions.Tests.MaybeTests.Extensions;

public class MatchTests_ValueTask : MatchTestsBase
{
[Fact]
public async Task Match_follows_some_branch_where_there_is_a_value()
{
Maybe<T> maybe = T.Value;
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (value, ct) =>
{
ct.Should().Be(cancellationToken);
value.Should().Be(T.Value);

return ValueTask.CompletedTask;
},
None: _ => throw new FieldAccessException("Accessed None path while maybe has value"),
cancellationToken
);
}

[Fact]
public async Task Match_follows_none_branch_where_is_no_value()
{
Maybe<T> maybe = null;
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (_, __) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ct) =>
{
ct.Should().Be(cancellationToken);
return ValueTask.CompletedTask;
},
cancellationToken
);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_no_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.From(
new KeyValuePair<int, string>(42, "Matrix")
);
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (intValue, stringValue, ct) =>
{
intValue.Should().Be(42);
stringValue.Should().Be("Matrix");

return ValueTask.CompletedTask;
},
None: _ => throw new FieldAccessException("Accessed None path while maybe has value"),
cancellationToken
);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_none_branch_where_is_no_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.None;
var cancellationToken = GetCancellationToken();

await maybe.Match(
Some: (_, __, ___) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ct) =>
{
ct.Should().Be(cancellationToken);
return ValueTask.CompletedTask;
},
cancellationToken
);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_a_return_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.From(
new KeyValuePair<int, string>(42, "Matrix")
);
var cancellationToken = GetCancellationToken();

var returnValue = await maybe.Match(
Some: (intValue, stringValue, ct) =>
{
intValue.Should().Be(42);
stringValue.Should().Be("Matrix");

return ValueTask.FromResult(intValue);
},
None: _ => throw new FieldAccessException("Accessed None path while maybe has value"),
cancellationToken
);

42.Should().Be(returnValue);
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_none_branch_where_is_a_return_value()
{
Maybe<KeyValuePair<int, string>> maybe = Maybe<KeyValuePair<int, string>>.None;
var cancellationToken = GetCancellationToken();

var returnValue = await maybe.Match(
Some: (_, __, ___) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ct) =>
{
ct.Should().Be(cancellationToken);
return ValueTask.FromResult(-1);
},
cancellationToken
);

(-1).Should().Be(returnValue);
}

private static CancellationToken GetCancellationToken() => new(canceled: true);
}
72 changes: 72 additions & 0 deletions CSharpFunctionalExtensions/Maybe/Extensions/Match.Task.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace CSharpFunctionalExtensions
{
public static partial class MaybeExtensions
{
public static async Task<TE> Match<TE, T>(
this Maybe<T> maybe,
Func<T, CancellationToken, Task<TE>> Some,
Func<CancellationToken, Task<TE>> None,
CancellationToken cancellationToken = default
)
{
return maybe.HasValue
? await Some(maybe.GetValueOrThrow(), cancellationToken)
: await None(cancellationToken);
}

public static async Task Match<T>(
this Maybe<T> maybe,
Func<T, CancellationToken, Task> Some,
Func<CancellationToken, Task> None,
CancellationToken cancellationToken = default
)
{
if (maybe.HasValue)
await Some(maybe.GetValueOrThrow(), cancellationToken);
else
await None(cancellationToken);
}

public static async Task<TE> Match<TE, TKey, TValue>(
this Maybe<KeyValuePair<TKey, TValue>> maybe,
Func<TKey, TValue, CancellationToken, Task<TE>> Some,
Func<CancellationToken, Task<TE>> None,
CancellationToken cancellationToken = default
)
{
return maybe.HasValue
? await Some.Invoke(
maybe.GetValueOrThrow().Key,
maybe.GetValueOrThrow().Value,
cancellationToken
)
: await None.Invoke(cancellationToken);
}

public static async Task Match<TKey, TValue>(
this Maybe<KeyValuePair<TKey, TValue>> maybe,
Func<TKey, TValue, CancellationToken, Task> Some,
Func<CancellationToken, Task> None,
CancellationToken cancellationToken = default
)
{
if (maybe.HasValue)
{
await Some.Invoke(
maybe.GetValueOrThrow().Key,
maybe.GetValueOrThrow().Value,
cancellationToken
);
}
else
{
await None.Invoke(cancellationToken);
}
}
}
}
Loading

0 comments on commit 2776408

Please sign in to comment.