SelectMany.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  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.Generic;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. public static partial class AsyncEnumerable
  10. {
  11. public static IAsyncEnumerable<TResult> SelectMany<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, IAsyncEnumerable<TResult>> selector)
  12. {
  13. if (source == null)
  14. throw Error.ArgumentNull(nameof(source));
  15. if (selector == null)
  16. throw Error.ArgumentNull(nameof(selector));
  17. return new SelectManyAsyncIterator<TSource, TResult>(source, selector);
  18. }
  19. // REVIEW: Should we keep these overloads that return ValueTask<IAsyncEnumerable<TResult>>? One could argue the selector is async twice.
  20. internal static IAsyncEnumerable<TResult> SelectManyAwaitCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<IAsyncEnumerable<TResult>>> selector)
  21. {
  22. if (source == null)
  23. throw Error.ArgumentNull(nameof(source));
  24. if (selector == null)
  25. throw Error.ArgumentNull(nameof(selector));
  26. return new SelectManyAsyncIteratorWithTask<TSource, TResult>(source, selector);
  27. }
  28. #if !NO_DEEP_CANCELLATION
  29. internal static IAsyncEnumerable<TResult> SelectManyAwaitWithCancellationCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<IAsyncEnumerable<TResult>>> selector)
  30. {
  31. if (source == null)
  32. throw Error.ArgumentNull(nameof(source));
  33. if (selector == null)
  34. throw Error.ArgumentNull(nameof(selector));
  35. return new SelectManyAsyncIteratorWithTaskAndCancellation<TSource, TResult>(source, selector);
  36. }
  37. #endif
  38. public static IAsyncEnumerable<TResult> SelectMany<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, IAsyncEnumerable<TResult>> selector)
  39. {
  40. if (source == null)
  41. throw Error.ArgumentNull(nameof(source));
  42. if (selector == null)
  43. throw Error.ArgumentNull(nameof(selector));
  44. return Create(Core);
  45. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  46. {
  47. var index = -1;
  48. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  49. {
  50. checked
  51. {
  52. index++;
  53. }
  54. var inner = selector(element, index);
  55. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  56. {
  57. yield return subElement;
  58. }
  59. }
  60. }
  61. }
  62. internal static IAsyncEnumerable<TResult> SelectManyAwaitCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<IAsyncEnumerable<TResult>>> selector)
  63. {
  64. if (source == null)
  65. throw Error.ArgumentNull(nameof(source));
  66. if (selector == null)
  67. throw Error.ArgumentNull(nameof(selector));
  68. return Create(Core);
  69. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  70. {
  71. var index = -1;
  72. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  73. {
  74. checked
  75. {
  76. index++;
  77. }
  78. var inner = await selector(element, index).ConfigureAwait(false);
  79. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  80. {
  81. yield return subElement;
  82. }
  83. }
  84. }
  85. }
  86. #if !NO_DEEP_CANCELLATION
  87. internal static IAsyncEnumerable<TResult> SelectManyAwaitWithCancellationCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<IAsyncEnumerable<TResult>>> selector)
  88. {
  89. if (source == null)
  90. throw Error.ArgumentNull(nameof(source));
  91. if (selector == null)
  92. throw Error.ArgumentNull(nameof(selector));
  93. return Create(Core);
  94. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  95. {
  96. var index = -1;
  97. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  98. {
  99. checked
  100. {
  101. index++;
  102. }
  103. var inner = await selector(element, index, cancellationToken).ConfigureAwait(false);
  104. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  105. {
  106. yield return subElement;
  107. }
  108. }
  109. }
  110. }
  111. #endif
  112. public static IAsyncEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, IAsyncEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
  113. {
  114. if (source == null)
  115. throw Error.ArgumentNull(nameof(source));
  116. if (collectionSelector == null)
  117. throw Error.ArgumentNull(nameof(collectionSelector));
  118. if (resultSelector == null)
  119. throw Error.ArgumentNull(nameof(resultSelector));
  120. return Create(Core);
  121. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  122. {
  123. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  124. {
  125. var inner = collectionSelector(element);
  126. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  127. {
  128. yield return resultSelector(element, subElement);
  129. }
  130. }
  131. }
  132. }
  133. internal static IAsyncEnumerable<TResult> SelectManyAwaitCore<TSource, TCollection, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, ValueTask<TResult>> resultSelector)
  134. {
  135. if (source == null)
  136. throw Error.ArgumentNull(nameof(source));
  137. if (collectionSelector == null)
  138. throw Error.ArgumentNull(nameof(collectionSelector));
  139. if (resultSelector == null)
  140. throw Error.ArgumentNull(nameof(resultSelector));
  141. return Create(Core);
  142. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  143. {
  144. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  145. {
  146. var inner = await collectionSelector(element).ConfigureAwait(false);
  147. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  148. {
  149. yield return await resultSelector(element, subElement).ConfigureAwait(false);
  150. }
  151. }
  152. }
  153. }
  154. #if !NO_DEEP_CANCELLATION
  155. internal static IAsyncEnumerable<TResult> SelectManyAwaitWithCancellationCore<TSource, TCollection, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, CancellationToken, ValueTask<TResult>> resultSelector)
  156. {
  157. if (source == null)
  158. throw Error.ArgumentNull(nameof(source));
  159. if (collectionSelector == null)
  160. throw Error.ArgumentNull(nameof(collectionSelector));
  161. if (resultSelector == null)
  162. throw Error.ArgumentNull(nameof(resultSelector));
  163. return Create(Core);
  164. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  165. {
  166. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  167. {
  168. var inner = await collectionSelector(element, cancellationToken).ConfigureAwait(false);
  169. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  170. {
  171. yield return await resultSelector(element, subElement, cancellationToken).ConfigureAwait(false);
  172. }
  173. }
  174. }
  175. }
  176. #endif
  177. public static IAsyncEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, IAsyncEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
  178. {
  179. if (source == null)
  180. throw Error.ArgumentNull(nameof(source));
  181. if (collectionSelector == null)
  182. throw Error.ArgumentNull(nameof(collectionSelector));
  183. if (resultSelector == null)
  184. throw Error.ArgumentNull(nameof(resultSelector));
  185. return Create(Core);
  186. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  187. {
  188. var index = -1;
  189. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  190. {
  191. checked
  192. {
  193. index++;
  194. }
  195. var inner = collectionSelector(element, index);
  196. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  197. {
  198. yield return resultSelector(element, subElement);
  199. }
  200. }
  201. }
  202. }
  203. internal static IAsyncEnumerable<TResult> SelectManyAwaitCore<TSource, TCollection, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, ValueTask<TResult>> resultSelector)
  204. {
  205. if (source == null)
  206. throw Error.ArgumentNull(nameof(source));
  207. if (collectionSelector == null)
  208. throw Error.ArgumentNull(nameof(collectionSelector));
  209. if (resultSelector == null)
  210. throw Error.ArgumentNull(nameof(resultSelector));
  211. return Create(Core);
  212. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  213. {
  214. var index = -1;
  215. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  216. {
  217. checked
  218. {
  219. index++;
  220. }
  221. var inner = await collectionSelector(element, index).ConfigureAwait(false);
  222. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  223. {
  224. yield return await resultSelector(element, subElement).ConfigureAwait(false);
  225. }
  226. }
  227. }
  228. }
  229. #if !NO_DEEP_CANCELLATION
  230. internal static IAsyncEnumerable<TResult> SelectManyAwaitWithCancellationCore<TSource, TCollection, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, CancellationToken, ValueTask<TResult>> resultSelector)
  231. {
  232. if (source == null)
  233. throw Error.ArgumentNull(nameof(source));
  234. if (collectionSelector == null)
  235. throw Error.ArgumentNull(nameof(collectionSelector));
  236. if (resultSelector == null)
  237. throw Error.ArgumentNull(nameof(resultSelector));
  238. return Create(Core);
  239. async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
  240. {
  241. var index = -1;
  242. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  243. {
  244. checked
  245. {
  246. index++;
  247. }
  248. var inner = await collectionSelector(element, index, cancellationToken).ConfigureAwait(false);
  249. await foreach (var subElement in inner.WithCancellation(cancellationToken).ConfigureAwait(false))
  250. {
  251. yield return await resultSelector(element, subElement, cancellationToken).ConfigureAwait(false);
  252. }
  253. }
  254. }
  255. }
  256. #endif
  257. private sealed class SelectManyAsyncIterator<TSource, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  258. {
  259. private const int State_Source = 1;
  260. private const int State_Result = 2;
  261. private readonly Func<TSource, IAsyncEnumerable<TResult>> _selector;
  262. private readonly IAsyncEnumerable<TSource> _source;
  263. private int _mode;
  264. private IAsyncEnumerator<TResult>? _resultEnumerator;
  265. private IAsyncEnumerator<TSource>? _sourceEnumerator;
  266. public SelectManyAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, IAsyncEnumerable<TResult>> selector)
  267. {
  268. _source = source;
  269. _selector = selector;
  270. }
  271. public override AsyncIteratorBase<TResult> Clone()
  272. {
  273. return new SelectManyAsyncIterator<TSource, TResult>(_source, _selector);
  274. }
  275. public override async ValueTask DisposeAsync()
  276. {
  277. if (_resultEnumerator != null)
  278. {
  279. await _resultEnumerator.DisposeAsync().ConfigureAwait(false);
  280. _resultEnumerator = null;
  281. }
  282. if (_sourceEnumerator != null)
  283. {
  284. await _sourceEnumerator.DisposeAsync().ConfigureAwait(false);
  285. _sourceEnumerator = null;
  286. }
  287. await base.DisposeAsync().ConfigureAwait(false);
  288. }
  289. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  290. {
  291. if (onlyIfCheap)
  292. {
  293. return new ValueTask<int>(-1);
  294. }
  295. return Core(cancellationToken);
  296. async ValueTask<int> Core(CancellationToken cancellationToken)
  297. {
  298. var count = 0;
  299. await foreach (var element in _source.WithCancellation(cancellationToken).ConfigureAwait(false))
  300. {
  301. checked
  302. {
  303. count += await _selector(element).CountAsync().ConfigureAwait(false);
  304. }
  305. }
  306. return count;
  307. }
  308. }
  309. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  310. {
  311. // REVIEW: Substitute for SparseArrayBuilder<T> logic once we have access to that.
  312. var list = await ToListAsync(cancellationToken).ConfigureAwait(false);
  313. return list.ToArray();
  314. }
  315. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  316. {
  317. var list = new List<TResult>();
  318. await foreach (var element in _source.WithCancellation(cancellationToken).ConfigureAwait(false))
  319. {
  320. var items = _selector(element);
  321. await list.AddRangeAsync(items, cancellationToken).ConfigureAwait(false);
  322. }
  323. return list;
  324. }
  325. protected override async ValueTask<bool> MoveNextCore()
  326. {
  327. switch (_state)
  328. {
  329. case AsyncIteratorState.Allocated:
  330. _sourceEnumerator = _source.GetAsyncEnumerator(_cancellationToken);
  331. _mode = State_Source;
  332. _state = AsyncIteratorState.Iterating;
  333. goto case AsyncIteratorState.Iterating;
  334. case AsyncIteratorState.Iterating:
  335. switch (_mode)
  336. {
  337. case State_Source:
  338. if (await _sourceEnumerator!.MoveNextAsync().ConfigureAwait(false))
  339. {
  340. if (_resultEnumerator != null)
  341. {
  342. await _resultEnumerator.DisposeAsync().ConfigureAwait(false);
  343. }
  344. var inner = _selector(_sourceEnumerator.Current);
  345. _resultEnumerator = inner.GetAsyncEnumerator(_cancellationToken);
  346. _mode = State_Result;
  347. goto case State_Result;
  348. }
  349. break;
  350. case State_Result:
  351. if (await _resultEnumerator!.MoveNextAsync().ConfigureAwait(false))
  352. {
  353. _current = _resultEnumerator.Current;
  354. return true;
  355. }
  356. _mode = State_Source;
  357. goto case State_Source; // loop
  358. }
  359. break;
  360. }
  361. await DisposeAsync().ConfigureAwait(false);
  362. return false;
  363. }
  364. }
  365. private sealed class SelectManyAsyncIteratorWithTask<TSource, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  366. {
  367. private const int State_Source = 1;
  368. private const int State_Result = 2;
  369. private readonly Func<TSource, ValueTask<IAsyncEnumerable<TResult>>> _selector;
  370. private readonly IAsyncEnumerable<TSource> _source;
  371. private int _mode;
  372. private IAsyncEnumerator<TResult>? _resultEnumerator;
  373. private IAsyncEnumerator<TSource>? _sourceEnumerator;
  374. public SelectManyAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<IAsyncEnumerable<TResult>>> selector)
  375. {
  376. _source = source;
  377. _selector = selector;
  378. }
  379. public override AsyncIteratorBase<TResult> Clone()
  380. {
  381. return new SelectManyAsyncIteratorWithTask<TSource, TResult>(_source, _selector);
  382. }
  383. public override async ValueTask DisposeAsync()
  384. {
  385. if (_resultEnumerator != null)
  386. {
  387. await _resultEnumerator.DisposeAsync().ConfigureAwait(false);
  388. _resultEnumerator = null;
  389. }
  390. if (_sourceEnumerator != null)
  391. {
  392. await _sourceEnumerator.DisposeAsync().ConfigureAwait(false);
  393. _sourceEnumerator = null;
  394. }
  395. await base.DisposeAsync().ConfigureAwait(false);
  396. }
  397. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  398. {
  399. if (onlyIfCheap)
  400. {
  401. return new ValueTask<int>(-1);
  402. }
  403. return Core(cancellationToken);
  404. async ValueTask<int> Core(CancellationToken cancellationToken)
  405. {
  406. var count = 0;
  407. await foreach (var element in _source.WithCancellation(cancellationToken).ConfigureAwait(false))
  408. {
  409. var items = await _selector(element).ConfigureAwait(false);
  410. checked
  411. {
  412. count += await items.CountAsync().ConfigureAwait(false);
  413. }
  414. }
  415. return count;
  416. }
  417. }
  418. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  419. {
  420. // REVIEW: Substitute for SparseArrayBuilder<T> logic once we have access to that.
  421. var list = await ToListAsync(cancellationToken).ConfigureAwait(false);
  422. return list.ToArray();
  423. }
  424. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  425. {
  426. var list = new List<TResult>();
  427. await foreach (var element in _source.WithCancellation(cancellationToken).ConfigureAwait(false))
  428. {
  429. var items = await _selector(element).ConfigureAwait(false);
  430. await list.AddRangeAsync(items, cancellationToken).ConfigureAwait(false);
  431. }
  432. return list;
  433. }
  434. protected override async ValueTask<bool> MoveNextCore()
  435. {
  436. switch (_state)
  437. {
  438. case AsyncIteratorState.Allocated:
  439. _sourceEnumerator = _source.GetAsyncEnumerator(_cancellationToken);
  440. _mode = State_Source;
  441. _state = AsyncIteratorState.Iterating;
  442. goto case AsyncIteratorState.Iterating;
  443. case AsyncIteratorState.Iterating:
  444. switch (_mode)
  445. {
  446. case State_Source:
  447. if (await _sourceEnumerator!.MoveNextAsync().ConfigureAwait(false))
  448. {
  449. if (_resultEnumerator != null)
  450. {
  451. await _resultEnumerator.DisposeAsync().ConfigureAwait(false);
  452. }
  453. var inner = await _selector(_sourceEnumerator.Current).ConfigureAwait(false);
  454. _resultEnumerator = inner.GetAsyncEnumerator(_cancellationToken);
  455. _mode = State_Result;
  456. goto case State_Result;
  457. }
  458. break;
  459. case State_Result:
  460. if (await _resultEnumerator!.MoveNextAsync().ConfigureAwait(false))
  461. {
  462. _current = _resultEnumerator.Current;
  463. return true;
  464. }
  465. _mode = State_Source;
  466. goto case State_Source; // loop
  467. }
  468. break;
  469. }
  470. await DisposeAsync().ConfigureAwait(false);
  471. return false;
  472. }
  473. }
  474. #if !NO_DEEP_CANCELLATION
  475. private sealed class SelectManyAsyncIteratorWithTaskAndCancellation<TSource, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  476. {
  477. private const int State_Source = 1;
  478. private const int State_Result = 2;
  479. private readonly Func<TSource, CancellationToken, ValueTask<IAsyncEnumerable<TResult>>> _selector;
  480. private readonly IAsyncEnumerable<TSource> _source;
  481. private int _mode;
  482. private IAsyncEnumerator<TResult>? _resultEnumerator;
  483. private IAsyncEnumerator<TSource>? _sourceEnumerator;
  484. public SelectManyAsyncIteratorWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<IAsyncEnumerable<TResult>>> selector)
  485. {
  486. _source = source;
  487. _selector = selector;
  488. }
  489. public override AsyncIteratorBase<TResult> Clone()
  490. {
  491. return new SelectManyAsyncIteratorWithTaskAndCancellation<TSource, TResult>(_source, _selector);
  492. }
  493. public override async ValueTask DisposeAsync()
  494. {
  495. if (_resultEnumerator != null)
  496. {
  497. await _resultEnumerator.DisposeAsync().ConfigureAwait(false);
  498. _resultEnumerator = null;
  499. }
  500. if (_sourceEnumerator != null)
  501. {
  502. await _sourceEnumerator.DisposeAsync().ConfigureAwait(false);
  503. _sourceEnumerator = null;
  504. }
  505. await base.DisposeAsync().ConfigureAwait(false);
  506. }
  507. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  508. {
  509. if (onlyIfCheap)
  510. {
  511. return new ValueTask<int>(-1);
  512. }
  513. return Core(cancellationToken);
  514. async ValueTask<int> Core(CancellationToken cancellationToken)
  515. {
  516. var count = 0;
  517. await foreach (var element in _source.WithCancellation(cancellationToken).ConfigureAwait(false))
  518. {
  519. var items = await _selector(element, cancellationToken).ConfigureAwait(false);
  520. checked
  521. {
  522. count += await items.CountAsync().ConfigureAwait(false);
  523. }
  524. }
  525. return count;
  526. }
  527. }
  528. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  529. {
  530. // REVIEW: Substitute for SparseArrayBuilder<T> logic once we have access to that.
  531. var list = await ToListAsync(cancellationToken).ConfigureAwait(false);
  532. return list.ToArray();
  533. }
  534. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  535. {
  536. var list = new List<TResult>();
  537. await foreach (var element in _source.WithCancellation(cancellationToken).ConfigureAwait(false))
  538. {
  539. var items = await _selector(element, cancellationToken).ConfigureAwait(false);
  540. await list.AddRangeAsync(items, cancellationToken).ConfigureAwait(false);
  541. }
  542. return list;
  543. }
  544. protected override async ValueTask<bool> MoveNextCore()
  545. {
  546. switch (_state)
  547. {
  548. case AsyncIteratorState.Allocated:
  549. _sourceEnumerator = _source.GetAsyncEnumerator(_cancellationToken);
  550. _mode = State_Source;
  551. _state = AsyncIteratorState.Iterating;
  552. goto case AsyncIteratorState.Iterating;
  553. case AsyncIteratorState.Iterating:
  554. switch (_mode)
  555. {
  556. case State_Source:
  557. if (await _sourceEnumerator!.MoveNextAsync().ConfigureAwait(false))
  558. {
  559. if (_resultEnumerator != null)
  560. {
  561. await _resultEnumerator.DisposeAsync().ConfigureAwait(false);
  562. }
  563. var inner = await _selector(_sourceEnumerator.Current, _cancellationToken).ConfigureAwait(false);
  564. _resultEnumerator = inner.GetAsyncEnumerator(_cancellationToken);
  565. _mode = State_Result;
  566. goto case State_Result;
  567. }
  568. break;
  569. case State_Result:
  570. if (await _resultEnumerator!.MoveNextAsync().ConfigureAwait(false))
  571. {
  572. _current = _resultEnumerator.Current;
  573. return true;
  574. }
  575. _mode = State_Source;
  576. goto case State_Source; // loop
  577. }
  578. break;
  579. }
  580. await DisposeAsync().ConfigureAwait(false);
  581. return false;
  582. }
  583. }
  584. #endif
  585. }
  586. }