Skip to content

Commit

Permalink
Merge pull request #579 from marcinjahn/allocation-free-maybe-match
Browse files Browse the repository at this point in the history
feat: add allocation-free overloads of Maybe.Match
  • Loading branch information
vkhorikov authored Nov 18, 2024
2 parents 443a364 + fd6fb14 commit f2e6229
Show file tree
Hide file tree
Showing 6 changed files with 783 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,33 @@ await maybe.Match(
);
}

[Fact]
public async Task Match_provides_context_to_some_selector()
{
Maybe<T> maybe = T.Value;
var cancellationToken = GetCancellationToken();
var context = 5;
var contextAsserted = false;

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

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

contextAsserted.Should().BeTrue();
}

[Fact]
public async Task Match_follows_none_branch_where_is_no_value()
{
Expand All @@ -47,6 +74,32 @@ await maybe.Match(
);
}

[Fact]
public async Task Match_provides_context_to_none_selector()
{
Maybe<T> maybe = null;
var cancellationToken = GetCancellationToken();
var context = 5;
var contextAsserted = false;

await maybe.Match(
Some: (_, _, _) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ctx, ct) =>
{
ctx.Should().Be(context);
contextAsserted = true;
ct.Should().Be(cancellationToken);

return Task.CompletedTask;
},
context: context,
cancellationToken
);

contextAsserted.Should().BeTrue();
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_no_value()
{
Expand All @@ -68,6 +121,35 @@ await maybe.Match(
);
}

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

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

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

contextAsserted.Should().BeTrue();
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_none_branch_where_is_no_value()
{
Expand All @@ -86,6 +168,32 @@ await maybe.Match(
);
}

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

await maybe.Match(
Some: (_, _, _, _) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ctx, ct) =>
{
ctx.Should().Be(context);
contextAsserted = true;
ct.Should().Be(cancellationToken);

return Task.CompletedTask;
},
context: context,
cancellationToken
);

contextAsserted.Should().BeTrue();
}

[Fact]
public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_a_return_value()
{
Expand All @@ -100,7 +208,7 @@ public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_a_return
intValue.Should().Be(42);
stringValue.Should().Be("Matrix");

return Task.FromResult(intValue);
return intValue.AsTask();
},
None: _ => throw new FieldAccessException("Accessed None path while maybe has value"),
cancellationToken
Expand All @@ -109,6 +217,34 @@ public async Task Match_for_deconstruct_kv_follows_some_branch_where_is_a_return
42.Should().Be(returnValue);
}

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

var returnValue = await maybe.Match(
Some: (intValue, stringValue, ctx, ct) =>
{
ctx.Should().Be(context);
contextAsserted = true;

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

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

[Fact]
public async Task Match_for_deconstruct_kv_follows_none_branch_where_is_a_return_value()
{
Expand All @@ -121,12 +257,38 @@ public async Task Match_for_deconstruct_kv_follows_none_branch_where_is_a_return
None: (ct) =>
{
ct.Should().Be(cancellationToken);
return Task.FromResult(-1);
return (-1).AsTask();
},
cancellationToken
);

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

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

var returnValue = await maybe.Match(
Some: (intValue, stringValue, ctx, ct) =>
throw new FieldAccessException("Accessed Some path while maybe has no value"),
None: (ctx, _) =>
{
ctx.Should().Be(context);
contextAsserted = true;

return (-1).AsTask();
},
context: context,
cancellationToken
);

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

private static CancellationToken GetCancellationToken() => new(canceled: true);
Expand Down
Loading

0 comments on commit f2e6229

Please sign in to comment.