From c3b89f7061c5c948c53e81afd7c4d8e6105d69a6 Mon Sep 17 00:00:00 2001 From: Bar Arnon Date: Sun, 1 Feb 2026 20:30:28 +0200 Subject: [PATCH 1/3] Generators | Aggregate --- .../Operators/AggregateTests.cs | 762 ++++++++++++++++++ 1 file changed, 762 insertions(+) create mode 100644 tests/MoreAsyncLINQ.Tests/Operators/AggregateTests.cs diff --git a/tests/MoreAsyncLINQ.Tests/Operators/AggregateTests.cs b/tests/MoreAsyncLINQ.Tests/Operators/AggregateTests.cs new file mode 100644 index 0000000..103707d --- /dev/null +++ b/tests/MoreAsyncLINQ.Tests/Operators/AggregateTests.cs @@ -0,0 +1,762 @@ +using MoreLinq; +using static System.Linq.AsyncEnumerable; + +namespace MoreAsyncLINQ.Tests; + +public class AggregateTests : AsyncEnumerableTests +{ + [Fact] + public void InvalidInputs_TwoAccumulators_Throws() + { + Assert.Throws( + "source", + () => + MoreAsyncEnumerable.AggregateAsync( + null!, + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + (a1, a2) => a1 + a2)); + + Assert.Throws( + "accumulator1", + () => + Empty(). + AggregateAsync( + 0, + null!, + 0, + (acc, x) => acc + x, + (a1, a2) => a1 + a2)); + + Assert.Throws( + "accumulator2", + () => + Empty(). + AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + null!, + (a1, a2) => a1 + a2)); + + Assert.Throws( + "resultSelector", + () => + Empty(). + AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + (Func)null!)); + + Assert.Throws( + "source", + () => + MoreAsyncEnumerable.AggregateAsync( + null!, + 0, + (acc, x, _) => ValueTask.FromResult(acc + x), + 0, + (acc, x, _) => ValueTask.FromResult(acc + x), + (a1, a2, _) => ValueTask.FromResult(a1 + a2))); + + Assert.Throws( + "accumulator1", + () => + Empty(). + AggregateAsync( + 0, + null!, + 0, + (acc, x, _) => ValueTask.FromResult(acc + x), + (a1, a2, _) => ValueTask.FromResult(a1 + a2))); + + Assert.Throws( + "accumulator2", + () => + Empty(). + AggregateAsync( + 0, + (acc, x, _) => ValueTask.FromResult(acc + x), + 0, + null!, + (a1, a2, _) => ValueTask.FromResult(a1 + a2))); + + Assert.Throws( + "resultSelector", + () => + Empty(). + AggregateAsync( + 0, + (acc, x, _) => ValueTask.FromResult(acc + x), + 0, + (acc, x, _) => ValueTask.FromResult(acc + x), + (Func>)null!)); + } + + [Fact] + public void InvalidInputs_ThreeAccumulators_Throws() + { + Assert.Throws( + "source", + () => + MoreAsyncEnumerable.AggregateAsync( + null!, + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + (a1, a2, a3) => a1 + a2 + a3)); + + Assert.Throws( + "accumulator1", + () => + Empty(). + AggregateAsync( + 0, + null!, + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + (a1, a2, a3) => a1 + a2 + a3)); + + Assert.Throws( + "accumulator2", + () => + Empty(). + AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + null!, + 0, + (acc, x) => acc + x, + (a1, a2, a3) => a1 + a2 + a3)); + + Assert.Throws( + "accumulator3", + () => + Empty(). + AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + 0, + null!, + (a1, a2, a3) => a1 + a2 + a3)); + + Assert.Throws( + "resultSelector", + () => + Empty(). + AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + (Func)null!)); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task EmptySequence_TwoAccumulators(bool isAsync) + { + var source = Empty(); + + var result = + isAsync + ? await source.AggregateAsync( + 10, + async (acc, x, _) => acc + x, + 20, + async (acc, x, _) => acc * x, + async (a1, a2, _) => (a1, a2)) + : await source.AggregateAsync( + 10, + (acc, x) => acc + x, + 20, + (acc, x) => acc * x, + (a1, a2) => (a1, a2)); + + Assert.Equal((10, 20), result); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task EmptySequence_ThreeAccumulators(bool isAsync) + { + var source = Empty(); + + var result = + isAsync + ? await source.AggregateAsync( + 10, + async (acc, x, _) => acc + x, + 20, + async (acc, x, _) => acc * x, + 30, + async (acc, x, _) => acc - x, + async (a1, a2, a3, _) => (a1, a2, a3)) + : await source.AggregateAsync( + 10, + (acc, x) => acc + x, + 20, + (acc, x) => acc * x, + 30, + (acc, x) => acc - x, + (a1, a2, a3) => (a1, a2, a3)); + + Assert.Equal((10, 20, 30), result); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task TwoAccumulators(bool isAsync) + { + var source = Enumerable.Range(1, 10).ToArray(); + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + (sum1, sum2) => new[] { sum1, sum2 }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, x, _) => acc + x, + 0, + async (acc, x, _) => acc + x, + async (sum1, sum2, _) => new[] { sum1, sum2 }) + : await asyncSource.AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => acc + x, + (sum1, sum2) => new[] { sum1, sum2 }); + + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task ThreeAccumulators(bool isAsync) + { + var source = Enumerable.Range(1, 10).ToArray(); + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, x) => acc + x, + 1, + (acc, x) => acc * x, + 0, + (acc, _) => acc + 1, + (sum, product, count) => new { Sum = sum, Product = product, Count = count }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, x, _) => acc + x, + 1, + async (acc, x, _) => acc * x, + 0, + async (acc, _, _) => acc + 1, + async (sum, product, count, _) => new { Sum = sum, Product = product, Count = count }) + : await asyncSource.AggregateAsync( + 0, + (acc, x) => acc + x, + 1, + (acc, x) => acc * x, + 0, + (acc, _) => acc + 1, + (sum, product, count) => new { Sum = sum, Product = product, Count = count }); + + Assert.Equal(expected.Sum, actual.Sum); + Assert.Equal(expected.Product, actual.Product); + Assert.Equal(expected.Count, actual.Count); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task FourAccumulators(bool isAsync) + { + var source = Enumerable.Range(1, 10).ToArray(); + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + (sum, evenSum, min, max) => new { Sum = sum, EvenSum = evenSum, Min = min, Max = max }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, x, _) => acc + x, + 0, + async (acc, x, _) => x % 2 == 0 ? acc + x : acc, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Max(n, x) : x, + async (sum, evenSum, min, max, _) => new { Sum = sum, EvenSum = evenSum, Min = min, Max = max }) + : await asyncSource.AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + (sum, evenSum, min, max) => new { Sum = sum, EvenSum = evenSum, Min = min, Max = max }); + + Assert.Equal(expected.Sum, actual.Sum); + Assert.Equal(expected.EvenSum, actual.EvenSum); + Assert.Equal(expected.Min, actual.Min); + Assert.Equal(expected.Max, actual.Max); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task FiveAccumulators(bool isAsync) + { + var source = Enumerable.Range(1, 10).ToArray(); + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + (sum, evenSum, count, min, max) => new { Sum = sum, EvenSum = evenSum, Count = count, Min = min, Max = max }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, x, _) => acc + x, + 0, + async (acc, x, _) => x % 2 == 0 ? acc + x : acc, + 0, + async (acc, _, _) => acc + 1, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Max(n, x) : x, + async (sum, evenSum, count, min, max, _) => new { Sum = sum, EvenSum = evenSum, Count = count, Min = min, Max = max }) + : await asyncSource.AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + (sum, evenSum, count, min, max) => new { Sum = sum, EvenSum = evenSum, Count = count, Min = min, Max = max }); + + Assert.Equal(expected.Sum, actual.Sum); + Assert.Equal(expected.EvenSum, actual.EvenSum); + Assert.Equal(expected.Count, actual.Count); + Assert.Equal(expected.Min, actual.Min); + Assert.Equal(expected.Max, actual.Max); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task SixAccumulators(bool isAsync) + { + var source = Enumerable.Range(1, 10).ToArray(); + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + new HashSet(), + (acc, x) => + { + acc.Add(x % 3); + return acc; + }, + (sum, evenSum, count, min, max, modulos) => new { Sum = sum, EvenSum = evenSum, Count = count, Min = min, Max = max, Modulos = modulos }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, x, _) => acc + x, + 0, + async (acc, x, _) => x % 2 == 0 ? acc + x : acc, + 0, + async (acc, _, _) => acc + 1, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Max(n, x) : x, + new HashSet(), + async (acc, x, _) => + { + acc.Add(x % 3); + return acc; + }, + async (sum, evenSum, count, min, max, modulos, _) => new { Sum = sum, EvenSum = evenSum, Count = count, Min = min, Max = max, Modulos = modulos }) + : await asyncSource.AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + new HashSet(), + (acc, x) => + { + acc.Add(x % 3); + return acc; + }, + (sum, evenSum, count, min, max, modulos) => new { Sum = sum, EvenSum = evenSum, Count = count, Min = min, Max = max, Modulos = modulos }); + + Assert.Equal(expected.Sum, actual.Sum); + Assert.Equal(expected.EvenSum, actual.EvenSum); + Assert.Equal(expected.Count, actual.Count); + Assert.Equal(expected.Min, actual.Min); + Assert.Equal(expected.Max, actual.Max); + Assert.Equal(expected.Modulos.OrderBy(x => x), actual.Modulos.OrderBy(x => x)); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task SevenAccumulators(bool isAsync) + { + var source = Enumerable.Range(1, 10).Select(n => new { Num = n, Str = n.ToString() }).ToArray(); + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, e) => acc + e.Num, + 0, + (acc, e) => e.Num % 2 == 0 ? acc + e.Num : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, e) => acc is { } n ? Math.Min(n, e.Num) : e.Num, + (int?)null, + (acc, e) => acc is { } n ? Math.Max(n, e.Num) : e.Num, + new HashSet(), + (acc, e) => + { + acc.Add(e.Str.Length); + return acc; + }, + new List<(int Num, string Str)>(), + (acc, e) => + { + acc.Add((e.Num, e.Str)); + return acc; + }, + (sum, evenSum, count, min, max, lengths, items) => new + { + Sum = sum, + EvenSum = evenSum, + Count = count, + Average = (double)sum / count, + Min = min ?? throw new InvalidOperationException(), + Max = max ?? throw new InvalidOperationException(), + UniqueLengths = lengths, + Items = items, + }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, e, _) => acc + e.Num, + 0, + async (acc, e, _) => e.Num % 2 == 0 ? acc + e.Num : acc, + 0, + async (acc, _, _) => acc + 1, + (int?)null, + async (acc, e, _) => acc is { } n ? Math.Min(n, e.Num) : e.Num, + (int?)null, + async (acc, e, _) => acc is { } n ? Math.Max(n, e.Num) : e.Num, + new HashSet(), + async (acc, e, _) => + { + acc.Add(e.Str.Length); + return acc; + }, + new List<(int Num, string Str)>(), + async (acc, e, _) => + { + acc.Add((e.Num, e.Str)); + return acc; + }, + async (sum, evenSum, count, min, max, lengths, items, _) => new + { + Sum = sum, + EvenSum = evenSum, + Count = count, + Average = (double)sum / count, + Min = min ?? throw new InvalidOperationException(), + Max = max ?? throw new InvalidOperationException(), + UniqueLengths = lengths, + Items = items, + }) + : await asyncSource.AggregateAsync( + 0, + (acc, e) => acc + e.Num, + 0, + (acc, e) => e.Num % 2 == 0 ? acc + e.Num : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, e) => acc is { } n ? Math.Min(n, e.Num) : e.Num, + (int?)null, + (acc, e) => acc is { } n ? Math.Max(n, e.Num) : e.Num, + new HashSet(), + (acc, e) => + { + acc.Add(e.Str.Length); + return acc; + }, + new List<(int Num, string Str)>(), + (acc, e) => + { + acc.Add((e.Num, e.Str)); + return acc; + }, + (sum, evenSum, count, min, max, lengths, items) => new + { + Sum = sum, + EvenSum = evenSum, + Count = count, + Average = (double)sum / count, + Min = min ?? throw new InvalidOperationException(), + Max = max ?? throw new InvalidOperationException(), + UniqueLengths = lengths, + Items = items, + }); + + Assert.Equal(expected.Sum, actual.Sum); + Assert.Equal(expected.EvenSum, actual.EvenSum); + Assert.Equal(expected.Count, actual.Count); + Assert.Equal(expected.Average, actual.Average); + Assert.Equal(expected.Min, actual.Min); + Assert.Equal(expected.Max, actual.Max); + Assert.Equal(expected.UniqueLengths.OrderBy(x => x), actual.UniqueLengths.OrderBy(x => x)); + Assert.Equal( + expected.Items.OrderBy(x => x.Num).ToArray(), + actual.Items.OrderBy(x => x.Num).ToArray()); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task EightAccumulators(bool isAsync) + { + var source = Enumerable.Range(1, 10).ToArray(); + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + 0, + (acc, x) => x % 2 != 0 ? acc + x : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + new HashSet(), + (acc, x) => + { + acc.Add(x % 3); + return acc; + }, + new List(), + (acc, x) => + { + acc.Add(x); + return acc; + }, + (sum, evenSum, oddSum, count, min, max, modulos, items) => new + { + Sum = sum, + EvenSum = evenSum, + OddSum = oddSum, + Count = count, + Min = min, + Max = max, + Modulos = modulos, + Items = items, + }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, x, _) => acc + x, + 0, + async (acc, x, _) => x % 2 == 0 ? acc + x : acc, + 0, + async (acc, x, _) => x % 2 != 0 ? acc + x : acc, + 0, + async (acc, _, _) => acc + 1, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + async (acc, x, _) => acc is { } n ? Math.Max(n, x) : x, + new HashSet(), + async (acc, x, _) => + { + acc.Add(x % 3); + return acc; + }, + new List(), + async (acc, x, _) => + { + acc.Add(x); + return acc; + }, + async (sum, evenSum, oddSum, count, min, max, modulos, items, _) => new + { + Sum = sum, + EvenSum = evenSum, + OddSum = oddSum, + Count = count, + Min = min, + Max = max, + Modulos = modulos, + Items = items, + }) + : await asyncSource.AggregateAsync( + 0, + (acc, x) => acc + x, + 0, + (acc, x) => x % 2 == 0 ? acc + x : acc, + 0, + (acc, x) => x % 2 != 0 ? acc + x : acc, + 0, + (acc, _) => acc + 1, + (int?)null, + (acc, x) => acc is { } n ? Math.Min(n, x) : x, + (int?)null, + (acc, x) => acc is { } n ? Math.Max(n, x) : x, + new HashSet(), + (acc, x) => + { + acc.Add(x % 3); + return acc; + }, + new List(), + (acc, x) => + { + acc.Add(x); + return acc; + }, + (sum, evenSum, oddSum, count, min, max, modulos, items) => new + { + Sum = sum, + EvenSum = evenSum, + OddSum = oddSum, + Count = count, + Min = min, + Max = max, + Modulos = modulos, + Items = items, + }); + + Assert.Equal(expected.Sum, actual.Sum); + Assert.Equal(expected.EvenSum, actual.EvenSum); + Assert.Equal(expected.OddSum, actual.OddSum); + Assert.Equal(expected.Count, actual.Count); + Assert.Equal(expected.Min, actual.Min); + Assert.Equal(expected.Max, actual.Max); + Assert.Equal(expected.Modulos.OrderBy(x => x), actual.Modulos.OrderBy(x => x)); + Assert.Equal(expected.Items, actual.Items); + } + + [Theory] + [MemberData(nameof(IsAsync))] + public async Task AccumulatorsWithDifferentTypes(bool isAsync) + { + var source = new[] { "one", "two", "three", "four", "five" }; + var asyncSource = source.ToAsyncEnumerable(); + + var expected = + source.Aggregate( + 0, + (acc, s) => acc + s.Length, + "", + (acc, s) => acc + s[0], + (totalLength, firstChars) => new { TotalLength = totalLength, FirstChars = firstChars }); + + var actual = + isAsync + ? await asyncSource.AggregateAsync( + 0, + async (acc, s, _) => acc + s.Length, + "", + async (acc, s, _) => acc + s[0], + async (totalLength, firstChars, _) => new { TotalLength = totalLength, FirstChars = firstChars }) + : await asyncSource.AggregateAsync( + 0, + (acc, s) => acc + s.Length, + "", + (acc, s) => acc + s[0], + (totalLength, firstChars) => new { TotalLength = totalLength, FirstChars = firstChars }); + + Assert.Equal(expected.TotalLength, actual.TotalLength); + Assert.Equal(expected.FirstChars, actual.FirstChars); + } +} + From 7dccbd1068f2b34e11d26a9f1ff10e434a6fbed4 Mon Sep 17 00:00:00 2001 From: Bar Arnon Date: Sun, 1 Feb 2026 20:32:23 +0200 Subject: [PATCH 2/3] . --- src/MoreAsyncLINQ/Operators/Aggregate.cs | 1668 ---------------------- 1 file changed, 1668 deletions(-) delete mode 100644 src/MoreAsyncLINQ/Operators/Aggregate.cs diff --git a/src/MoreAsyncLINQ/Operators/Aggregate.cs b/src/MoreAsyncLINQ/Operators/Aggregate.cs deleted file mode 100644 index 2d0ac64..0000000 --- a/src/MoreAsyncLINQ/Operators/Aggregate.cs +++ /dev/null @@ -1,1668 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MoreAsyncLINQ; - -static partial class MoreAsyncEnumerable -{ - /// - /// Applies two accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - Func resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return source.IsKnownEmpty() - ? ValueTasks.FromResult( - resultSelector( - seed1, - seed2)) - : Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - Func resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = accumulator1(accumulate1, element); - accumulate2 = accumulator2(accumulate2, element); - } - - return resultSelector( - accumulate1, - accumulate2); - } - } - - /// - /// Applies three accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - Func resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return source.IsKnownEmpty() - ? ValueTasks.FromResult( - resultSelector( - seed1, - seed2, - seed3)) - : Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - Func resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = accumulator1(accumulate1, element); - accumulate2 = accumulator2(accumulate2, element); - accumulate3 = accumulator3(accumulate3, element); - } - - return resultSelector( - accumulate1, - accumulate2, - accumulate3); - } - } - - /// - /// Applies four accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - Func resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return source.IsKnownEmpty() - ? ValueTasks.FromResult( - resultSelector( - seed1, - seed2, - seed3, - seed4)) - : Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - Func resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = accumulator1(accumulate1, element); - accumulate2 = accumulator2(accumulate2, element); - accumulate3 = accumulator3(accumulate3, element); - accumulate4 = accumulator4(accumulate4, element); - } - - return resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4); - } - } - - /// - /// Applies five accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - Func resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return source.IsKnownEmpty() - ? ValueTasks.FromResult( - resultSelector( - seed1, - seed2, - seed3, - seed4, - seed5)) - : Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - Func resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = accumulator1(accumulate1, element); - accumulate2 = accumulator2(accumulate2, element); - accumulate3 = accumulator3(accumulate3, element); - accumulate4 = accumulator4(accumulate4, element); - accumulate5 = accumulator5(accumulate5, element); - } - - return resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5); - } - } - - /// - /// Applies six accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of sixth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// The seed value for the sixth accumulator. - /// The sixth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TAccumulate6, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - TAccumulate6 seed6, - Func accumulator6, - Func resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (accumulator6 is null) throw new ArgumentNullException(nameof(accumulator6)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return source.IsKnownEmpty() - ? ValueTasks.FromResult( - resultSelector( - seed1, - seed2, - seed3, - seed4, - seed5, - seed6)) - : Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - seed6, - accumulator6, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - TAccumulate6 seed6, - Func accumulator6, - Func resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - var accumulate6 = seed6; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = accumulator1(accumulate1, element); - accumulate2 = accumulator2(accumulate2, element); - accumulate3 = accumulator3(accumulate3, element); - accumulate4 = accumulator4(accumulate4, element); - accumulate5 = accumulator5(accumulate5, element); - accumulate6 = accumulator6(accumulate6, element); - } - - return resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5, - accumulate6); - } - } - - /// - /// Applies seven accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of sixth accumulator value. - /// The type of seventh accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// The seed value for the sixth accumulator. - /// The sixth accumulator. - /// The seed value for the seventh accumulator. - /// The seventh accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TAccumulate6, - TAccumulate7, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - TAccumulate6 seed6, - Func accumulator6, - TAccumulate7 seed7, - Func accumulator7, - Func resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (accumulator6 is null) throw new ArgumentNullException(nameof(accumulator6)); - if (accumulator7 is null) throw new ArgumentNullException(nameof(accumulator7)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return source.IsKnownEmpty() - ? ValueTasks.FromResult( - resultSelector( - seed1, - seed2, - seed3, - seed4, - seed5, - seed6, - seed7)) - : Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - seed6, - accumulator6, - seed7, - accumulator7, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - TAccumulate6 seed6, - Func accumulator6, - TAccumulate7 seed7, - Func accumulator7, - Func resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - var accumulate6 = seed6; - var accumulate7 = seed7; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = accumulator1(accumulate1, element); - accumulate2 = accumulator2(accumulate2, element); - accumulate3 = accumulator3(accumulate3, element); - accumulate4 = accumulator4(accumulate4, element); - accumulate5 = accumulator5(accumulate5, element); - accumulate6 = accumulator6(accumulate6, element); - accumulate7 = accumulator7(accumulate7, element); - } - - return resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5, - accumulate6, - accumulate7); - } - } - - /// - /// Applies eight accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of sixth accumulator value. - /// The type of seventh accumulator value. - /// The type of eighth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// The seed value for the sixth accumulator. - /// The sixth accumulator. - /// The seed value for the seventh accumulator. - /// The seventh accumulator. - /// The seed value for the eighth accumulator. - /// The eighth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TAccumulate6, - TAccumulate7, - TAccumulate8, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - TAccumulate6 seed6, - Func accumulator6, - TAccumulate7 seed7, - Func accumulator7, - TAccumulate8 seed8, - Func accumulator8, - Func resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (accumulator6 is null) throw new ArgumentNullException(nameof(accumulator6)); - if (accumulator7 is null) throw new ArgumentNullException(nameof(accumulator7)); - if (accumulator8 is null) throw new ArgumentNullException(nameof(accumulator8)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return source.IsKnownEmpty() - ? ValueTasks.FromResult( - resultSelector( - seed1, - seed2, - seed3, - seed4, - seed5, - seed6, - seed7, - seed8)) - : Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - seed6, - accumulator6, - seed7, - accumulator7, - seed8, - accumulator8, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func accumulator1, - TAccumulate2 seed2, - Func accumulator2, - TAccumulate3 seed3, - Func accumulator3, - TAccumulate4 seed4, - Func accumulator4, - TAccumulate5 seed5, - Func accumulator5, - TAccumulate6 seed6, - Func accumulator6, - TAccumulate7 seed7, - Func accumulator7, - TAccumulate8 seed8, - Func accumulator8, - Func resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - var accumulate6 = seed6; - var accumulate7 = seed7; - var accumulate8 = seed8; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = accumulator1(accumulate1, element); - accumulate2 = accumulator2(accumulate2, element); - accumulate3 = accumulator3(accumulate3, element); - accumulate4 = accumulator4(accumulate4, element); - accumulate5 = accumulator5(accumulate5, element); - accumulate6 = accumulator6(accumulate6, element); - accumulate7 = accumulator7(accumulate7, element); - accumulate8 = accumulator8(accumulate8, element); - } - - return resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5, - accumulate6, - accumulate7, - accumulate8); - } - } - /// - /// Applies two accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - Func> resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - Func> resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = await accumulator1(accumulate1, element, cancellationToken); - accumulate2 = await accumulator2(accumulate2, element, cancellationToken); - } - - return await resultSelector( - accumulate1, - accumulate2, - cancellationToken); - } - } - - /// - /// Applies three accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - Func> resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - Func> resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = await accumulator1(accumulate1, element, cancellationToken); - accumulate2 = await accumulator2(accumulate2, element, cancellationToken); - accumulate3 = await accumulator3(accumulate3, element, cancellationToken); - } - - return await resultSelector( - accumulate1, - accumulate2, - accumulate3, - cancellationToken); - } - } - - /// - /// Applies four accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - Func> resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - Func> resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = await accumulator1(accumulate1, element, cancellationToken); - accumulate2 = await accumulator2(accumulate2, element, cancellationToken); - accumulate3 = await accumulator3(accumulate3, element, cancellationToken); - accumulate4 = await accumulator4(accumulate4, element, cancellationToken); - } - - return await resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - cancellationToken); - } - } - - /// - /// Applies five accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - Func> resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - Func> resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = await accumulator1(accumulate1, element, cancellationToken); - accumulate2 = await accumulator2(accumulate2, element, cancellationToken); - accumulate3 = await accumulator3(accumulate3, element, cancellationToken); - accumulate4 = await accumulator4(accumulate4, element, cancellationToken); - accumulate5 = await accumulator5(accumulate5, element, cancellationToken); - } - - return await resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5, - cancellationToken); - } - } - - /// - /// Applies six accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of sixth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// The seed value for the sixth accumulator. - /// The sixth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TAccumulate6, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - TAccumulate6 seed6, - Func> accumulator6, - Func> resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (accumulator6 is null) throw new ArgumentNullException(nameof(accumulator6)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - seed6, - accumulator6, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - TAccumulate6 seed6, - Func> accumulator6, - Func> resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - var accumulate6 = seed6; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = await accumulator1(accumulate1, element, cancellationToken); - accumulate2 = await accumulator2(accumulate2, element, cancellationToken); - accumulate3 = await accumulator3(accumulate3, element, cancellationToken); - accumulate4 = await accumulator4(accumulate4, element, cancellationToken); - accumulate5 = await accumulator5(accumulate5, element, cancellationToken); - accumulate6 = await accumulator6(accumulate6, element, cancellationToken); - } - - return await resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5, - accumulate6, - cancellationToken); - } - } - - /// - /// Applies seven accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of sixth accumulator value. - /// The type of seventh accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// The seed value for the sixth accumulator. - /// The sixth accumulator. - /// The seed value for the seventh accumulator. - /// The seventh accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TAccumulate6, - TAccumulate7, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - TAccumulate6 seed6, - Func> accumulator6, - TAccumulate7 seed7, - Func> accumulator7, - Func> resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (accumulator6 is null) throw new ArgumentNullException(nameof(accumulator6)); - if (accumulator7 is null) throw new ArgumentNullException(nameof(accumulator7)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - seed6, - accumulator6, - seed7, - accumulator7, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - TAccumulate6 seed6, - Func> accumulator6, - TAccumulate7 seed7, - Func> accumulator7, - Func> resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - var accumulate6 = seed6; - var accumulate7 = seed7; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = await accumulator1(accumulate1, element, cancellationToken); - accumulate2 = await accumulator2(accumulate2, element, cancellationToken); - accumulate3 = await accumulator3(accumulate3, element, cancellationToken); - accumulate4 = await accumulator4(accumulate4, element, cancellationToken); - accumulate5 = await accumulator5(accumulate5, element, cancellationToken); - accumulate6 = await accumulator6(accumulate6, element, cancellationToken); - accumulate7 = await accumulator7(accumulate7, element, cancellationToken); - } - - return await resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5, - accumulate6, - accumulate7, - cancellationToken); - } - } - - /// - /// Applies eight accumulators sequentially in a single pass over a - /// sequence. - /// - /// The type of elements in . - /// The type of first accumulator value. - /// The type of second accumulator value. - /// The type of third accumulator value. - /// The type of fourth accumulator value. - /// The type of fifth accumulator value. - /// The type of sixth accumulator value. - /// The type of seventh accumulator value. - /// The type of eighth accumulator value. - /// The type of the accumulated result. - /// The source sequence - /// The seed value for the first accumulator. - /// The first accumulator. - /// The seed value for the second accumulator. - /// The second accumulator. - /// The seed value for the third accumulator. - /// The third accumulator. - /// The seed value for the fourth accumulator. - /// The fourth accumulator. - /// The seed value for the fifth accumulator. - /// The fifth accumulator. - /// The seed value for the sixth accumulator. - /// The sixth accumulator. - /// The seed value for the seventh accumulator. - /// The seventh accumulator. - /// The seed value for the eighth accumulator. - /// The eighth accumulator. - /// - /// A function that projects a single result given the result of each - /// accumulator. - /// The optional cancellation token to be used for cancelling the sequence at any time. - /// The value returned by . - /// - /// This operator executes immediately. - /// - public static ValueTask AggregateAsync< - TSource, - TAccumulate1, - TAccumulate2, - TAccumulate3, - TAccumulate4, - TAccumulate5, - TAccumulate6, - TAccumulate7, - TAccumulate8, - TResult>( - this IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - TAccumulate6 seed6, - Func> accumulator6, - TAccumulate7 seed7, - Func> accumulator7, - TAccumulate8 seed8, - Func> accumulator8, - Func> resultSelector, - CancellationToken cancellationToken = default) - { - if (source is null) throw new ArgumentNullException(nameof(source)); - if (accumulator1 is null) throw new ArgumentNullException(nameof(accumulator1)); - if (accumulator2 is null) throw new ArgumentNullException(nameof(accumulator2)); - if (accumulator3 is null) throw new ArgumentNullException(nameof(accumulator3)); - if (accumulator4 is null) throw new ArgumentNullException(nameof(accumulator4)); - if (accumulator5 is null) throw new ArgumentNullException(nameof(accumulator5)); - if (accumulator6 is null) throw new ArgumentNullException(nameof(accumulator6)); - if (accumulator7 is null) throw new ArgumentNullException(nameof(accumulator7)); - if (accumulator8 is null) throw new ArgumentNullException(nameof(accumulator8)); - if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector)); - - return Core( - source, - seed1, - accumulator1, - seed2, - accumulator2, - seed3, - accumulator3, - seed4, - accumulator4, - seed5, - accumulator5, - seed6, - accumulator6, - seed7, - accumulator7, - seed8, - accumulator8, - resultSelector, - cancellationToken); - - static async ValueTask Core( - IAsyncEnumerable source, - TAccumulate1 seed1, - Func> accumulator1, - TAccumulate2 seed2, - Func> accumulator2, - TAccumulate3 seed3, - Func> accumulator3, - TAccumulate4 seed4, - Func> accumulator4, - TAccumulate5 seed5, - Func> accumulator5, - TAccumulate6 seed6, - Func> accumulator6, - TAccumulate7 seed7, - Func> accumulator7, - TAccumulate8 seed8, - Func> accumulator8, - Func> resultSelector, - CancellationToken cancellationToken) - { - var accumulate1 = seed1; - var accumulate2 = seed2; - var accumulate3 = seed3; - var accumulate4 = seed4; - var accumulate5 = seed5; - var accumulate6 = seed6; - var accumulate7 = seed7; - var accumulate8 = seed8; - - await foreach (var element in source.WithCancellation(cancellationToken)) - { - accumulate1 = await accumulator1(accumulate1, element, cancellationToken); - accumulate2 = await accumulator2(accumulate2, element, cancellationToken); - accumulate3 = await accumulator3(accumulate3, element, cancellationToken); - accumulate4 = await accumulator4(accumulate4, element, cancellationToken); - accumulate5 = await accumulator5(accumulate5, element, cancellationToken); - accumulate6 = await accumulator6(accumulate6, element, cancellationToken); - accumulate7 = await accumulator7(accumulate7, element, cancellationToken); - accumulate8 = await accumulator8(accumulate8, element, cancellationToken); - } - - return await resultSelector( - accumulate1, - accumulate2, - accumulate3, - accumulate4, - accumulate5, - accumulate6, - accumulate7, - accumulate8, - cancellationToken); - } - } -} \ No newline at end of file From 4d60c9a7e39e5f46c3d1d0aa4c4cdeb1b4b17976 Mon Sep 17 00:00:00 2001 From: Bar Arnon Date: Sun, 1 Feb 2026 20:32:30 +0200 Subject: [PATCH 3/3] . --- .../AggregateGenerator.cs | 319 ++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 src/MoreAsyncLINQ.Generators/AggregateGenerator.cs diff --git a/src/MoreAsyncLINQ.Generators/AggregateGenerator.cs b/src/MoreAsyncLINQ.Generators/AggregateGenerator.cs new file mode 100644 index 0000000..3a3819d --- /dev/null +++ b/src/MoreAsyncLINQ.Generators/AggregateGenerator.cs @@ -0,0 +1,319 @@ +using System.CodeDom.Compiler; +using System.IO; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace MoreAsyncLINQ.Generators; + +[Generator] +public class AggregateGenerator : IIncrementalGenerator +{ + private const int MinAccumulators = 2; + private const int MaxAccumulators = 8; + + private static readonly string[] _ordinals = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth"]; + + public void Initialize(IncrementalGeneratorInitializationContext context) => + context.RegisterPostInitializationOutput(postInitializationContext => + { + var source = GenerateOverloads(); + postInitializationContext.AddSource("MoreAsyncEnumerable.Aggregate.g.cs", source); + }); + + private string GenerateOverloads() + { + using var stringWriter = new StringWriter(); + using var writer = new IndentedTextWriter(stringWriter); + + writer.WriteLine("// "); + writer.WriteLine("#nullable enable"); + writer.WriteLine(); + writer.WriteLine("using System;"); + writer.WriteLine("using System.Collections.Generic;"); + writer.WriteLine("using System.Linq;"); + writer.WriteLine("using System.Threading;"); + writer.WriteLine("using System.Threading.Tasks;"); + writer.WriteLine(); + writer.WriteLine("namespace MoreAsyncLINQ;"); + writer.WriteLine(); + writer.WriteLine("static partial class MoreAsyncEnumerable"); + writer.WriteLine("{"); + writer.Indent++; + + for (var arity = MinAccumulators; arity <= MaxAccumulators; arity++) + { + GenerateSyncOverload(writer, arity); + writer.WriteLine(); + GenerateAsyncOverload(writer, arity); + + if (arity < MaxAccumulators) + { + writer.WriteLine(); + } + } + + writer.Indent--; + writer.WriteLine("}"); + + return stringWriter.ToString(); + } + + private void GenerateSyncOverload(IndentedTextWriter writer, int arity) + { + WriteXmlDocumentation(writer, arity); + WriteMethodSignature(writer, arity, isAsync: false); + + writer.WriteLine("{"); + writer.Indent++; + + WriteNullChecks(writer, arity); + writer.WriteLine(); + + writer.WriteLine("return source.IsKnownEmpty()"); + writer.Indent++; + writer.WriteLine("? ValueTasks.FromResult("); + writer.Indent++; + writer.WriteLine("resultSelector("); + writer.Indent++; + WriteSeedArgs(writer, arity); + writer.WriteLine("))"); + writer.Indent--; + writer.Indent--; + writer.WriteLine(": Core("); + writer.Indent++; + WriteCoreCallArgs(writer, arity); + writer.WriteLine(");"); + writer.Indent--; + writer.Indent--; + + writer.WriteLine(); + WriteCoreMethod(writer, arity, isAsync: false); + + writer.Indent--; + writer.WriteLine("}"); + } + + private void GenerateAsyncOverload(IndentedTextWriter writer, int arity) + { + WriteXmlDocumentation(writer, arity); + WriteMethodSignature(writer, arity, isAsync: true); + + writer.WriteLine("{"); + writer.Indent++; + + WriteNullChecks(writer, arity); + writer.WriteLine(); + + writer.WriteLine("return Core("); + writer.Indent++; + WriteCoreCallArgs(writer, arity); + writer.WriteLine(");"); + writer.Indent--; + + writer.WriteLine(); + WriteCoreMethod(writer, arity, isAsync: true); + + writer.Indent--; + writer.WriteLine("}"); + } + + private void WriteXmlDocumentation(IndentedTextWriter writer, int arity) + { + writer = new IndentedTextWriter(writer, "/// "); + writer.Indent++; + + writer.WriteLine(""); + writer.WriteLine($"Applies {_ordinals[arity - 1]} accumulators sequentially in a single pass over a"); + writer.WriteLine("sequence."); + writer.WriteLine(""); + writer.WriteLine("The type of elements in ."); + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"The type of {_ordinals[index - 1]} accumulator value."); + } + + writer.WriteLine("The type of the accumulated result."); + writer.WriteLine("The source sequence"); + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"The seed value for the {_ordinals[index - 1]} accumulator."); + writer.WriteLine($"The {_ordinals[index - 1]} accumulator."); + } + + writer.WriteLine(""); + writer.WriteLine("A function that projects a single result given the result of each"); + writer.WriteLine("accumulator."); + writer.WriteLine("The optional cancellation token to be used for cancelling the sequence at any time."); + writer.WriteLine("The value returned by ."); + writer.WriteLine(""); + writer.WriteLine("This operator executes immediately."); + writer.WriteLine(""); + } + + private void WriteMethodSignature(IndentedTextWriter writer, int arity, bool isAsync) + { + writer.WriteLine("public static ValueTask AggregateAsync<"); + writer.Indent++; + + // Type parameters + writer.WriteLine("TSource,"); + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"TAccumulate{index},"); + } + writer.WriteLine("TResult>("); + + // Method parameters + writer.WriteLine("this IAsyncEnumerable source,"); + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"TAccumulate{index} seed{index},"); + + var funcType = + isAsync + ? $"Func>" + : $"Func"; + + writer.WriteLine($"{funcType} accumulator{index},"); + } + + var resultSelectorTypes = string.Join(", ", Enumerable.Range(1, arity).Select(index => $"TAccumulate{index}")); + var resultSelectorType = + isAsync + ? $"Func<{resultSelectorTypes}, CancellationToken, ValueTask>" + : $"Func<{resultSelectorTypes}, TResult>"; + + writer.WriteLine($"{resultSelectorType} resultSelector,"); + writer.WriteLine("CancellationToken cancellationToken = default)"); + + writer.Indent--; + } + + private void WriteNullChecks(IndentedTextWriter writer, int arity) + { + writer.WriteLine("if (source is null) throw new ArgumentNullException(nameof(source));"); + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"if (accumulator{index} is null) throw new ArgumentNullException(nameof(accumulator{index}));"); + } + + writer.WriteLine("if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector));"); + } + + private void WriteCoreCallArgs(IndentedTextWriter writer, int arity) + { + writer.WriteLine("source,"); + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"seed{index},"); + writer.WriteLine($"accumulator{index},"); + } + + writer.WriteLine("resultSelector,"); + writer.Write("cancellationToken"); + } + + private void WriteSeedArgs(IndentedTextWriter writer, int arity) + { + for (var index = 1; index <= arity; index++) + { + writer.Write($"seed{index}"); + + if (index < arity) + { + writer.WriteLine(","); + } + } + } + + private void WriteCoreMethod(IndentedTextWriter writer, int arity, bool isAsync) + { + writer.WriteLine("static async ValueTask Core("); + writer.Indent++; + + writer.WriteLine("IAsyncEnumerable source,"); + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"TAccumulate{index} seed{index},"); + + var funcType = + isAsync + ? $"Func>" + : $"Func"; + + writer.WriteLine($"{funcType} accumulator{index},"); + } + + var resultSelectorTypes = string.Join(", ", Enumerable.Range(1, arity).Select(index => $"TAccumulate{index}")); + var resultSelectorType = + isAsync + ? $"Func<{resultSelectorTypes}, CancellationToken, ValueTask>" + : $"Func<{resultSelectorTypes}, TResult>"; + + writer.WriteLine($"{resultSelectorType} resultSelector,"); + writer.WriteLine("CancellationToken cancellationToken)"); + + writer.Indent--; + writer.WriteLine("{"); + writer.Indent++; + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"var accumulate{index} = seed{index};"); + } + + writer.WriteLine(); + writer.WriteLine("await foreach (var element in source.WithCancellation(cancellationToken))"); + writer.WriteLine("{"); + writer.Indent++; + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine( + isAsync + ? $"accumulate{index} = await accumulator{index}(accumulate{index}, element, cancellationToken);" + : $"accumulate{index} = accumulator{index}(accumulate{index}, element);"); + } + + writer.Indent--; + writer.WriteLine("}"); + writer.WriteLine(); + + if (isAsync) + { + writer.WriteLine("return await resultSelector("); + writer.Indent++; + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine($"accumulate{index},"); + } + + writer.WriteLine("cancellationToken);"); + } + else + { + writer.WriteLine("return resultSelector("); + writer.Indent++; + + for (var index = 1; index <= arity; index++) + { + writer.WriteLine( + index < arity + ? $"accumulate{index}," + : $"accumulate{index});"); + } + } + + writer.Indent--; + + writer.Indent--; + writer.WriteLine("}"); + } +}