ToAsyncEnumerable.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace System.Linq
  10. {
  11. public static partial class AsyncEnumerable
  12. {
  13. public static IAsyncEnumerable<TSource> ToAsyncEnumerable<TSource>(this IEnumerable<TSource> source)
  14. {
  15. if (source == null)
  16. throw Error.ArgumentNull(nameof(source));
  17. switch (source)
  18. {
  19. case IList<TSource> list:
  20. return new AsyncIListEnumerableAdapter<TSource>(list);
  21. case ICollection<TSource> collection:
  22. return new AsyncICollectionEnumerableAdapter<TSource>(collection);
  23. }
  24. return new AsyncEnumerableAdapter<TSource>(source);
  25. }
  26. private sealed class AsyncEnumerableAdapter<T> : AsyncIterator<T>, IAsyncIListProvider<T>
  27. {
  28. private readonly IEnumerable<T> _source;
  29. private IEnumerator<T> _enumerator;
  30. public AsyncEnumerableAdapter(IEnumerable<T> source)
  31. {
  32. Debug.Assert(source != null);
  33. _source = source;
  34. }
  35. public override AsyncIteratorBase<T> Clone() => new AsyncEnumerableAdapter<T>(_source);
  36. public override async ValueTask DisposeAsync()
  37. {
  38. if (_enumerator != null)
  39. {
  40. _enumerator.Dispose();
  41. _enumerator = null;
  42. }
  43. await base.DisposeAsync().ConfigureAwait(false);
  44. }
  45. protected override async ValueTask<bool> MoveNextCore()
  46. {
  47. switch (_state)
  48. {
  49. case AsyncIteratorState.Allocated:
  50. _enumerator = _source.GetEnumerator();
  51. _state = AsyncIteratorState.Iterating;
  52. goto case AsyncIteratorState.Iterating;
  53. case AsyncIteratorState.Iterating:
  54. if (_enumerator.MoveNext())
  55. {
  56. _current = _enumerator.Current;
  57. return true;
  58. }
  59. await DisposeAsync().ConfigureAwait(false);
  60. break;
  61. }
  62. return false;
  63. }
  64. //
  65. // NB: These optimizations rely on the System.Linq implementation of IEnumerable<T> operators to optimize
  66. // and short-circuit as appropriate.
  67. //
  68. public ValueTask<T[]> ToArrayAsync(CancellationToken cancellationToken)
  69. {
  70. cancellationToken.ThrowIfCancellationRequested();
  71. return new ValueTask<T[]>(_source.ToArray());
  72. }
  73. public ValueTask<List<T>> ToListAsync(CancellationToken cancellationToken)
  74. {
  75. cancellationToken.ThrowIfCancellationRequested();
  76. return new ValueTask<List<T>>(_source.ToList());
  77. }
  78. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  79. {
  80. cancellationToken.ThrowIfCancellationRequested();
  81. return new ValueTask<int>(_source.Count());
  82. }
  83. }
  84. private sealed class AsyncIListEnumerableAdapter<T> : AsyncIterator<T>, IAsyncIListProvider<T>, IList<T>
  85. {
  86. private readonly IList<T> _source;
  87. private IEnumerator<T> _enumerator;
  88. public AsyncIListEnumerableAdapter(IList<T> source)
  89. {
  90. Debug.Assert(source != null);
  91. _source = source;
  92. }
  93. public override AsyncIteratorBase<T> Clone() => new AsyncIListEnumerableAdapter<T>(_source);
  94. public override async ValueTask DisposeAsync()
  95. {
  96. if (_enumerator != null)
  97. {
  98. _enumerator.Dispose();
  99. _enumerator = null;
  100. }
  101. await base.DisposeAsync().ConfigureAwait(false);
  102. }
  103. protected override async ValueTask<bool> MoveNextCore()
  104. {
  105. switch (_state)
  106. {
  107. case AsyncIteratorState.Allocated:
  108. _enumerator = _source.GetEnumerator();
  109. _state = AsyncIteratorState.Iterating;
  110. goto case AsyncIteratorState.Iterating;
  111. case AsyncIteratorState.Iterating:
  112. if (_enumerator.MoveNext())
  113. {
  114. _current = _enumerator.Current;
  115. return true;
  116. }
  117. await DisposeAsync().ConfigureAwait(false);
  118. break;
  119. }
  120. return false;
  121. }
  122. public override IAsyncEnumerable<TResult> Select<TResult>(Func<T, TResult> selector) => new SelectIListIterator<T, TResult>(_source, selector);
  123. //
  124. // NB: These optimizations rely on the System.Linq implementation of IEnumerable<T> operators to optimize
  125. // and short-circuit as appropriate.
  126. //
  127. public ValueTask<T[]> ToArrayAsync(CancellationToken cancellationToken)
  128. {
  129. cancellationToken.ThrowIfCancellationRequested();
  130. return new ValueTask<T[]>(_source.ToArray());
  131. }
  132. public ValueTask<List<T>> ToListAsync(CancellationToken cancellationToken)
  133. {
  134. cancellationToken.ThrowIfCancellationRequested();
  135. return new ValueTask<List<T>>(_source.ToList());
  136. }
  137. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  138. {
  139. cancellationToken.ThrowIfCancellationRequested();
  140. return new ValueTask<int>(_source.Count);
  141. }
  142. IEnumerator<T> IEnumerable<T>.GetEnumerator() => _source.GetEnumerator();
  143. IEnumerator IEnumerable.GetEnumerator() => _source.GetEnumerator();
  144. void ICollection<T>.Add(T item) => _source.Add(item);
  145. void ICollection<T>.Clear() => _source.Clear();
  146. bool ICollection<T>.Contains(T item) => _source.Contains(item);
  147. void ICollection<T>.CopyTo(T[] array, int arrayIndex) => _source.CopyTo(array, arrayIndex);
  148. bool ICollection<T>.Remove(T item) => _source.Remove(item);
  149. int ICollection<T>.Count => _source.Count;
  150. bool ICollection<T>.IsReadOnly => _source.IsReadOnly;
  151. int IList<T>.IndexOf(T item) => _source.IndexOf(item);
  152. void IList<T>.Insert(int index, T item) => _source.Insert(index, item);
  153. void IList<T>.RemoveAt(int index) => _source.RemoveAt(index);
  154. T IList<T>.this[int index]
  155. {
  156. get => _source[index];
  157. set => _source[index] = value;
  158. }
  159. }
  160. private sealed class AsyncICollectionEnumerableAdapter<T> : AsyncIterator<T>, IAsyncIListProvider<T>, ICollection<T>
  161. {
  162. private readonly ICollection<T> _source;
  163. private IEnumerator<T> _enumerator;
  164. public AsyncICollectionEnumerableAdapter(ICollection<T> source)
  165. {
  166. Debug.Assert(source != null);
  167. _source = source;
  168. }
  169. public override AsyncIteratorBase<T> Clone() => new AsyncICollectionEnumerableAdapter<T>(_source);
  170. public override async ValueTask DisposeAsync()
  171. {
  172. if (_enumerator != null)
  173. {
  174. _enumerator.Dispose();
  175. _enumerator = null;
  176. }
  177. await base.DisposeAsync().ConfigureAwait(false);
  178. }
  179. protected override async ValueTask<bool> MoveNextCore()
  180. {
  181. switch (_state)
  182. {
  183. case AsyncIteratorState.Allocated:
  184. _enumerator = _source.GetEnumerator();
  185. _state = AsyncIteratorState.Iterating;
  186. goto case AsyncIteratorState.Iterating;
  187. case AsyncIteratorState.Iterating:
  188. if (_enumerator.MoveNext())
  189. {
  190. _current = _enumerator.Current;
  191. return true;
  192. }
  193. await DisposeAsync().ConfigureAwait(false);
  194. break;
  195. }
  196. return false;
  197. }
  198. //
  199. // NB: These optimizations rely on the System.Linq implementation of IEnumerable<T> operators to optimize
  200. // and short-circuit as appropriate.
  201. //
  202. public ValueTask<T[]> ToArrayAsync(CancellationToken cancellationToken)
  203. {
  204. cancellationToken.ThrowIfCancellationRequested();
  205. return new ValueTask<T[]>(_source.ToArray());
  206. }
  207. public ValueTask<List<T>> ToListAsync(CancellationToken cancellationToken)
  208. {
  209. cancellationToken.ThrowIfCancellationRequested();
  210. return new ValueTask<List<T>>(_source.ToList());
  211. }
  212. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  213. {
  214. cancellationToken.ThrowIfCancellationRequested();
  215. return new ValueTask<int>(_source.Count);
  216. }
  217. IEnumerator<T> IEnumerable<T>.GetEnumerator() => _source.GetEnumerator();
  218. IEnumerator IEnumerable.GetEnumerator() => _source.GetEnumerator();
  219. void ICollection<T>.Add(T item) => _source.Add(item);
  220. void ICollection<T>.Clear() => _source.Clear();
  221. bool ICollection<T>.Contains(T item) => _source.Contains(item);
  222. void ICollection<T>.CopyTo(T[] array, int arrayIndex) => _source.CopyTo(array, arrayIndex);
  223. bool ICollection<T>.Remove(T item) => _source.Remove(item);
  224. int ICollection<T>.Count => _source.Count;
  225. bool ICollection<T>.IsReadOnly => _source.IsReadOnly;
  226. }
  227. }
  228. }