Skip to content

Commit f87d3fa

Browse files
committed
Copy all Async classes and fix the types due to the change to System.Linq.Async
1 parent 974a9f9 commit f87d3fa

67 files changed

Lines changed: 4481 additions & 55 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#if INTEGRATED_ASYNC
2+
namespace Funcky;
3+
4+
public static partial class AsyncSequence
5+
{
6+
/// <summary>
7+
/// Concatenates multiple sequences together.
8+
/// </summary>
9+
[Pure]
10+
public static IAsyncEnumerable<TSource> Concat<TSource>(params IAsyncEnumerable<TSource>[] sources)
11+
=> Concat(sources.AsEnumerable());
12+
13+
/// <summary>
14+
/// Concatenates multiple sequences together.
15+
/// </summary>
16+
[Pure]
17+
public static IAsyncEnumerable<TSource> Concat<TSource>(IAsyncEnumerable<IAsyncEnumerable<TSource>> sources)
18+
=> sources
19+
.SelectMany(Identity);
20+
21+
/// <summary>
22+
/// Concatenates multiple sequences together.
23+
/// </summary>
24+
[Pure]
25+
public static IAsyncEnumerable<TSource> Concat<TSource>(IEnumerable<IAsyncEnumerable<TSource>> sources)
26+
=> sources.ToAsyncEnumerable()
27+
.SelectMany(Identity);
28+
29+
/// <summary>
30+
/// Concatenates multiple sequences together.
31+
/// </summary>
32+
[Pure]
33+
public static IAsyncEnumerable<TSource> Concat<TSource>(IAsyncEnumerable<IEnumerable<TSource>> sources)
34+
=> sources
35+
.SelectMany(AsyncEnumerable.ToAsyncEnumerable);
36+
}
37+
#endif
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#if INTEGRATED_ASYNC
2+
using static Funcky.ValueTaskFactory;
3+
4+
namespace Funcky;
5+
6+
public static partial class AsyncSequence
7+
{
8+
/// <summary>
9+
/// Cycles the same element over and over again as an endless generator.
10+
/// </summary>
11+
/// <typeparam name="TResult">Type of the element to be cycled.</typeparam>
12+
/// <param name="element">The element to be cycled.</param>
13+
/// <returns>Returns an infinite IEnumerable cycling through the same elements.</returns>
14+
[Pure]
15+
public static IAsyncEnumerable<TResult> Cycle<TResult>(TResult element)
16+
=> Successors(element, ValueTaskFromResult);
17+
}
18+
#endif
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#if INTEGRATED_ASYNC
2+
#pragma warning disable SA1010 // StyleCop support for collection expressions is missing
3+
namespace Funcky;
4+
5+
public static partial class AsyncSequence
6+
{
7+
/// <summary>
8+
/// Generates a sequence that contains the same sequence of elements over and over again as an endless generator.
9+
/// </summary>
10+
/// <typeparam name="TSource">Type of the elements to be cycled.</typeparam>
11+
/// <param name="sequence">The sequence of elements which are cycled. Throws an exception if the sequence is empty.</param>
12+
/// <returns>Returns an infinite IEnumerable repeating the same sequence of elements.</returns>
13+
[Pure]
14+
public static IAsyncBuffer<TSource> CycleRange<TSource>(IAsyncEnumerable<TSource> sequence)
15+
=> CycleBuffer.Create(sequence);
16+
17+
private static class CycleBuffer
18+
{
19+
public static AsyncCycleBuffer<TSource> Create<TSource>(IAsyncEnumerable<TSource> source, Option<int> maxCycles = default)
20+
=> new(source, maxCycles);
21+
}
22+
23+
private sealed class AsyncCycleBuffer<T>(IAsyncEnumerable<T> source, Option<int> maxCycles = default) : IAsyncBuffer<T>
24+
{
25+
private readonly List<T> _buffer = [];
26+
private readonly IAsyncEnumerator<T> _source = source.GetAsyncEnumerator();
27+
28+
private bool _disposed;
29+
30+
public async ValueTask DisposeAsync()
31+
{
32+
if (!_disposed)
33+
{
34+
await _source.DisposeAsync().ConfigureAwait(false);
35+
_buffer.Clear();
36+
_disposed = true;
37+
}
38+
}
39+
40+
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
41+
{
42+
ThrowIfDisposed();
43+
44+
return GetEnumeratorInternal();
45+
}
46+
47+
private async IAsyncEnumerator<T> GetEnumeratorInternal()
48+
{
49+
if (HasNoCycles())
50+
{
51+
yield break;
52+
}
53+
54+
for (var index = 0; true; ++index)
55+
{
56+
ThrowIfDisposed();
57+
58+
if (index == _buffer.Count)
59+
{
60+
if (await _source.MoveNextAsync().ConfigureAwait(false))
61+
{
62+
_buffer.Add(_source.Current);
63+
}
64+
else
65+
{
66+
break;
67+
}
68+
}
69+
70+
yield return _buffer[index];
71+
}
72+
73+
if (_buffer.Count is 0)
74+
{
75+
if (maxCycles.Match(none: true, some: False))
76+
{
77+
throw new InvalidOperationException("you cannot cycle an empty enumerable");
78+
}
79+
else
80+
{
81+
yield break;
82+
}
83+
}
84+
85+
// this can change on Dispose!
86+
var bufferCount = _buffer.Count;
87+
88+
for (int cycle = 1; IsCycling(cycle); ++cycle)
89+
{
90+
for (var index = 0; index < bufferCount; ++index)
91+
{
92+
ThrowIfDisposed();
93+
94+
yield return _buffer[index];
95+
}
96+
}
97+
}
98+
99+
private bool HasNoCycles()
100+
=> maxCycles.Match(none: false, some: maxCycles => maxCycles is 0);
101+
102+
private bool IsCycling(int cycle)
103+
=> maxCycles.Match(
104+
none: true,
105+
some: maxCycles => cycle < maxCycles);
106+
107+
private void ThrowIfDisposed()
108+
{
109+
if (_disposed)
110+
{
111+
throw new ObjectDisposedException(nameof(CycleBuffer));
112+
}
113+
}
114+
}
115+
}
116+
#endif
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#if INTEGRATED_ASYNC
2+
namespace Funcky;
3+
4+
public static partial class AsyncSequence
5+
{
6+
/// <returns>An <see cref="IEnumerable{T}" /> consisting of a single item or zero items.</returns>
7+
[Pure]
8+
public static IAsyncEnumerable<TResult> FromNullable<TResult>(TResult? element)
9+
where TResult : class
10+
=> element is null
11+
? AsyncEnumerable.Empty<TResult>()
12+
: Return(element);
13+
14+
/// <inheritdoc cref="FromNullable{T}(T)"/>
15+
[Pure]
16+
public static IAsyncEnumerable<TResult> FromNullable<TResult>(TResult? element)
17+
where TResult : struct
18+
=> element.HasValue
19+
? Return(element.Value)
20+
: AsyncEnumerable.Empty<TResult>();
21+
}
22+
#endif
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#if INTEGRATED_ASYNC
2+
namespace Funcky;
3+
4+
public static partial class AsyncSequence
5+
{
6+
/// <summary>
7+
/// Generates a sequence that contains the same sequence of elements the given number of times.
8+
/// </summary>
9+
/// <typeparam name="TSource">Type of the elements to be repeated.</typeparam>
10+
/// <param name="source">The sequence of elements to be repeated.</param>
11+
/// <param name="count">The number of times to repeat the value in the generated sequence.</param>
12+
/// <returns>Returns an infinite IEnumerable cycling through the same elements.</returns>
13+
[Pure]
14+
public static IAsyncBuffer<TSource> RepeatRange<TSource>(IAsyncEnumerable<TSource> source, int count)
15+
=> CycleBuffer.Create(source, count);
16+
}
17+
#endif
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#if INTEGRATED_ASYNC
2+
namespace Funcky;
3+
4+
public static partial class AsyncSequence
5+
{
6+
[Pure]
7+
public static IAsyncEnumerable<TResult> Return<TResult>(TResult element)
8+
=> Return(elements: element);
9+
10+
[Pure]
11+
public static IAsyncEnumerable<TResult> Return<TResult>(params TResult[] elements)
12+
=> elements.ToAsyncEnumerable();
13+
}
14+
#endif
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#if INTEGRATED_ASYNC
2+
namespace Funcky;
3+
4+
public static partial class AsyncSequence
5+
{
6+
/// <summary>
7+
/// Generates a sequence based on a <paramref name="successor"/> function stopping at the first <see cref="Option{TItem}.None"/> value.
8+
/// This is essentially the inverse operation of an <see cref="AsyncEnumerable.AggregateAsync{T}"/>.
9+
/// </summary>
10+
/// <param name="first">The first element of the sequence.</param>
11+
/// <param name="successor">Generates the next element of the sequence or <see cref="Option{TItem}.None"/> based on the previous item.</param>
12+
/// <remarks>Use <see cref="AsyncEnumerable.Skip{TSource}(IAsyncEnumerable{TSource}, int)"/> on the result if you don't want the first item to be included.</remarks>
13+
[Pure]
14+
public static async IAsyncEnumerable<TResult> Successors<TResult>(Option<TResult> first, Func<TResult, ValueTask<Option<TResult>>> successor)
15+
where TResult : notnull
16+
{
17+
var item = first;
18+
while (item.TryGetValue(out var itemValue))
19+
{
20+
yield return itemValue;
21+
item = await successor(itemValue).ConfigureAwait(false);
22+
}
23+
}
24+
25+
/// <inheritdoc cref="Successors{TResult}(Option{TResult}, Func{TResult, ValueTask{Option{TResult}}})" />
26+
[Pure]
27+
public static IAsyncEnumerable<TResult> Successors<TResult>(TResult first, Func<TResult, ValueTask<Option<TResult>>> successor)
28+
where TResult : notnull
29+
=> Successors(Option.Some(first), successor);
30+
31+
/// <inheritdoc cref="Successors{TResult}(Option{TResult}, Func{TResult, ValueTask{Option{TResult}}})" />
32+
[Pure]
33+
public static IAsyncEnumerable<TResult> Successors<TResult>(Option<TResult> first, Func<TResult, ValueTask<TResult>> successor)
34+
where TResult : notnull
35+
=> Successors(first, async previous => Option.Some(await successor(previous).ConfigureAwait(false)));
36+
37+
/// <inheritdoc cref="Successors{TResult}(Option{TResult}, Func{TResult, ValueTask{Option{TResult}}})" />
38+
[Pure]
39+
public static async IAsyncEnumerable<TResult> Successors<TResult>(TResult first, Func<TResult, ValueTask<TResult>> successor)
40+
{
41+
var item = first;
42+
while (true)
43+
{
44+
yield return item;
45+
item = await successor(item).ConfigureAwait(false);
46+
}
47+
}
48+
}
49+
#endif

0 commit comments

Comments
 (0)