Skip to content

Commit

Permalink
Add Repeat operator (#280)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceroypenguin authored Mar 10, 2023
1 parent 82afd2a commit ac8c83b
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 4 deletions.
48 changes: 44 additions & 4 deletions Source/SuperLinq.Async/Repeat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ public partial class AsyncSuperEnumerable
/// <typeparam name="TResult">Result sequence element type.</typeparam>
/// <param name="value">Value to repeat in the resulting sequence.</param>
/// <returns>Sequence repeating the given value infinitely.</returns>
public static IAsyncEnumerable<TResult> Repeat<TResult>(TResult value)
public static async IAsyncEnumerable<TResult> Repeat<TResult>(TResult value)
{
throw new NotImplementedException();
await default(ValueTask);
while (true)
yield return value;
}

/// <summary>
Expand All @@ -22,7 +24,25 @@ public static IAsyncEnumerable<TResult> Repeat<TResult>(TResult value)
/// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
public static IAsyncEnumerable<TSource> Repeat<TSource>(this IAsyncEnumerable<TSource> source)
{
throw new NotImplementedException();
Guard.IsNotNull(source);

return Core(source);

static async IAsyncEnumerable<TSource> Core(
IAsyncEnumerable<TSource> source,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await using var buffer = source.Memoize();
while (true)
{
await foreach (var el in buffer
.WithCancellation(cancellationToken)
.ConfigureAwait(false))
{
yield return el;
}
}
}
}

/// <summary>
Expand All @@ -38,6 +58,26 @@ public static IAsyncEnumerable<TSource> Repeat<TSource>(this IAsyncEnumerable<TS
/// <c>0</c>.</exception>
public static IAsyncEnumerable<TSource> Repeat<TSource>(this IAsyncEnumerable<TSource> source, int count)
{
throw new NotImplementedException();
Guard.IsNotNull(source);
Guard.IsGreaterThan(count, 0);

return Core(source, count);

static async IAsyncEnumerable<TSource> Core(
IAsyncEnumerable<TSource> source,
int count,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await using var buffer = source.Memoize();
while (count-- > 0)
{
await foreach (var el in buffer
.WithCancellation(cancellationToken)
.ConfigureAwait(false))
{
yield return el;
}
}
}
}
}
68 changes: 68 additions & 0 deletions Tests/SuperLinq.Async.Test/RepeatTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
namespace Test.Async;

public class RepeatTest
{
[Theory]
[InlineData(1)]
[InlineData(10)]
[InlineData(50)]
public async Task RepeatItemForeverBehavior(int repeats)
{
var result = AsyncSuperEnumerable.Repeat(42);

Assert.True(await result
.Take(repeats)
.AssertCount(repeats)
.AllAsync(x => x == 42));
}

[Fact]
public void RepeatIsLazy()
{
_ = new AsyncBreakingSequence<int>().Repeat(4);
}

[Fact]
public void RepeatValidatesArguments()
{
_ = Assert.Throws<ArgumentOutOfRangeException>("count", () =>
new AsyncBreakingSequence<int>().Repeat(0));
}

[Fact]
public async Task RepeatBehavior()
{
await using var sequence = Enumerable.Range(1, 10).AsTestingSequence();

var result = sequence.Repeat(3);

var expected = Enumerable.Empty<int>();
for (var i = 0; i < 3; i++)
expected = expected.Concat(Enumerable.Range(1, 10));

await result.AssertSequenceEqual(expected);
}

[Fact]
public void RepeatForeverIsLazy()
{
_ = new AsyncBreakingSequence<int>().Repeat();
}

[Theory]
[InlineData(1)]
[InlineData(10)]
[InlineData(50)]
public async Task RepeatForeverBehavior(int repeats)
{
await using var sequence = Enumerable.Range(1, 10).AsTestingSequence();

var result = sequence.Repeat();

var expected = Enumerable.Empty<int>();
for (var i = 0; i < repeats; i++)
expected = expected.Concat(Enumerable.Range(1, 10));

await result.Take(repeats * 10).AssertSequenceEqual(expected);
}
}

0 comments on commit ac8c83b

Please sign in to comment.