/Ix.NET/Source/System.Interactive.Async/AsyncEnumerable.Creation.cs

https://gitlab.com/svsamipillai/Rx.NET · C# · 283 lines · 240 code · 42 blank · 1 comment · 23 complexity · 0aad65b22043b500f1643222167e168a MD5 · raw file

  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. public static partial class AsyncEnumerable
  10. {
  11. static IAsyncEnumerable<T> Create<T>(Func<IAsyncEnumerator<T>> getEnumerator)
  12. {
  13. return new AnonymousAsyncEnumerable<T>(getEnumerator);
  14. }
  15. class AnonymousAsyncEnumerable<T> : IAsyncEnumerable<T>
  16. {
  17. Func<IAsyncEnumerator<T>> getEnumerator;
  18. public AnonymousAsyncEnumerable(Func<IAsyncEnumerator<T>> getEnumerator)
  19. {
  20. this.getEnumerator = getEnumerator;
  21. }
  22. public IAsyncEnumerator<T> GetEnumerator()
  23. {
  24. return getEnumerator();
  25. }
  26. }
  27. static IAsyncEnumerator<T> Create<T>(Func<CancellationToken, Task<bool>> moveNext, Func<T> current, Action dispose)
  28. {
  29. return new AnonymousAsyncEnumerator<T>(moveNext, current, dispose);
  30. }
  31. static IAsyncEnumerator<T> Create<T>(Func<CancellationToken, TaskCompletionSource<bool>, Task<bool>> moveNext, Func<T> current, Action dispose)
  32. {
  33. var self = default(IAsyncEnumerator<T>);
  34. self = new AnonymousAsyncEnumerator<T>(
  35. ct =>
  36. {
  37. var tcs = new TaskCompletionSource<bool>();
  38. var stop = new Action(() =>
  39. {
  40. self.Dispose();
  41. tcs.TrySetCanceled();
  42. });
  43. var ctr = ct.Register(stop);
  44. var res = moveNext(ct, tcs).Finally(ctr.Dispose);
  45. return res;
  46. },
  47. current,
  48. dispose
  49. );
  50. return self;
  51. }
  52. class AnonymousAsyncEnumerator<T> : IAsyncEnumerator<T>
  53. {
  54. private readonly Func<CancellationToken, Task<bool>> _moveNext;
  55. private readonly Func<T> _current;
  56. private readonly Action _dispose;
  57. private bool _disposed;
  58. public AnonymousAsyncEnumerator(Func<CancellationToken, Task<bool>> moveNext, Func<T> current, Action dispose)
  59. {
  60. _moveNext = moveNext;
  61. _current = current;
  62. _dispose = dispose;
  63. }
  64. public Task<bool> MoveNext(CancellationToken cancellationToken)
  65. {
  66. if (_disposed)
  67. return TaskExt.False;
  68. return _moveNext(cancellationToken);
  69. }
  70. public T Current
  71. {
  72. get
  73. {
  74. return _current();
  75. }
  76. }
  77. public void Dispose()
  78. {
  79. if (!_disposed)
  80. {
  81. _disposed = true;
  82. _dispose();
  83. }
  84. }
  85. }
  86. public static IAsyncEnumerable<TValue> Return<TValue>(TValue value)
  87. {
  88. return new[] { value }.ToAsyncEnumerable();
  89. }
  90. public static IAsyncEnumerable<TValue> Throw<TValue>(Exception exception)
  91. {
  92. if (exception == null)
  93. throw new ArgumentNullException("exception");
  94. return Create(() => Create<TValue>(
  95. ct => TaskExt.Throw<bool>(exception),
  96. () => { throw new InvalidOperationException(); },
  97. () => { })
  98. );
  99. }
  100. public static IAsyncEnumerable<TValue> Never<TValue>()
  101. {
  102. return Create(() => Create<TValue>(
  103. (ct, tcs) => tcs.Task,
  104. () => { throw new InvalidOperationException(); },
  105. () => { })
  106. );
  107. }
  108. public static IAsyncEnumerable<TValue> Empty<TValue>()
  109. {
  110. return Create(() => Create<TValue>(
  111. ct => TaskExt.False,
  112. () => { throw new InvalidOperationException(); },
  113. () => { })
  114. );
  115. }
  116. public static IAsyncEnumerable<int> Range(int start, int count)
  117. {
  118. if (count < 0)
  119. throw new ArgumentOutOfRangeException("count");
  120. return Enumerable.Range(start, count).ToAsyncEnumerable();
  121. }
  122. public static IAsyncEnumerable<TResult> Repeat<TResult>(TResult element, int count)
  123. {
  124. if (count < 0)
  125. throw new ArgumentOutOfRangeException("count");
  126. return Enumerable.Repeat(element, count).ToAsyncEnumerable();
  127. }
  128. public static IAsyncEnumerable<TResult> Repeat<TResult>(TResult element)
  129. {
  130. return Create(() =>
  131. {
  132. return Create(
  133. ct => TaskExt.True,
  134. () => element,
  135. () => { }
  136. );
  137. });
  138. }
  139. public static IAsyncEnumerable<TSource> Defer<TSource>(Func<IAsyncEnumerable<TSource>> factory)
  140. {
  141. if (factory == null)
  142. throw new ArgumentNullException("factory");
  143. return Create(() => factory().GetEnumerator());
  144. }
  145. public static IAsyncEnumerable<TResult> Generate<TState, TResult>(TState initialState, Func<TState, bool> condition, Func<TState, TState> iterate, Func<TState, TResult> resultSelector)
  146. {
  147. if (condition == null)
  148. throw new ArgumentNullException("condition");
  149. if (iterate == null)
  150. throw new ArgumentNullException("iterate");
  151. if (resultSelector == null)
  152. throw new ArgumentNullException("resultSelector");
  153. return Create(() =>
  154. {
  155. var i = initialState;
  156. var started = false;
  157. var current = default(TResult);
  158. return Create(
  159. ct =>
  160. {
  161. var b = false;
  162. try
  163. {
  164. if (started)
  165. i = iterate(i);
  166. b = condition(i);
  167. if (b)
  168. current = resultSelector(i);
  169. }
  170. catch (Exception ex)
  171. {
  172. return TaskExt.Throw<bool>(ex);
  173. }
  174. if (!b)
  175. return TaskExt.False;
  176. if (!started)
  177. started = true;
  178. return TaskExt.True;
  179. },
  180. () => current,
  181. () => { }
  182. );
  183. });
  184. }
  185. public static IAsyncEnumerable<TSource> Using<TSource, TResource>(Func<TResource> resourceFactory, Func<TResource, IAsyncEnumerable<TSource>> enumerableFactory) where TResource : IDisposable
  186. {
  187. if (resourceFactory == null)
  188. throw new ArgumentNullException("resourceFactory");
  189. if (enumerableFactory == null)
  190. throw new ArgumentNullException("enumerableFactory");
  191. return Create(() =>
  192. {
  193. var resource = resourceFactory();
  194. var e = default(IAsyncEnumerator<TSource>);
  195. try
  196. {
  197. e = enumerableFactory(resource).GetEnumerator();
  198. }
  199. catch (Exception)
  200. {
  201. resource.Dispose();
  202. throw;
  203. }
  204. var cts = new CancellationTokenDisposable();
  205. var d = Disposable.Create(cts, resource, e);
  206. var current = default(TSource);
  207. return Create(
  208. (ct, tcs) =>
  209. {
  210. e.MoveNext(cts.Token).Then(t =>
  211. {
  212. t.Handle(tcs,
  213. res =>
  214. {
  215. if (res)
  216. {
  217. current = e.Current;
  218. tcs.TrySetResult(true);
  219. }
  220. else
  221. {
  222. d.Dispose();
  223. tcs.TrySetResult(false);
  224. }
  225. },
  226. ex =>
  227. {
  228. d.Dispose();
  229. tcs.TrySetException(ex);
  230. }
  231. );
  232. });
  233. return tcs.Task;
  234. },
  235. () => current,
  236. d.Dispose
  237. );
  238. });
  239. }
  240. }
  241. }