Skip to content

Commit

Permalink
Add NullArgumentsTest to SuperLinq.Async (#476)
Browse files Browse the repository at this point in the history
* Add null-argument checking in `SuperLinq.Async`
* Update error-checking on `Fold`
* Update error-checking on `AggregateRight`
* Update error-checking on `Case`
* Update error-checking on `CollectionEqual`
* Update error-checking on `CompareCount`
* Update error-checking on `Do`
* Update error-checking on `ElementAt`
* Update error-checking on `EndsWith`
* Update error-checking on `FindIndex`
* Update error-checking on `FindLastIndex`
* Update error-checking on `ForEach`
* Update error-checking on `GetShortestPath`
* Update error-checking on `HasDuplicates`
* Update error-checking on `If`
* Update error-checking on `Lag`
* Update error-checking on `Lead`
* Update error-checking on `ScanBy`
* Update error-checking on `ScanRight`
* Update error-checking on `Segment`
* Update error-checking on `StartsWith`
* Update error-checking on `TrySingle`
* Update error-checking on `While`
  • Loading branch information
viceroypenguin committed Jun 23, 2023
1 parent 2abaf3b commit 6206d9d
Show file tree
Hide file tree
Showing 28 changed files with 1,062 additions and 362 deletions.
19 changes: 14 additions & 5 deletions Generators/SuperLinq.Async.Generator/Fold.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static partial class AsyncSuperEnumerable
/// <exception cref="global::System.InvalidOperationException">
/// <paramref name="source"/> does not contain exactly {{$i}} element{{if $i != 1}}s{{end}}.
/// </exception>
public static async global::System.Threading.Tasks.ValueTask<TResult> Fold<T, TResult>(this global::System.Collections.Generic.IAsyncEnumerable<T> source, global::System.Func<
public static global::System.Threading.Tasks.ValueTask<TResult> Fold<T, TResult>(this global::System.Collections.Generic.IAsyncEnumerable<T> source, global::System.Func<
{{~ for $j in 1..$i ~}}
T,
{{~ end ~}}
Expand All @@ -29,13 +29,22 @@ public static partial class AsyncSuperEnumerable
global::CommunityToolkit.Diagnostics.Guard.IsNotNull(source);
global::CommunityToolkit.Diagnostics.Guard.IsNotNull(folder);

var elements = await source.AssertCount({{$i}}).ToListAsync().ConfigureAwait(false);
return Core(source, folder);

return folder(
static async global::System.Threading.Tasks.ValueTask<TResult> Core(global::System.Collections.Generic.IAsyncEnumerable<T> source, global::System.Func<
{{~ for $j in 1..$i ~}}
elements[{{$j-1}}]{{ if !for.last }},{{ end }}
T,
{{~ end ~}}
);
TResult> folder)
{
var elements = await source.AssertCount({{$i}}).ToListAsync().ConfigureAwait(false);

return folder(
{{~ for $j in 1..$i ~}}
elements[{{$j-1}}]{{ if !for.last }},{{ end }}
{{~ end ~}}
);
}
}
{{ end ~}}
}
74 changes: 60 additions & 14 deletions Source/SuperLinq.Async/AggregateRight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public static partial class AsyncSuperEnumerable
/// </remarks>
public static ValueTask<TSource> AggregateRight<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, TSource, TSource> func, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(source);
Guard.IsNotNull(func);

return source.AggregateRight((a, b, ct) => new ValueTask<TSource>(func(a, b)), cancellationToken);
}

Expand All @@ -51,6 +54,9 @@ public static ValueTask<TSource> AggregateRight<TSource>(this IAsyncEnumerable<T
/// </remarks>
public static ValueTask<TSource> AggregateRight<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, TSource, ValueTask<TSource>> func, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(source);
Guard.IsNotNull(func);

return source.AggregateRight((a, b, ct) => func(a, b), cancellationToken);
}

Expand All @@ -75,22 +81,33 @@ public static ValueTask<TSource> AggregateRight<TSource>(this IAsyncEnumerable<T
/// <remarks>
/// This operator executes immediately.
/// </remarks>
public static async ValueTask<TSource> AggregateRight<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, TSource, CancellationToken, ValueTask<TSource>> func, CancellationToken cancellationToken = default)
public static ValueTask<TSource> AggregateRight<TSource>(
this IAsyncEnumerable<TSource> source,
Func<TSource, TSource, CancellationToken, ValueTask<TSource>> func,
CancellationToken cancellationToken = default)
{
Guard.IsNotNull(source);
Guard.IsNotNull(func);

await using var e = source.Reverse().GetConfiguredAsyncEnumerator(cancellationToken);
return Core(source, func, cancellationToken);

if (!await e.MoveNextAsync())
ThrowHelper.ThrowInvalidOperationException("Sequence contains no elements");
static async ValueTask<TSource> Core(
IAsyncEnumerable<TSource> source,
Func<TSource, TSource, CancellationToken, ValueTask<TSource>> func,
CancellationToken cancellationToken = default)
{
await using var e = source.Reverse().GetConfiguredAsyncEnumerator(cancellationToken);

var seed = e.Current;
if (!await e.MoveNextAsync())
ThrowHelper.ThrowInvalidOperationException("Sequence contains no elements");

while (await e.MoveNextAsync())
seed = await func(e.Current, seed, cancellationToken).ConfigureAwait(false);
var seed = e.Current;

return seed;
while (await e.MoveNextAsync())
seed = await func(e.Current, seed, cancellationToken).ConfigureAwait(false);

return seed;
}
}

/// <summary>
Expand Down Expand Up @@ -121,6 +138,9 @@ public static async ValueTask<TSource> AggregateRight<TSource>(this IAsyncEnumer

public static ValueTask<TAccumulate> AggregateRight<TSource, TAccumulate>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, TAccumulate> func, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(source);
Guard.IsNotNull(func);

return source.AggregateRight(seed, (a, b, ct) => new ValueTask<TAccumulate>(func(a, b)), cancellationToken);
}

Expand Down Expand Up @@ -152,6 +172,9 @@ public static ValueTask<TAccumulate> AggregateRight<TSource, TAccumulate>(this I

public static ValueTask<TAccumulate> AggregateRight<TSource, TAccumulate>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, ValueTask<TAccumulate>> func, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(source);
Guard.IsNotNull(func);

return source.AggregateRight(seed, (a, b, ct) => func(a, b), cancellationToken);
}

Expand Down Expand Up @@ -181,15 +204,24 @@ public static ValueTask<TAccumulate> AggregateRight<TSource, TAccumulate>(this I
/// This operator executes immediately.
/// </remarks>

public static async ValueTask<TAccumulate> AggregateRight<TSource, TAccumulate>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, CancellationToken, ValueTask<TAccumulate>> func, CancellationToken cancellationToken = default)
public static ValueTask<TAccumulate> AggregateRight<TSource, TAccumulate>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, CancellationToken, ValueTask<TAccumulate>> func, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(source);
Guard.IsNotNull(func);

await foreach (var i in source.Reverse().WithCancellation(cancellationToken).ConfigureAwait(false))
seed = await func(i, seed, cancellationToken).ConfigureAwait(false);
return Core(source, seed, func, cancellationToken);

static async ValueTask<TAccumulate> Core(
IAsyncEnumerable<TSource> source,
TAccumulate seed,
Func<TSource, TAccumulate, CancellationToken, ValueTask<TAccumulate>> func,
CancellationToken cancellationToken = default)
{
await foreach (var i in source.Reverse().WithCancellation(cancellationToken).ConfigureAwait(false))
seed = await func(i, seed, cancellationToken).ConfigureAwait(false);

return seed;
return seed;
}
}

/// <summary>
Expand Down Expand Up @@ -224,6 +256,9 @@ public static async ValueTask<TAccumulate> AggregateRight<TSource, TAccumulate>(

public static ValueTask<TResult> AggregateRight<TSource, TAccumulate, TResult>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, TAccumulate> func, Func<TAccumulate, TResult> resultSelector, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(func);
Guard.IsNotNull(resultSelector);

return source.AggregateRight(seed, (a, b, ct) => new ValueTask<TAccumulate>(func(a, b)), (a, ct) => new ValueTask<TResult>(resultSelector(a)), cancellationToken);
}

Expand Down Expand Up @@ -259,6 +294,9 @@ public static ValueTask<TResult> AggregateRight<TSource, TAccumulate, TResult>(t

public static ValueTask<TResult> AggregateRight<TSource, TAccumulate, TResult>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, ValueTask<TAccumulate>> func, Func<TAccumulate, ValueTask<TResult>> resultSelector, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(func);
Guard.IsNotNull(resultSelector);

return source.AggregateRight(seed, (a, b, ct) => func(a, b), (a, ct) => resultSelector(a), cancellationToken);
}

Expand Down Expand Up @@ -292,12 +330,20 @@ public static ValueTask<TResult> AggregateRight<TSource, TAccumulate, TResult>(t
/// This operator executes immediately.
/// </remarks>

public static async ValueTask<TResult> AggregateRight<TSource, TAccumulate, TResult>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, CancellationToken, ValueTask<TAccumulate>> func, Func<TAccumulate, CancellationToken, ValueTask<TResult>> resultSelector, CancellationToken cancellationToken = default)
public static ValueTask<TResult> AggregateRight<TSource, TAccumulate, TResult>(this IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, CancellationToken, ValueTask<TAccumulate>> func, Func<TAccumulate, CancellationToken, ValueTask<TResult>> resultSelector, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(source);
Guard.IsNotNull(func);
Guard.IsNotNull(resultSelector);

return await resultSelector(await source.AggregateRight(seed, func, cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
return Core(source, seed, func, resultSelector, cancellationToken);

static async ValueTask<TResult> Core(
IAsyncEnumerable<TSource> source,
TAccumulate seed,
Func<TSource, TAccumulate, CancellationToken, ValueTask<TAccumulate>> func,
Func<TAccumulate, CancellationToken, ValueTask<TResult>> resultSelector,
CancellationToken cancellationToken = default) =>
await resultSelector(await source.AggregateRight(seed, func, cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
}
}
9 changes: 9 additions & 0 deletions Source/SuperLinq.Async/Case.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public static IAsyncEnumerable<TResult> Case<TValue, TResult>(
IDictionary<TValue, IAsyncEnumerable<TResult>> sources)
where TValue : notnull
{
Guard.IsNotNull(selector);
Guard.IsNotNull(sources);

return Case(selector.ToAsync(), sources, AsyncEnumerable.Empty<TResult>());
}

Expand Down Expand Up @@ -57,6 +60,9 @@ public static IAsyncEnumerable<TResult> Case<TValue, TResult>(
IDictionary<TValue, IAsyncEnumerable<TResult>> sources)
where TValue : notnull
{
Guard.IsNotNull(selector);
Guard.IsNotNull(sources);

return Case(selector, sources, AsyncEnumerable.Empty<TResult>());
}

Expand All @@ -83,6 +89,9 @@ public static IAsyncEnumerable<TResult> Case<TValue, TResult>(
IAsyncEnumerable<TResult> defaultSource)
where TValue : notnull
{
Guard.IsNotNull(selector);
Guard.IsNotNull(sources);

return Case(selector.ToAsync(), sources, defaultSource);
}

Expand Down
25 changes: 17 additions & 8 deletions Source/SuperLinq.Async/CollectionEqual.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static ValueTask<bool> CollectionEqual<TSource>(
/// This method executes immediately.
/// </para>
/// </remarks>
public static async ValueTask<bool> CollectionEqual<TSource>(
public static ValueTask<bool> CollectionEqual<TSource>(
this IAsyncEnumerable<TSource> first,
IAsyncEnumerable<TSource> second,
IEqualityComparer<TSource>? comparer,
Expand All @@ -84,12 +84,21 @@ public static async ValueTask<bool> CollectionEqual<TSource>(
Guard.IsNotNull(first);
Guard.IsNotNull(second);

var firstSet = await first.CountBy(Identity, comparer)
.ToHashSetAsync(ValueTupleEqualityComparer.Create<TSource, int>(comparer, comparer2: null), cancellationToken)
.ConfigureAwait(false);
var secondSet = await second.CountBy(Identity, comparer)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
return firstSet.SetEquals(secondSet);
return Core(first, second, comparer, cancellationToken);

static async ValueTask<bool> Core(
IAsyncEnumerable<TSource> first,
IAsyncEnumerable<TSource> second,
IEqualityComparer<TSource>? comparer,
CancellationToken cancellationToken = default)
{
var firstSet = await first.CountBy(Identity, comparer)
.ToHashSetAsync(ValueTupleEqualityComparer.Create<TSource, int>(comparer, comparer2: null), cancellationToken)
.ConfigureAwait(false);
var secondSet = await second.CountBy(Identity, comparer)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
return firstSet.SetEquals(secondSet);
}
}
}
19 changes: 11 additions & 8 deletions Source/SuperLinq.Async/CountMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,26 +154,29 @@ private static async ValueTask<bool> QuantityIterator<T>(IAsyncEnumerable<T> sou
/// The <c>result</c> variable will contain <c>1</c>.
/// </example>

public static async ValueTask<int> CompareCount<TFirst, TSecond>(this IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, CancellationToken cancellationToken = default)
public static ValueTask<int> CompareCount<TFirst, TSecond>(this IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(first);
Guard.IsNotNull(second);

bool firstHasNext;
bool secondHasNext;

await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken);
await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken);
return Core(first, second, cancellationToken);

static async ValueTask<int> Core(IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, CancellationToken cancellationToken)
{
bool firstHasNext;
bool secondHasNext;

await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken);
await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken);

do
{
firstHasNext = await e1.MoveNextAsync();
secondHasNext = await e2.MoveNextAsync();
}
while (firstHasNext && secondHasNext);
}

return firstHasNext.CompareTo(secondHasNext);
return firstHasNext.CompareTo(secondHasNext);
}
}
}
19 changes: 19 additions & 0 deletions Source/SuperLinq.Async/Do.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public static partial class AsyncSuperEnumerable
/// </remarks>
public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSource> source, Action<TSource> onNext)
{
Guard.IsNotNull(source);
Guard.IsNotNull(onNext);

return Do(source, onNext.ToAsync(), onCompleted: () => default);
}

Expand All @@ -33,6 +36,9 @@ public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSourc
/// </remarks>
public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask> onNext)
{
Guard.IsNotNull(source);
Guard.IsNotNull(onNext);

return Do(source, onNext, onCompleted: () => default);
}

Expand Down Expand Up @@ -111,6 +117,10 @@ static async IAsyncEnumerable<TSource> Core(
/// </remarks>
public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
{
Guard.IsNotNull(source);
Guard.IsNotNull(onNext);
Guard.IsNotNull(onError);

return Do(source, onNext.ToAsync(), onError.ToAsync(), onCompleted: () => default);
}

Expand All @@ -129,6 +139,10 @@ public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSourc
/// </remarks>
public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask> onNext, Func<Exception, ValueTask> onError)
{
Guard.IsNotNull(source);
Guard.IsNotNull(onNext);
Guard.IsNotNull(onError);

return Do(source, onNext, onError, onCompleted: () => default);
}

Expand All @@ -149,6 +163,11 @@ public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSourc
/// </remarks>
public static IAsyncEnumerable<TSource> Do<TSource>(this IAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
{
Guard.IsNotNull(source);
Guard.IsNotNull(onNext);
Guard.IsNotNull(onError);
Guard.IsNotNull(onCompleted);

return Do(source, onNext.ToAsync(), onError.ToAsync(), onCompleted.ToAsync());
}

Expand Down
Loading

0 comments on commit 6206d9d

Please sign in to comment.