diff --git a/src/UniTask.NetCore/Linq/ElementAt.cs b/src/UniTask.NetCore/Linq/ElementAt.cs index d92970a..03450f4 100644 --- a/src/UniTask.NetCore/Linq/ElementAt.cs +++ b/src/UniTask.NetCore/Linq/ElementAt.cs @@ -1,775 +1,58 @@ -namespace Cysharp.Threading.Tasks.Linq +using Cysharp.Threading.Tasks.Internal; +using System; +using System.Threading; + +namespace Cysharp.Threading.Tasks.Linq { - internal sealed class ElementAt + public static partial class UniTaskAsyncEnumerable { + public static UniTask ElementAtAsync(this IUniTaskAsyncEnumerable source, int index, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return ElementAt.InvokeAsync(source, index, cancellationToken, false); + } + + public static UniTask ElementAtOrDefaultAsync(this IUniTaskAsyncEnumerable source, int index, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return ElementAt.InvokeAsync(source, index, cancellationToken, true); + } } - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal static class ElementAt + { + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, int index, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + int i = 0; + while (await e.MoveNextAsync()) + { + if (i++ == index) + { + return e.Current; + } + } + + if (defaultIfEmpty) + { + return default; + } + else + { + throw Error.ArgumentOutOfRange(nameof(index)); + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + } +} \ No newline at end of file diff --git a/src/UniTask.NetCore/Linq/ElementAtOrDefault.cs b/src/UniTask.NetCore/Linq/ElementAtOrDefault.cs deleted file mode 100644 index 929c9c5..0000000 --- a/src/UniTask.NetCore/Linq/ElementAtOrDefault.cs +++ /dev/null @@ -1,775 +0,0 @@ -namespace Cysharp.Threading.Tasks.Linq -{ - internal sealed class ElementAtOrDefault - { - } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/UniTask.NetCore/Linq/First.cs b/src/UniTask.NetCore/Linq/First.cs index ebc630c..9cbb2e0 100644 --- a/src/UniTask.NetCore/Linq/First.cs +++ b/src/UniTask.NetCore/Linq/First.cs @@ -1,775 +1,200 @@ -namespace Cysharp.Threading.Tasks.Linq +using Cysharp.Threading.Tasks.Internal; +using System; +using System.Threading; + +namespace Cysharp.Threading.Tasks.Linq { - internal sealed class First + public static partial class UniTaskAsyncEnumerable { + public static UniTask FirstAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return First.InvokeAsync(source, cancellationToken, false); + } + + public static UniTask FirstAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return First.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask FirstAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return First.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask FirstAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return First.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask FirstOrDefaultAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return First.InvokeAsync(source, cancellationToken, true); + } + + public static UniTask FirstOrDefaultAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return First.InvokeAsync(source, predicate, cancellationToken, true); + } + + public static UniTask FirstOrDefaultAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return First.InvokeAsync(source, predicate, cancellationToken, true); + } + + public static UniTask FirstOrDefaultAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return First.InvokeAsync(source, predicate, cancellationToken, true); + } } - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal static class First + { + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + if (await e.MoveNextAsync()) + { + return e.Current; + } + else + { + if (defaultIfEmpty) + { + return default; + } + else + { + throw Error.NoElements(); + } + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (predicate(v)) + { + return v; + } + } + + if (defaultIfEmpty) + { + return default; + } + else + { + throw Error.NoElements(); + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (await predicate(v)) + { + return v; + } + } + + if (defaultIfEmpty) + { + return default; + } + else + { + throw Error.NoElements(); + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (await predicate(v, cancellationToken)) + { + return v; + } + } + + if (defaultIfEmpty) + { + return default; + } + else + { + throw Error.NoElements(); + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + } +} \ No newline at end of file diff --git a/src/UniTask.NetCore/Linq/FirstOrDefault.cs b/src/UniTask.NetCore/Linq/FirstOrDefault.cs deleted file mode 100644 index 8766cab..0000000 --- a/src/UniTask.NetCore/Linq/FirstOrDefault.cs +++ /dev/null @@ -1,775 +0,0 @@ -namespace Cysharp.Threading.Tasks.Linq -{ - internal sealed class FirstOrDefault - { - } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/UniTask.NetCore/Linq/Last.cs b/src/UniTask.NetCore/Linq/Last.cs index 940b967..430aedb 100644 --- a/src/UniTask.NetCore/Linq/Last.cs +++ b/src/UniTask.NetCore/Linq/Last.cs @@ -1,775 +1,240 @@ -namespace Cysharp.Threading.Tasks.Linq +using Cysharp.Threading.Tasks.Internal; +using System; +using System.Threading; + +namespace Cysharp.Threading.Tasks.Linq { - internal sealed class Last + public static partial class UniTaskAsyncEnumerable { + public static UniTask LastAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return Last.InvokeAsync(source, cancellationToken, false); + } + + public static UniTask LastAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return Last.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask LastAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return Last.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask LastAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return Last.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask LastOrDefaultAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return Last.InvokeAsync(source, cancellationToken, true); + } + + public static UniTask LastOrDefaultAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return Last.InvokeAsync(source, predicate, cancellationToken, true); + } + + public static UniTask LastOrDefaultAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return Last.InvokeAsync(source, predicate, cancellationToken, true); + } + + public static UniTask LastOrDefaultAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return Last.InvokeAsync(source, predicate, cancellationToken, true); + } } - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal static class Last + { + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + TSource value = default; + if (await e.MoveNextAsync()) + { + value = e.Current; + } + else + { + if (defaultIfEmpty) + { + return value; + } + else + { + throw Error.NoElements(); + } + } + + while (await e.MoveNextAsync()) + { + value = e.Current; + } + return value; + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + TSource value = default; + + bool found = false; + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (predicate(v)) + { + found = true; + value = v; + } + } + + if (defaultIfEmpty) + { + return value; + } + else + { + if (found) + { + return value; + } + else + { + throw Error.NoElements(); + } + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + TSource value = default; + + bool found = false; + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (await predicate(v)) + { + found = true; + value = v; + } + } + + if (defaultIfEmpty) + { + return value; + } + else + { + if (found) + { + return value; + } + else + { + throw Error.NoElements(); + } + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + TSource value = default; + + bool found = false; + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (await predicate(v, cancellationToken)) + { + found = true; + value = v; + } + } + + if (defaultIfEmpty) + { + return value; + } + else + { + if (found) + { + return value; + } + else + { + throw Error.NoElements(); + } + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + } +} \ No newline at end of file diff --git a/src/UniTask.NetCore/Linq/LastOrDefault.cs b/src/UniTask.NetCore/Linq/LastOrDefault.cs deleted file mode 100644 index b18f736..0000000 --- a/src/UniTask.NetCore/Linq/LastOrDefault.cs +++ /dev/null @@ -1,775 +0,0 @@ -namespace Cysharp.Threading.Tasks.Linq -{ - internal sealed class LastOrDefault - { - } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/UniTask.NetCore/Linq/Single.cs b/src/UniTask.NetCore/Linq/Single.cs index 8fd06ae..512eb88 100644 --- a/src/UniTask.NetCore/Linq/Single.cs +++ b/src/UniTask.NetCore/Linq/Single.cs @@ -1,776 +1,230 @@ -namespace Cysharp.Threading.Tasks.Linq +using Cysharp.Threading.Tasks.Internal; +using System; +using System.Threading; + +namespace Cysharp.Threading.Tasks.Linq { - // avoid conflicts with System.Single - internal sealed class SingleOperator + public static partial class UniTaskAsyncEnumerable { + public static UniTask SingleAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return SingleOperator.InvokeAsync(source, cancellationToken, false); + } + + public static UniTask SingleAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return SingleOperator.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask SingleAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return SingleOperator.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask SingleAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return SingleOperator.InvokeAsync(source, predicate, cancellationToken, false); + } + + public static UniTask SingleOrDefaultAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + + return SingleOperator.InvokeAsync(source, cancellationToken, true); + } + + public static UniTask SingleOrDefaultAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return SingleOperator.InvokeAsync(source, predicate, cancellationToken, true); + } + + public static UniTask SingleOrDefaultAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return SingleOperator.InvokeAsync(source, predicate, cancellationToken, true); + } + + public static UniTask SingleOrDefaultAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) + { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(predicate, nameof(predicate)); + + return SingleOperator.InvokeAsync(source, predicate, cancellationToken, true); + } } - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal static class SingleOperator + { + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + if (await e.MoveNextAsync()) + { + var v = e.Current; + if (!await e.MoveNextAsync()) + { + return v; + } + + throw Error.MoreThanOneElement(); + } + else + { + if (defaultIfEmpty) + { + return default; + } + else + { + throw Error.NoElements(); + } + } + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + TSource value = default; + bool found = false; + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (predicate(v)) + { + if (found) + { + throw Error.MoreThanOneElement(); + } + else + { + found = true; + value = v; + } + } + } + + if (found || defaultIfEmpty) + { + return value; + } + + throw Error.NoElements(); + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + TSource value = default; + bool found = false; + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (await predicate(v)) + { + if (found) + { + throw Error.MoreThanOneElement(); + } + else + { + found = true; + value = v; + } + } + } + + if (found || defaultIfEmpty) + { + return value; + } + + throw Error.NoElements(); + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + + public static async UniTask InvokeAsync(IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken, bool defaultIfEmpty) + { + var e = source.GetAsyncEnumerator(cancellationToken); + try + { + TSource value = default; + bool found = false; + while (await e.MoveNextAsync()) + { + var v = e.Current; + if (await predicate(v, cancellationToken)) + { + if (found) + { + throw Error.MoreThanOneElement(); + } + else + { + found = true; + value = v; + } + } + } + + if (found || defaultIfEmpty) + { + return value; + } + + throw Error.NoElements(); + } + finally + { + if (e != null) + { + await e.DisposeAsync(); + } + } + } + } +} \ No newline at end of file diff --git a/src/UniTask.NetCore/Linq/SingleOrDefault.cs b/src/UniTask.NetCore/Linq/SingleOrDefault.cs deleted file mode 100644 index ffec4ca..0000000 --- a/src/UniTask.NetCore/Linq/SingleOrDefault.cs +++ /dev/null @@ -1,775 +0,0 @@ -namespace Cysharp.Threading.Tasks.Linq -{ - internal sealed class SingleOrDefault - { - } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/UniTask.NetCore/Linq/ToUniTaskAsyncEnumerable.cs b/src/UniTask.NetCore/Linq/ToUniTaskAsyncEnumerable.cs index 067738d..ed452c5 100644 --- a/src/UniTask.NetCore/Linq/ToUniTaskAsyncEnumerable.cs +++ b/src/UniTask.NetCore/Linq/ToUniTaskAsyncEnumerable.cs @@ -223,6 +223,8 @@ namespace Cysharp.Threading.Tasks.Linq CancellationToken cancellationToken; + bool useCachedCurrent; + T current; bool subscribeCompleted; readonly Queue queuedResult; Exception error; @@ -250,7 +252,14 @@ namespace Cysharp.Threading.Tasks.Linq ExceptionDispatchInfo.Capture(error).Throw(); } - return queuedResult.Dequeue(); + if (useCachedCurrent) + { + return current; + } + + current = queuedResult.Dequeue(); + useCachedCurrent = true; + return current; } } @@ -258,6 +267,8 @@ namespace Cysharp.Threading.Tasks.Linq { lock (queuedResult) { + useCachedCurrent = false; + if (cancellationToken.IsCancellationRequested) { return UniTask.FromCanceled(cancellationToken); diff --git a/src/UniTask.NetCore/Linq/_FileMaker.cs b/src/UniTask.NetCore/Linq/_FileMaker.cs index 0f3fd29..a432008 100644 --- a/src/UniTask.NetCore/Linq/_FileMaker.cs +++ b/src/UniTask.NetCore/Linq/_FileMaker.cs @@ -172,45 +172,7 @@ namespace ___Dummy throw new NotImplementedException(); } - public static UniTask FirstAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - public static UniTask FirstAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask FirstAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask FirstAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask FirstOrDefaultAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask FirstOrDefaultAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask FirstOrDefaultAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask FirstOrDefaultAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } public static IUniTaskAsyncEnumerable GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer) @@ -403,46 +365,7 @@ namespace ___Dummy throw new NotImplementedException(); } - public static UniTask LastAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask LastAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask LastAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask LastAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask LastOrDefaultAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask LastOrDefaultAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask LastOrDefaultAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask LastOrDefaultAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - + public static UniTask LongCountAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) { throw new NotImplementedException(); @@ -611,46 +534,6 @@ namespace ___Dummy throw new NotImplementedException(); } - public static UniTask SingleAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask SingleAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask SingleAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask SingleAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask SingleOrDefaultAsync(this IUniTaskAsyncEnumerable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask SingleOrDefaultAsync(this IUniTaskAsyncEnumerable source, Func predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask SingleOrDefaultAwaitAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public static UniTask SingleOrDefaultAwaitWithCancellationAsync(this IUniTaskAsyncEnumerable source, Func> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - public static IUniTaskAsyncEnumerable Skip(this IUniTaskAsyncEnumerable source, Int32 count) { throw new NotImplementedException(); diff --git a/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs b/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs index 1c7a4e5..834968a 100644 --- a/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs +++ b/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs @@ -1,4 +1,6 @@ -using System; +#pragma warning disable 0649 + +using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Threading.Tasks.Sources; @@ -75,7 +77,6 @@ namespace Cysharp.Threading.Tasks struct UniTaskToValueTask { - public IUniTaskSource source; public T result; public short token; diff --git a/src/UniTask.NetCoreSandbox/Program.cs b/src/UniTask.NetCoreSandbox/Program.cs index fe5fb5f..18d9fc3 100644 --- a/src/UniTask.NetCoreSandbox/Program.cs +++ b/src/UniTask.NetCoreSandbox/Program.cs @@ -34,12 +34,13 @@ namespace NetCoreSandbox static async Task Main(string[] args) { - var x = await new[] { 110, 50, 200 }.ToUniTaskAsyncEnumerable().MinAsync(); - Console.WriteLine(x); - // new object[] { }.Min( + var xs = new[] { 1, 10, 100 }.GetEnumerator(); + while (xs.MoveNext()) + { - // AsyncEnumerable.MinAwaitAsync( + } + Console.WriteLine(xs.MoveNext()); } diff --git a/src/UniTask.NetCoreTests/Linq/FirstLast.cs b/src/UniTask.NetCoreTests/Linq/FirstLast.cs new file mode 100644 index 0000000..185ae35 --- /dev/null +++ b/src/UniTask.NetCoreTests/Linq/FirstLast.cs @@ -0,0 +1,258 @@ +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 FirstLast + { + [Fact] + public async Task FirstTest() + { + { + await Assert.ThrowsAsync(async () => await Enumerable.Empty().ToUniTaskAsyncEnumerable().FirstAsync()); + Assert.Throws(() => Enumerable.Empty().First()); + + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().FirstAsync(); + var y = new[] { 99 }.First(); + x.Should().Be(y); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().FirstAsync(x => x % 98 == 0)); + Assert.Throws(() => array.First(x => x % 98 == 0)); + + var x = await array.ToUniTaskAsyncEnumerable().FirstAsync(x => x % 2 == 0); + var y = array.First(x => x % 2 == 0); + x.Should().Be(y); + } + + { + var x = await Enumerable.Empty().ToUniTaskAsyncEnumerable().FirstOrDefaultAsync(); + var y = Enumerable.Empty().FirstOrDefault(); + x.Should().Be(y); + } + { + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().FirstOrDefaultAsync(); + var y = new[] { 99 }.FirstOrDefault(); + x.Should().Be(y); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + var x = await array.ToUniTaskAsyncEnumerable().FirstOrDefaultAsync(x => x % 98 == 0); + var y = array.FirstOrDefault(x => x % 98 == 0); + x.Should().Be(y); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + var x = await array.ToUniTaskAsyncEnumerable().FirstAsync(x => x % 2 == 0); + var y = array.FirstOrDefault(x => x % 2 == 0); + x.Should().Be(y); + } + } + + [Fact] + public async Task LastTest() + { + { + await Assert.ThrowsAsync(async () => await Enumerable.Empty().ToUniTaskAsyncEnumerable().LastAsync()); + Assert.Throws(() => Enumerable.Empty().Last()); + + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().LastAsync(); + var y = new[] { 99 }.Last(); + x.Should().Be(y); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().LastAsync(x => x % 98 == 0)); + Assert.Throws(() => array.Last(x => x % 98 == 0)); + + var x = await array.ToUniTaskAsyncEnumerable().LastAsync(x => x % 2 == 0); + var y = array.Last(x => x % 2 == 0); + x.Should().Be(y); + } + + { + var x = await Enumerable.Empty().ToUniTaskAsyncEnumerable().LastOrDefaultAsync(); + var y = Enumerable.Empty().LastOrDefault(); + x.Should().Be(y); + } + { + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().LastOrDefaultAsync(); + var y = new[] { 99 }.LastOrDefault(); + x.Should().Be(y); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + var x = await array.ToUniTaskAsyncEnumerable().LastOrDefaultAsync(x => x % 98 == 0); + var y = array.LastOrDefault(x => x % 98 == 0); + x.Should().Be(y); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + var x = await array.ToUniTaskAsyncEnumerable().LastOrDefaultAsync(x => x % 2 == 0); + var y = array.LastOrDefault(x => x % 2 == 0); + x.Should().Be(y); + } + } + + [Fact] + public async Task SingleTest() + { + { + await Assert.ThrowsAsync(async () => await Enumerable.Empty().ToUniTaskAsyncEnumerable().SingleAsync()); + Assert.Throws(() => Enumerable.Empty().Single()); + + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().SingleAsync(); + var y = new[] { 99 }.Single(); + x.Should().Be(y); + + var array = new[] { 99, 11, 135, 10, 144, 800 }; + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().SingleAsync()); + Assert.Throws(() => array.Single()); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + // not found + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().SingleAsync(x => x % 999 == 0)); + Assert.Throws(() => array.Single(x => x % 999 == 0)); + // found multi + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().SingleAsync(x => x % 2 == 0)); + Assert.Throws(() => array.Single(x => x % 2 == 0)); + + { + var x = await array.ToUniTaskAsyncEnumerable().SingleAsync(x => x % 144 == 0); + var y = array.Single(x => x % 144 == 0); + x.Should().Be(y); + } + { + var x = await array.ToUniTaskAsyncEnumerable().SingleAsync(x => x % 800 == 0); + var y = array.Single(x => x % 800 == 0); + x.Should().Be(y); + } + } + + { + { + var x = await Enumerable.Empty().ToUniTaskAsyncEnumerable().SingleOrDefaultAsync(); + var y = Enumerable.Empty().SingleOrDefault(); + x.Should().Be(y); + } + { + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().SingleOrDefaultAsync(); + var y = new[] { 99 }.SingleOrDefault(); + x.Should().Be(y); + + var array = new[] { 99, 11, 135, 10, 144, 800 }; + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().SingleOrDefaultAsync()); + Assert.Throws(() => array.SingleOrDefault()); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + // not found + { + var x = await array.ToUniTaskAsyncEnumerable().SingleOrDefaultAsync(x => x % 999 == 0); + var y = array.SingleOrDefault(x => x % 999 == 0); + x.Should().Be(y); + } + // found multi + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().SingleOrDefaultAsync(x => x % 2 == 0)); + Assert.Throws(() => array.SingleOrDefault(x => x % 2 == 0)); + + // normal + { + var x = await array.ToUniTaskAsyncEnumerable().SingleOrDefaultAsync(x => x % 144 == 0); + var y = array.SingleOrDefault(x => x % 144 == 0); + x.Should().Be(y); + } + { + var x = await array.ToUniTaskAsyncEnumerable().SingleOrDefaultAsync(x => x % 800 == 0); + var y = array.SingleOrDefault(x => x % 800 == 0); + x.Should().Be(y); + } + } + } + } + + + [Fact] + public async Task ElementAtTest() + { + { + await Assert.ThrowsAsync(async () => await Enumerable.Empty().ToUniTaskAsyncEnumerable().ElementAtAsync(0)); + Assert.Throws(() => Enumerable.Empty().ElementAt(0)); + + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().ElementAtAsync(0); + var y = new[] { 99 }.ElementAt(0); + x.Should().Be(y); + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + await Assert.ThrowsAsync(async () => await array.ToUniTaskAsyncEnumerable().ElementAtAsync(10)); + Assert.Throws(() => array.ElementAt(10)); + + { + var x = await array.ToUniTaskAsyncEnumerable().ElementAtAsync(0); + var y = array.ElementAt(0); + x.Should().Be(y); + } + { + var x = await array.ToUniTaskAsyncEnumerable().ElementAtAsync(3); + var y = array.ElementAt(3); + x.Should().Be(y); + } + { + var x = await array.ToUniTaskAsyncEnumerable().ElementAtAsync(5); + var y = array.ElementAt(5); + x.Should().Be(y); + } + } + + + { + { + var x = await Enumerable.Empty().ToUniTaskAsyncEnumerable().ElementAtOrDefaultAsync(0); + var y = Enumerable.Empty().ElementAtOrDefault(0); + x.Should().Be(y); + } + { + var x = await new[] { 99 }.ToUniTaskAsyncEnumerable().ElementAtOrDefaultAsync(0); + var y = new[] { 99 }.ElementAtOrDefault(0); + x.Should().Be(y); + } + } + { + var array = new[] { 99, 11, 135, 10, 144, 800 }; + { + var x = await array.ToUniTaskAsyncEnumerable().ElementAtOrDefaultAsync(10); + var y = array.ElementAtOrDefault(10); + x.Should().Be(y); + } + { + var x = await array.ToUniTaskAsyncEnumerable().ElementAtOrDefaultAsync(0); + var y = array.ElementAtOrDefault(0); + x.Should().Be(y); + } + { + var x = await array.ToUniTaskAsyncEnumerable().ElementAtOrDefaultAsync(3); + var y = array.ElementAtOrDefault(3); + x.Should().Be(y); + } + { + var x = await array.ToUniTaskAsyncEnumerable().ElementAtOrDefaultAsync(5); + var y = array.ElementAtOrDefault(5); + x.Should().Be(y); + } + } + } + } + + +} diff --git a/src/UniTask/Assets/Plugins/UniTask/Internal/Error.cs b/src/UniTask/Assets/Plugins/UniTask/Internal/Error.cs index 2ceae96..5c7bc93 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Internal/Error.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Internal/Error.cs @@ -20,16 +20,22 @@ namespace Cysharp.Threading.Tasks.Internal throw new ArgumentNullException(paramName); } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static Exception ArgumentOutOfRange(string paramName) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception ArgumentOutOfRange(string paramName) { return new ArgumentOutOfRangeException(paramName); } - [MethodImpl(MethodImplOptions.NoInlining)] - internal static Exception NoElements() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception NoElements() { - throw new InvalidOperationException("Source sequence doesn't contain any elements."); + return new InvalidOperationException("Source sequence doesn't contain any elements."); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception MoreThanOneElement() + { + return new InvalidOperationException("Source sequence contains more than one element."); } [MethodImpl(MethodImplOptions.NoInlining)]