Skip to content

Commit

Permalink
Add TrySingle overloads for (#643)
Browse files Browse the repository at this point in the history
  • Loading branch information
elianora authored Apr 1, 2024
1 parent f5001c2 commit 636e2d0
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collectio
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<TSource?>
SuperLinq.Async.IAsyncBuffer<T>.ConfigureAwait(bool continueOnCapturedContext) -> System.Runtime.CompilerServices.ConfiguredAsyncDisposable
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collectio
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<TSource?>
SuperLinq.Async.IAsyncBuffer<T>.ConfigureAwait(bool continueOnCapturedContext) -> System.Runtime.CompilerServices.ConfiguredAsyncDisposable
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collectio
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<TSource?>
SuperLinq.Async.IAsyncBuffer<T>.ConfigureAwait(bool continueOnCapturedContext) -> System.Runtime.CompilerServices.ConfiguredAsyncDisposable
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collectio
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<TSource?>
SuperLinq.Async.IAsyncBuffer<T>.ConfigureAwait(bool continueOnCapturedContext) -> System.Runtime.CompilerServices.ConfiguredAsyncDisposable
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collectio
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.Split<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IAsyncEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.Async.AsyncSuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IAsyncEnumerable<TSource>! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<TSource?>
SuperLinq.Async.IAsyncBuffer<T>.ConfigureAwait(bool continueOnCapturedContext) -> System.Runtime.CompilerServices.ConfiguredAsyncDisposable
41 changes: 40 additions & 1 deletion Source/SuperLinq.Async/TrySingle.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace SuperLinq.Async;
namespace SuperLinq.Async;

public static partial class AsyncSuperEnumerable
{
Expand Down Expand Up @@ -107,4 +107,43 @@ static async ValueTask<TResult> Core(
: resultSelector(many, default);
}
}

/// <summary>
/// Returns the single element in the sequence if it contains exactly one element.
/// Similar to <see cref="AsyncEnumerable.SingleOrDefaultAsync{TSource}(IAsyncEnumerable{TSource}, CancellationToken)"/>.
/// </summary>
/// <typeparam name="TSource">
/// The type of the elements of <paramref name="source"/>.
/// </typeparam>
/// <param name="source">
/// The source sequence.
/// </param>
/// <param name="cancellationToken">
/// The optional cancellation token to be used for cancelling the sequence at any time.
/// </param>
/// <returns>
/// The single element or the default value of <typeparamref name="TSource"/>.
/// </returns>
public static ValueTask<TSource?> TrySingle<TSource>(
this IAsyncEnumerable<TSource> source,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(source);

return Core(source, cancellationToken);

static async ValueTask<TSource?> Core(
IAsyncEnumerable<TSource> source,
CancellationToken cancellationToken)
{
await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken);
if (!await e.MoveNextAsync())
return default;

var current = e.Current;
return !await e.MoveNextAsync()
? current
: default;
}
}
}
1 change: 1 addition & 0 deletions Source/SuperLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source) -> TSource?
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
1 change: 1 addition & 0 deletions Source/SuperLinq/PublicAPI/net7.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source) -> TSource?
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
1 change: 1 addition & 0 deletions Source/SuperLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source) -> TSource?
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
1 change: 1 addition & 0 deletions Source/SuperLinq/PublicAPI/net9.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source) -> TSource?
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.Split<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource separator, System.Collections.Generic.IEqualityComparer<TSource>? comparer, int count) -> System.Collections.Generic.IEnumerable<System.Collections.Generic.IReadOnlyList<TSource>!>!
static SuperLinq.SuperEnumerable.TrySingle<TSource>(this System.Collections.Generic.IEnumerable<TSource>! source) -> TSource?
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, SuperLinq.SuperEnumerable.ReadOnlySpanFunc<TSource, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
40 changes: 39 additions & 1 deletion Source/SuperLinq/TrySingle.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace SuperLinq;
namespace SuperLinq;

public static partial class SuperEnumerable
{
Expand Down Expand Up @@ -112,4 +112,42 @@ public static TResult TrySingle<T, TCardinality, TResult>(
: resultSelector(many, default);
}
}

/// <summary>
/// Returns the single element in the sequence if it contains exactly one element.
/// Similar to <see cref="Enumerable.SingleOrDefault{TSource}(IEnumerable{TSource})"/>.
/// </summary>
/// <typeparam name="TSource">
/// The type of the elements of <paramref name="source"/>.
/// </typeparam>
/// <param name="source">
/// The source sequence.
/// </param>
/// <returns>
/// The single element or the default value of <typeparamref name="TSource"/>.
/// </returns>
public static TSource? TrySingle<TSource>(this IEnumerable<TSource> source)
{
ArgumentNullException.ThrowIfNull(source);

if (source.TryGetCollectionCount() is int n)
{
return n switch
{
1 => source.First(),
0 or _ => default
};
}
else
{
using var e = source.GetEnumerator();
if (!e.MoveNext())
return default;

var current = e.Current;
return !e.MoveNext()
? current
: default;
}
}
}
13 changes: 12 additions & 1 deletion Tests/SuperLinq.Async.Test/TrySingleTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Test.Async;
namespace Test.Async;

public class TrySingleTest
{
Expand Down Expand Up @@ -61,4 +61,15 @@ public async Task TrySingleEnumeratesOnceOnlyAndDisposes(int numberOfElements, s
var (cardinality, _) = await seq.TrySingle("zero", "one", "many");
Assert.Equal(expectedCardinality, cardinality);
}

[Theory]
[InlineData(0, 0)]
[InlineData(1, 1)]
[InlineData(2, 0)]
public async Task TrySingleShouldReturnDefaultOrSingleValue(int numberOfElements, int expectedResult)
{
await using var seq = AsyncEnumerable.Range(1, numberOfElements).AsTestingSequence();
var result = await seq.TrySingle();
Assert.Equal(expectedResult, result);
}
}
Loading

0 comments on commit 636e2d0

Please sign in to comment.