Browse Source

Merge pull request #888 from dotnet/IxAsyncCancellation

Initial work to support EnumeratorCancellation.
Bart J.F. De Smet 5 years ago
parent
commit
8d279c6372
30 changed files with 515 additions and 9 deletions
  1. 6 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Amb.cs
  2. 12 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Buffer.cs
  3. 18 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Catch.cs
  4. 18 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Concat.cs
  5. 18 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Defer.cs
  6. 24 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/DistinctUntilChanged.cs
  7. 21 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Do.cs
  8. 18 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Expand.cs
  9. 12 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Finally.cs
  10. 7 1
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Generate.cs
  11. 6 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/IgnoreElements.cs
  12. 9 7
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Merge.cs
  13. 19 1
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Repeat.cs
  14. 36 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Scan.cs
  15. 18 0
      Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Using.cs
  16. 6 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Cast.cs
  17. 6 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Except.cs
  18. 18 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/GroupJoin.cs
  19. 6 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Intersect.cs
  20. 18 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Join.cs
  21. 6 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/OfType.cs
  22. 18 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Select.cs
  23. 54 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SelectMany.cs
  24. 6 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SkipLast.cs
  25. 36 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SkipWhile.cs
  26. 6 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/TakeLast.cs
  27. 36 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/TakeWhile.cs
  28. 18 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Where.cs
  29. 24 0
      Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Zip.cs
  30. 15 0
      Ix.NET/Source/System.Linq.Async/System/Runtime/CompilerServices/EnumeratorCancellationAttribute.cs

+ 6 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Amb.cs

@@ -25,9 +25,15 @@ namespace System.Linq
             if (second == null)
                 throw Error.ArgumentNull(nameof(second));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(first, second);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> first, IAsyncEnumerable<TSource> second, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 IAsyncEnumerator<TSource>? firstEnumerator = null;
                 IAsyncEnumerator<TSource>? secondEnumerator = null;

+ 12 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Buffer.cs

@@ -26,9 +26,15 @@ namespace System.Linq
             if (count <= 0)
                 throw Error.ArgumentOutOfRange(nameof(count));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, count);
+
+            static async IAsyncEnumerable<IList<TSource>> Core(IAsyncEnumerable<TSource> source, int count, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<IList<TSource>> Core(CancellationToken cancellationToken)
+#endif
             {
                 var buffer = new List<TSource>(count);
 
@@ -70,9 +76,15 @@ namespace System.Linq
             if (skip <= 0)
                 throw Error.ArgumentOutOfRange(nameof(skip));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, count, skip);
+
+            static async IAsyncEnumerable<IList<TSource>> Core(IAsyncEnumerable<TSource> source, int count, int skip, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<IList<TSource>> Core(CancellationToken cancellationToken)
+#endif
             {
                 var buffers = new Queue<IList<TSource>>();
 

+ 18 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Catch.cs

@@ -33,9 +33,15 @@ namespace System.Linq
             if (handler == null)
                 throw Error.ArgumentNull(nameof(handler));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, handler);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TException, IAsyncEnumerable<TSource>> handler, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 // REVIEW: This implementation mirrors the Ix implementation, which does not protect GetEnumerator
                 //         using the try statement either. A more trivial implementation would use await foreach
@@ -96,9 +102,15 @@ namespace System.Linq
             if (handler == null)
                 throw Error.ArgumentNull(nameof(handler));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, handler);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TException, ValueTask<IAsyncEnumerable<TSource>>> handler, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 // REVIEW: This implementation mirrors the Ix implementation, which does not protect GetEnumerator
                 //         using the try statement either. A more trivial implementation would use await foreach
@@ -160,9 +172,15 @@ namespace System.Linq
             if (handler == null)
                 throw Error.ArgumentNull(nameof(handler));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, handler);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TException, CancellationToken, ValueTask<IAsyncEnumerable<TSource>>> handler, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 // REVIEW: This implementation mirrors the Ix implementation, which does not protect GetEnumerator
                 //         using the try statement either. A more trivial implementation would use await foreach

+ 18 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Concat.cs

@@ -22,9 +22,15 @@ namespace System.Linq
             if (sources == null)
                 throw Error.ArgumentNull(nameof(sources));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(sources);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<IAsyncEnumerable<TSource>> sources, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var source in sources.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -48,9 +54,15 @@ namespace System.Linq
             if (sources == null)
                 throw Error.ArgumentNull(nameof(sources));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(sources);
+
+            static async IAsyncEnumerable<TSource> Core(IEnumerable<IAsyncEnumerable<TSource>> sources, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 foreach (var source in sources)
                 {
@@ -74,9 +86,15 @@ namespace System.Linq
             if (sources == null)
                 throw Error.ArgumentNull(nameof(sources));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(sources);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource>[] sources, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 foreach (var source in sources)
                 {

+ 18 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Defer.cs

@@ -22,9 +22,15 @@ namespace System.Linq
             if (factory == null)
                 throw Error.ArgumentNull(nameof(factory));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(factory);
+
+            static async IAsyncEnumerable<TSource> Core(Func<IAsyncEnumerable<TSource>> factory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var item in factory().WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -46,9 +52,15 @@ namespace System.Linq
             if (factory == null)
                 throw Error.ArgumentNull(nameof(factory));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(factory);
+
+            static async IAsyncEnumerable<TSource> Core(Func<Task<IAsyncEnumerable<TSource>>> factory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var item in (await factory().ConfigureAwait(false)).WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -73,9 +85,15 @@ namespace System.Linq
             if (factory == null)
                 throw Error.ArgumentNull(nameof(factory));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(factory);
+
+            static async IAsyncEnumerable<TSource> Core(Func<CancellationToken, Task<IAsyncEnumerable<TSource>>> factory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var item in (await factory(cancellationToken).ConfigureAwait(false)).WithCancellation(cancellationToken).ConfigureAwait(false))
                 {

+ 24 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/DistinctUntilChanged.cs

@@ -166,9 +166,15 @@ namespace System.Linq
         {
             comparer ??= EqualityComparer<TSource>.Default;
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, comparer);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -201,9 +207,15 @@ namespace System.Linq
         {
             comparer ??= EqualityComparer<TKey>.Default;
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, keySelector, comparer);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -240,9 +252,15 @@ namespace System.Linq
         {
             comparer ??= EqualityComparer<TKey>.Default;
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, keySelector, comparer);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TSource> comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -280,9 +298,15 @@ namespace System.Linq
         {
             comparer ??= EqualityComparer<TKey>.Default;
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, keySelector, comparer);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TSource> comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 

+ 21 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Do.cs

@@ -299,9 +299,16 @@ namespace System.Linq
 
         private static IAsyncEnumerable<TSource> DoCore<TSource>(IAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception>? onError, Action? onCompleted)
         {
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, onNext, onError, onCompleted);
+
+            // TODO: Can remove local function.
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception>? onError, Action? onCompleted, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -339,9 +346,16 @@ namespace System.Linq
 
         private static IAsyncEnumerable<TSource> DoCore<TSource>(IAsyncEnumerable<TSource> source, Func<TSource, Task> onNext, Func<Exception, Task>? onError, Func<Task>? onCompleted)
         {
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, onNext, onError, onCompleted);
+
+            // TODO: Can remove local function.
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, Task> onNext, Func<Exception, Task>? onError, Func<Task>? onCompleted, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -383,9 +397,16 @@ namespace System.Linq
 #if !NO_DEEP_CANCELLATION
         private static IAsyncEnumerable<TSource> DoCore<TSource>(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, Task> onNext, Func<Exception, CancellationToken, Task>? onError, Func<CancellationToken, Task>? onCompleted)
         {
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, onNext, onError, onCompleted);
+
+            // TODO: Can remove local function.
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, Task> onNext, Func<Exception, CancellationToken, Task>? onError, Func<CancellationToken, Task>? onCompleted, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 

+ 18 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Expand.cs

@@ -24,9 +24,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, IAsyncEnumerable<TSource>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var queue = new Queue<IAsyncEnumerable<TSource>>();
 
@@ -58,9 +64,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<IAsyncEnumerable<TSource>>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var queue = new Queue<IAsyncEnumerable<TSource>>();
 
@@ -93,9 +105,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<IAsyncEnumerable<TSource>>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var queue = new Queue<IAsyncEnumerable<TSource>>();
 

+ 12 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Finally.cs

@@ -25,9 +25,15 @@ namespace System.Linq
             if (finallyAction == null)
                 throw Error.ArgumentNull(nameof(finallyAction));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, finallyAction);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Action finallyAction, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 try
                 {
@@ -58,9 +64,15 @@ namespace System.Linq
             if (finallyAction == null)
                 throw Error.ArgumentNull(nameof(finallyAction));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, finallyAction);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<Task> finallyAction, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 try
                 {

+ 7 - 1
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Generate.cs

@@ -31,10 +31,16 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(initialState, condition, iterate, resultSelector);
+
+            static async IAsyncEnumerable<TResult> Core(TState initialState, Func<TState, bool> condition, Func<TState, TState> iterate, Func<TState, TResult> resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
-#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 for (var state = initialState; condition(state); state = iterate(state))
                 {

+ 6 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/IgnoreElements.cs

@@ -22,9 +22,15 @@ namespace System.Linq
             if (source == null)
                 throw Error.ArgumentNull(nameof(source));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var _ in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {

+ 9 - 7
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Merge.cs

@@ -22,6 +22,15 @@ namespace System.Linq
             if (sources == null)
                 throw Error.ArgumentNull(nameof(sources));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(sources);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource>[] sources, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
+            return AsyncEnumerable.Create(Core);
+
+            async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
 #if USE_FAIR_AND_CHEAPER_MERGE
             //
             // This new implementation of Merge differs from the original one in a few ways:
@@ -34,10 +43,6 @@ namespace System.Linq
             //     instead of awaiting a new WhenAny task where "left" sources have preferential
             //     treatment over "right" sources.
             //
-
-            return AsyncEnumerable.Create(Core);
-
-            async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
             {
                 var count = sources.Length;
 
@@ -177,9 +182,6 @@ namespace System.Linq
                 }
             }
 #else
-            return AsyncEnumerable.Create(Core);
-
-            async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
             {
                 var count = sources.Length;
 

+ 19 - 1
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Repeat.cs

@@ -18,10 +18,16 @@ namespace System.Linq
         /// <returns>The async-enumerable sequence producing the element repeatedly and sequentially.</returns>
         public static IAsyncEnumerable<TResult> Repeat<TResult>(TResult element)
         {
+#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(element);
+
+            static async IAsyncEnumerable<TResult> Core(TResult element, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
-#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 while (true)
                 {
@@ -45,9 +51,15 @@ namespace System.Linq
             if (source == null)
                 throw Error.ArgumentNull(nameof(source));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 while (true)
                 {
@@ -75,9 +87,15 @@ namespace System.Linq
             if (count < 0)
                 throw Error.ArgumentOutOfRange(nameof(count));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, count);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, int count, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 for (var i = 0; i < count; i++)
                 {

+ 36 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Scan.cs

@@ -30,9 +30,15 @@ namespace System.Linq
             if (accumulator == null)
                 throw Error.ArgumentNull(nameof(accumulator));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, accumulator);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, TSource, TSource> accumulator, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -70,9 +76,15 @@ namespace System.Linq
             if (accumulator == null)
                 throw Error.ArgumentNull(nameof(accumulator));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, seed, accumulator);
+
+            static async IAsyncEnumerable<TAccumulate> Core(IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TAccumulate> Core(CancellationToken cancellationToken)
+#endif
             {
                 var res = seed;
 
@@ -101,9 +113,15 @@ namespace System.Linq
             if (accumulator == null)
                 throw Error.ArgumentNull(nameof(accumulator));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, accumulator);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, TSource, ValueTask<TSource>> accumulator, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -140,9 +158,15 @@ namespace System.Linq
             if (accumulator == null)
                 throw Error.ArgumentNull(nameof(accumulator));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, accumulator);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, TSource, CancellationToken, ValueTask<TSource>> accumulator, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -181,9 +205,15 @@ namespace System.Linq
             if (accumulator == null)
                 throw Error.ArgumentNull(nameof(accumulator));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, seed, accumulator);
+
+            static async IAsyncEnumerable<TAccumulate> Core(IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, ValueTask<TAccumulate>> accumulator, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TAccumulate> Core(CancellationToken cancellationToken)
+#endif
             {
                 var res = seed;
 
@@ -215,9 +245,15 @@ namespace System.Linq
             if (accumulator == null)
                 throw Error.ArgumentNull(nameof(accumulator));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, seed, accumulator);
+
+            static async IAsyncEnumerable<TAccumulate> Core(IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, CancellationToken, ValueTask<TAccumulate>> accumulator, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TAccumulate> Core(CancellationToken cancellationToken)
+#endif
             {
                 var res = seed;
 

+ 18 - 0
Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Using.cs

@@ -28,9 +28,15 @@ namespace System.Linq
             if (enumerableFactory == null)
                 throw Error.ArgumentNull(nameof(enumerableFactory));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(resourceFactory, enumerableFactory);
+
+            static async IAsyncEnumerable<TSource> Core(Func<TResource> resourceFactory, Func<TResource, IAsyncEnumerable<TSource>> enumerableFactory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 using var resource = resourceFactory();
 
@@ -59,9 +65,15 @@ namespace System.Linq
             if (enumerableFactory == null)
                 throw Error.ArgumentNull(nameof(enumerableFactory));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(resourceFactory, enumerableFactory);
+
+            static async IAsyncEnumerable<TSource> Core(Func<Task<TResource>> resourceFactory, Func<TResource, ValueTask<IAsyncEnumerable<TSource>>> enumerableFactory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 using var resource = await resourceFactory().ConfigureAwait(false);
 
@@ -92,9 +104,15 @@ namespace System.Linq
             if (enumerableFactory == null)
                 throw Error.ArgumentNull(nameof(enumerableFactory));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(resourceFactory, enumerableFactory);
+
+            static async IAsyncEnumerable<TSource> Core(Func<CancellationToken, Task<TResource>> resourceFactory, Func<TResource, CancellationToken, ValueTask<IAsyncEnumerable<TSource>>> enumerableFactory, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return AsyncEnumerable.Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 using var resource = await resourceFactory(cancellationToken).ConfigureAwait(false);
 

+ 6 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Cast.cs

@@ -30,9 +30,15 @@ namespace System.Linq
                 return typedSource;
             }
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<object> source, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var obj in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {

+ 6 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Except.cs

@@ -37,9 +37,15 @@ namespace System.Linq
             if (second == null)
                 throw Error.ArgumentNull(nameof(second));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(first, second, comparer);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> first, IAsyncEnumerable<TSource> second, IEqualityComparer<TSource>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var set = new Set<TSource>(comparer);
 

+ 18 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/GroupJoin.cs

@@ -55,9 +55,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TOuter> outer, IAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IAsyncEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = outer.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -92,9 +98,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TOuter> outer, IAsyncEnumerable<TInner> inner, Func<TOuter, ValueTask<TKey>> outerKeySelector, Func<TInner, ValueTask<TKey>> innerKeySelector, Func<TOuter, IAsyncEnumerable<TInner>, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = outer.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -130,9 +142,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TOuter> outer, IAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, ValueTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, ValueTask<TKey>> innerKeySelector, Func<TOuter, IAsyncEnumerable<TInner>, CancellationToken, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = outer.GetConfiguredAsyncEnumerator(cancellationToken, false);
 

+ 6 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Intersect.cs

@@ -37,9 +37,15 @@ namespace System.Linq
             if (second == null)
                 throw Error.ArgumentNull(nameof(second));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(first, second, comparer);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> first, IAsyncEnumerable<TSource> second, IEqualityComparer<TSource>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var set = new Set<TSource>(comparer);
 

+ 18 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Join.cs

@@ -55,9 +55,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TOuter> outer, IAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = outer.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -108,9 +114,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TOuter> outer, IAsyncEnumerable<TInner> inner, Func<TOuter, ValueTask<TKey>> outerKeySelector, Func<TInner, ValueTask<TKey>> innerKeySelector, Func<TOuter, TInner, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = outer.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -162,9 +174,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TOuter> outer, IAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, ValueTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, ValueTask<TKey>> innerKeySelector, Func<TOuter, TInner, CancellationToken, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey>? comparer, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = outer.GetConfiguredAsyncEnumerator(cancellationToken, false);
 

+ 6 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/OfType.cs

@@ -30,9 +30,15 @@ namespace System.Linq
             if (source == null)
                 throw Error.ArgumentNull(nameof(source));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<object> source, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var obj in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {

+ 18 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Select.cs

@@ -50,9 +50,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -107,9 +113,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<TResult>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -133,9 +145,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<TResult>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 

+ 54 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SelectMany.cs

@@ -69,9 +69,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, IAsyncEnumerable<TResult>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -99,9 +105,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<IAsyncEnumerable<TResult>>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -130,9 +142,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<IAsyncEnumerable<TResult>>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -174,9 +192,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, collectionSelector, resultSelector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, IAsyncEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -199,9 +223,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, collectionSelector, resultSelector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, ValueTask<TResult>> resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -225,9 +255,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, collectionSelector, resultSelector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, CancellationToken, ValueTask<TResult>> resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -262,9 +298,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, collectionSelector, resultSelector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, IAsyncEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -294,9 +336,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, collectionSelector, resultSelector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, ValueTask<TResult>> resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -327,9 +375,15 @@ namespace System.Linq
             if (resultSelector == null)
                 throw Error.ArgumentNull(nameof(resultSelector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, collectionSelector, resultSelector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<IAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, CancellationToken, ValueTask<TResult>> resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 

+ 6 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SkipLast.cs

@@ -41,9 +41,15 @@ namespace System.Linq
                 count = 0;
             }
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, count);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, int count, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var queue = new Queue<TSource>();
 

+ 36 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SkipWhile.cs

@@ -25,9 +25,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -66,9 +72,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
                 var index = -1;
@@ -104,9 +116,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -137,9 +155,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
 
@@ -170,9 +194,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
                 var index = -1;
@@ -209,9 +239,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
                 var index = -1;

+ 6 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/TakeLast.cs

@@ -34,9 +34,15 @@ namespace System.Linq
                 return Empty<TSource>();
             }
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, count);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, int count, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 Queue<TSource> queue;
 

+ 36 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/TakeWhile.cs

@@ -25,9 +25,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -57,9 +63,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -87,9 +99,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -111,9 +129,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
                 {
@@ -135,9 +159,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -166,9 +196,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 

+ 18 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Where.cs

@@ -49,9 +49,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -111,9 +117,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 
@@ -140,9 +152,15 @@ namespace System.Linq
             if (predicate == null)
                 throw Error.ArgumentNull(nameof(predicate));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(source, predicate);
+
+            async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
+#endif
             {
                 var index = -1;
 

+ 24 - 0
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Zip.cs

@@ -18,9 +18,15 @@ namespace System.Linq
             if (second == null)
                 throw Error.ArgumentNull(nameof(second));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(first, second);
+
+            static async IAsyncEnumerable<(TFirst, TSecond)> Core(IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<(TFirst, TSecond)> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
                 await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);
@@ -53,9 +59,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(first, second, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
                 await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);
@@ -76,9 +88,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(first, second, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, ValueTask<TResult>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
                 await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);
@@ -100,9 +118,15 @@ namespace System.Linq
             if (selector == null)
                 throw Error.ArgumentNull(nameof(selector));
 
+#if HAS_ASYNC_ENUMERABLE_CANCELLATION
+            return Core(first, second, selector);
+
+            static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TFirst> first, IAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, CancellationToken, ValueTask<TResult>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
+#else
             return Create(Core);
 
             async IAsyncEnumerator<TResult> Core(CancellationToken cancellationToken)
+#endif
             {
                 await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
                 await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);

+ 15 - 0
Ix.NET/Source/System.Linq.Async/System/Runtime/CompilerServices/EnumeratorCancellationAttribute.cs

@@ -0,0 +1,15 @@
+#if !BCL_HAS_ENUMERATOR_CANCELLATION
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.CompilerServices
+{
+    [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+    public sealed class EnumeratorCancellationAttribute : Attribute
+    {
+    }
+}
+
+#endif