diff --git a/src/UniTask.NetCore/Linq/Reverse.cs b/src/UniTask.NetCore/Linq/Reverse.cs index c59f44b..4a553ca 100644 --- a/src/UniTask.NetCore/Linq/Reverse.cs +++ b/src/UniTask.NetCore/Linq/Reverse.cs @@ -1,775 +1,76 @@ -namespace Cysharp.Threading.Tasks.Linq +using Cysharp.Threading.Tasks.Internal; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace Cysharp.Threading.Tasks.Linq { - internal sealed class Reverse + public static partial class UniTaskAsyncEnumerable { + public static IUniTaskAsyncEnumerable Reverse(this IUniTaskAsyncEnumerable source) + { + Error.ThrowArgumentNullException(source, nameof(source)); + return new Reverse(source); + } } - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal sealed class Reverse : IUniTaskAsyncEnumerable + { + readonly IUniTaskAsyncEnumerable source; + + public Reverse(IUniTaskAsyncEnumerable source) + { + this.source = source; + } + + public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + return new Enumerator(source, cancellationToken); + } + + sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator + { + readonly IUniTaskAsyncEnumerable source; + CancellationToken cancellationToken; + + TSource[] array; + int index; + + public Enumerator(IUniTaskAsyncEnumerable source, CancellationToken cancellationToken) + { + this.source = source; + this.cancellationToken = cancellationToken; + } + + public TSource Current { get; private set; } + + // after consumed array, don't use await so allow async(not require UniTaskCompletionSourceCore). + public async UniTask MoveNextAsync() + { + cancellationToken.ThrowIfCancellationRequested(); + + if (array == null) + { + array = await source.ToArrayAsync(cancellationToken); + index = array.Length - 1; + } + + if (index != -1) + { + Current = array[index]; + --index; + return true; + } + else + { + return false; + } + } + + public UniTask DisposeAsync() + { + return default; + } + } + } +} \ No newline at end of file diff --git a/src/UniTask.NetCoreSandbox/Program.cs b/src/UniTask.NetCoreSandbox/Program.cs index ae8d8c7..843564a 100644 --- a/src/UniTask.NetCoreSandbox/Program.cs +++ b/src/UniTask.NetCoreSandbox/Program.cs @@ -39,17 +39,8 @@ namespace NetCoreSandbox static async Task Main(string[] args) { - Console.WriteLine("YEAH"); - try - { - var xs = await UniTaskAsyncEnumerable.Range(1, 10).Concat(UniTaskAsyncEnumerable.Throw(new InvalidOperationException("something"))) - .SumAsync(); - } - catch (Exception ex) - { - Console.WriteLine("EX"); - Console.WriteLine(ex); - } + var foo = Enumerable.Range(1, 10).ToArray().AsEnumerable().GetEnumerator() as IEnumerator; + Console.WriteLine(foo.GetType().FullName); } diff --git a/src/UniTask.NetCoreTests/Linq/Projection.cs b/src/UniTask.NetCoreTests/Linq/Projection.cs new file mode 100644 index 0000000..49f3017 --- /dev/null +++ b/src/UniTask.NetCoreTests/Linq/Projection.cs @@ -0,0 +1,40 @@ +using Cysharp.Threading.Tasks; +using Cysharp.Threading.Tasks.Linq; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Concurrency; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Xunit; + + +namespace NetCoreTests.Linq +{ + public class Projection + { + [Theory] + [InlineData(0, 0)] + [InlineData(0, 1)] + [InlineData(0, 2)] + [InlineData(0, 10)] + public async Task Reverse(int start, int count) + { + var xs = await Enumerable.Range(start, count).ToUniTaskAsyncEnumerable().Reverse().ToArrayAsync(); + var ys = Enumerable.Range(start, count).Reverse().ToArray(); + + xs.Should().BeEquivalentTo(ys); + } + + [Fact] + public async Task ReverseException() + { + foreach (var item in UniTaskTestException.Throws()) + { + var xs = item.Reverse().ToArrayAsync(); + await Assert.ThrowsAsync(async () => await xs); + } + } + } +}