-
Notifications
You must be signed in to change notification settings - Fork 55
Expand file tree
/
Copy pathAsyncEnumerable.cs
More file actions
144 lines (130 loc) · 6.11 KB
/
AsyncEnumerable.cs
File metadata and controls
144 lines (130 loc) · 6.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Dasync.Collections.Internals;
namespace Dasync.Collections
{
/// <summary>
/// Base abstract class that implements <see cref="IAsyncEnumerable"/>.
/// Use concrete implementation <see cref="AsyncEnumerable{T}"/> or <see cref="AsyncEnumerableWithState{TItem, TState}"/>.
/// </summary>
public abstract class AsyncEnumerable : IAsyncEnumerable
{
/// <summary>
/// Returns pre-cached empty collection
/// </summary>
public static IAsyncEnumerable<T> Empty<T>() => AsyncEnumerable<T>.Empty;
/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
IAsyncEnumerator IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Helps to enumerate items in a collection asynchronously
/// </summary>
/// <example>
/// <code>
/// IAsyncEnumerable<int> ProduceNumbers(int start, int end)
/// {
/// return new AsyncEnumerable<int>(async yield => {
/// for (int number = start; number <= end; number++)
/// await yield.ReturnAsync(number);
/// });
/// }
///
/// async Task ConsumeAsync()
/// {
/// var asyncEnumerableCollection = ProduceNumbers(start: 1, end: 10);
/// await asyncEnumerableCollection.ForEachAsync(async number => {
/// await Console.Out.WriteLineAsync(number);
/// });
/// }
/// </code>
/// </example>
public class AsyncEnumerable<T> : AsyncEnumerable, IAsyncEnumerable, IAsyncEnumerable<T>
{
private readonly Func<AsyncEnumerator<T>.Yield, Task> _enumerationFunction;
/// <summary>
/// A pre-cached empty collection
/// </summary>
public readonly static IAsyncEnumerable<T> Empty = new EmptyAsyncEnumerable<T>();
/// <summary>
/// Constructor
/// </summary>
/// <param name="enumerationFunction">A function that enumerates items in a collection asynchronously</param>
public AsyncEnumerable(Func<AsyncEnumerator<T>.Yield, Task> enumerationFunction)
{
_enumerationFunction = enumerationFunction;
}
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// It has been pointed out that overhead costs can be reduced by returning this instead of a new object for the enumerator
/// </remarks>
protected AsyncEnumerable()
{
}
/// <summary>
/// Creates an enumerator that iterates through a collection asynchronously
/// </summary>
/// <param name="cancellationToken">A cancellation token to cancel creation of the enumerator in case if it takes a lot of time</param>
/// <returns>Returns a task with the created enumerator as result on completion</returns>
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
=> new AsyncEnumerator<T>(_enumerationFunction ?? GetEnumerationFunction()) { MasterCancellationToken = cancellationToken };
IAsyncEnumerator IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken)
=> new AsyncEnumerator<T>(_enumerationFunction ?? GetEnumerationFunction()) { MasterCancellationToken = cancellationToken };
/// <summary>
/// Gets a EnumerationFunction which allows for a user to inherit from <see cref="AsyncEnumerator{T}"/>
/// </summary>
/// <returns></returns>
public virtual Func<AsyncEnumerator<T>.Yield, Task> GetEnumerationFunction()
{
throw new NotImplementedException();
}
}
/// <summary>
/// Similar to <see cref="AsyncEnumerable{T}"/>, but allows you to pass a state object into the enumeration function, what can be
/// used for performance optimization, so don't have to create a delegate on the fly every single time you create the enumerator.
/// </summary>
/// <typeparam name="TItem">Type of items returned by </typeparam>
/// <typeparam name="TState">Type of the state object</typeparam>
public class AsyncEnumerableWithState<TItem, TState> : AsyncEnumerable, IAsyncEnumerable, IAsyncEnumerable<TItem>
{
private readonly Func<AsyncEnumerator<TItem>.Yield, TState, Task> _enumerationFunction;
/// <summary>
/// Constructor
/// </summary>
/// <param name="enumerationFunction">A function that enumerates items in a collection asynchronously</param>
/// <param name="state">A state object that is passed to the <paramref name="enumerationFunction"/></param>
public AsyncEnumerableWithState(Func<AsyncEnumerator<TItem>.Yield, TState, Task> enumerationFunction, TState state)
{
_enumerationFunction = enumerationFunction;
State = state;
}
/// <summary>
/// A user state that gets passed into the enumeration function.
/// </summary>
protected TState State { get; }
/// <summary>
/// Creates an enumerator that iterates through a collection asynchronously
/// </summary>
/// <returns>Returns a task with the created enumerator as result on completion</returns>
public virtual IAsyncEnumerator<TItem> GetAsyncEnumerator(CancellationToken cancellationToken = default)
=> new AsyncEnumeratorWithState<TItem, TState>(_enumerationFunction, State)
{ MasterCancellationToken = cancellationToken };
/// <summary>
/// Creates an enumerator that iterates through a collection asynchronously
/// </summary>
/// <returns>Returns a task with the created enumerator as result on completion</returns>
IAsyncEnumerator IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken)
=> new AsyncEnumeratorWithState<TItem, TState>(_enumerationFunction, State)
{ MasterCancellationToken = cancellationToken };
}
}