From 4cd90ceb9116adea17c5f0db48d423a3f0aa4d1c Mon Sep 17 00:00:00 2001
From: Ruben Schmidmeister <4602612+bash@users.noreply.github.com>
Date: Sat, 22 May 2021 10:49:47 +0200
Subject: [PATCH 01/11] Add reference to System.Collections.Immutable NuGet
package for down-level support
---
Ix.NET/Source/System.Linq.Async/System.Linq.Async.csproj | 1 +
.../refs/System.Linq.Async.Ref/System.Linq.Async.Ref.csproj | 2 ++
2 files changed, 3 insertions(+)
diff --git a/Ix.NET/Source/System.Linq.Async/System.Linq.Async.csproj b/Ix.NET/Source/System.Linq.Async/System.Linq.Async.csproj
index 1bfe13cbef..09d7dd28b6 100644
--- a/Ix.NET/Source/System.Linq.Async/System.Linq.Async.csproj
+++ b/Ix.NET/Source/System.Linq.Async/System.Linq.Async.csproj
@@ -27,6 +27,7 @@
+
diff --git a/Ix.NET/Source/refs/System.Linq.Async.Ref/System.Linq.Async.Ref.csproj b/Ix.NET/Source/refs/System.Linq.Async.Ref/System.Linq.Async.Ref.csproj
index ead9cd3018..0d355fff3c 100644
--- a/Ix.NET/Source/refs/System.Linq.Async.Ref/System.Linq.Async.Ref.csproj
+++ b/Ix.NET/Source/refs/System.Linq.Async.Ref/System.Linq.Async.Ref.csproj
@@ -16,6 +16,8 @@
ExtrasIsReferenceAssembly;AssemblyName;Version;AssemblyTitle
+
From efccb6335352c42a7c5c878c0e0e28c270092bc9 Mon Sep 17 00:00:00 2001
From: Ruben Schmidmeister <4602612+bash@users.noreply.github.com>
Date: Sat, 22 May 2021 11:16:24 +0200
Subject: [PATCH 02/11] Implement ToImmutableDictionaryAsync
---
.../Linq/Operators/ToImmutableDictionary.cs | 112 ++++++++
.../System/Linq/FunctionalHelpers.cs | 23 ++
.../Linq/Operators/ToImmutableDictionary.cs | 267 ++++++++++++++++++
3 files changed, 402 insertions(+)
create mode 100644 Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableDictionary.cs
create mode 100644 Ix.NET/Source/System.Linq.Async/System/Linq/FunctionalHelpers.cs
create mode 100644 Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableDictionary.cs
diff --git a/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableDictionary.cs b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableDictionary.cs
new file mode 100644
index 0000000000..e4ad40b40d
--- /dev/null
+++ b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableDictionary.cs
@@ -0,0 +1,112 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+ public class ToImmutableDictionary : AsyncEnumerableTests
+ {
+ [Fact]
+ public async Task ToImmutableDictionary_Null()
+ {
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default(Func)).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0, EqualityComparer.Default).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default, EqualityComparer.Default).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0, x => 0).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default, x => 0).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, x => 0, default).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0, x => 0, EqualityComparer.Default).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default, x => 0, EqualityComparer.Default).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, x => 0, default, EqualityComparer.Default).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default(Func), CancellationToken.None).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0, EqualityComparer.Default, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default, EqualityComparer.Default, CancellationToken.None).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0, x => 0, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default, x => 0, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, x => 0, default, CancellationToken.None).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(default, x => 0, x => 0, EqualityComparer.Default, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, default, x => 0, EqualityComparer.Default, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableDictionaryAsync(Return42, x => 0, default, EqualityComparer.Default, CancellationToken.None).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableDictionary1Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableDictionaryAsync(x => x % 2);
+ Assert.True(res[0] == 4);
+ Assert.True(res[1] == 1);
+ }
+
+ [Fact]
+ public async Task ToImmutableDictionary2Async()
+ {
+ var xs = new[] { 1, 4, 2 }.ToAsyncEnumerable();
+ await AssertThrowsAsync(xs.ToImmutableDictionaryAsync(x => x % 2).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableDictionary3Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableDictionaryAsync(x => x % 2, x => x + 1);
+ Assert.True(res[0] == 5);
+ Assert.True(res[1] == 2);
+ }
+
+ [Fact]
+ public async Task ToImmutableDictionary4Async()
+ {
+ var xs = new[] { 1, 4, 2 }.ToAsyncEnumerable();
+ await AssertThrowsAsync(xs.ToImmutableDictionaryAsync(x => x % 2, x => x + 1).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableDictionary5Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableDictionaryAsync(x => x % 2, new Eq());
+ Assert.True(res[0] == 4);
+ Assert.True(res[1] == 1);
+ }
+
+ [Fact]
+ public async Task ToImmutableDictionary6Async()
+ {
+ var xs = new[] { 1, 4, 2 }.ToAsyncEnumerable();
+ await AssertThrowsAsync(xs.ToImmutableDictionaryAsync(x => x % 2, new Eq()).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableDictionary7Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableDictionaryAsync(x => x % 2, x => x, new Eq());
+ Assert.True(res[0] == 4);
+ Assert.True(res[1] == 1);
+ }
+
+ private sealed class Eq : IEqualityComparer
+ {
+ public bool Equals(int x, int y) => EqualityComparer.Default.Equals(Math.Abs(x), Math.Abs(y));
+
+ public int GetHashCode(int obj) => EqualityComparer.Default.GetHashCode(Math.Abs(obj));
+ }
+ }
+}
diff --git a/Ix.NET/Source/System.Linq.Async/System/Linq/FunctionalHelpers.cs b/Ix.NET/Source/System.Linq.Async/System/Linq/FunctionalHelpers.cs
new file mode 100644
index 0000000000..f88e9ca9b2
--- /dev/null
+++ b/Ix.NET/Source/System.Linq.Async/System/Linq/FunctionalHelpers.cs
@@ -0,0 +1,23 @@
+// 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.
+
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Linq.Async.System.Linq
+{
+ internal static class FunctionalHelpers
+ {
+ public static T Identity(T value) => value;
+
+ public static ValueTask IdentityAsync(T value) => new(value);
+
+ public static ValueTask IdentityAsync(T value, CancellationToken token) => new(value);
+
+ public static TKey Key(KeyValuePair kvp) => kvp.Key;
+
+ public static TValue Value(KeyValuePair kvp) => kvp.Value;
+ }
+}
diff --git a/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableDictionary.cs b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableDictionary.cs
new file mode 100644
index 0000000000..e2fed0282c
--- /dev/null
+++ b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableDictionary.cs
@@ -0,0 +1,267 @@
+// 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.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using static System.Linq.Async.System.Linq.FunctionalHelpers;
+
+namespace System.Linq
+{
+ public static partial class AsyncEnumerable
+ {
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence according to a specified key selector function.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(this IAsyncEnumerable source, Func keySelector, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAsync(keySelector, elementSelector: Identity, keyComparer: null, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence according to a specified key selector function, and an element selector function.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// , , or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(this IAsyncEnumerable source, Func keySelector, Func elementSelector, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAsync(keySelector, elementSelector, keyComparer: null, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence according to a specified key selector function, and a key equality comparer.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// An equality comparer to compare keys.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(this IAsyncEnumerable source, Func keySelector, IEqualityComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAsync(keySelector, elementSelector: Identity, keyComparer, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence according to a specified key selector function, an element selector function, and a key equality comparer.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ /// An equality comparer to compare keys.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// , , or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(this IAsyncEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAsync(keySelector, elementSelector, keyComparer, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence of key/value pairs.
+ ///
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(this IAsyncEnumerable> source, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAsync(keySelector: Key, elementSelector: Value, keyComparer: null, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence of key/value pairs according to a specified key equality comparer.
+ ///
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An equality comparer to compare keys.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(this IAsyncEnumerable> source, IEqualityComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAsync(keySelector: Key, elementSelector: Value, keyComparer, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence of key/value pairs according to a specified key equality comparer and a value equality comparer.
+ ///
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An equality comparer to compare keys.
+ /// An equality comparer to compare values.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(this IAsyncEnumerable> source, IEqualityComparer? keyComparer, IEqualityComparer? valueComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAsync(keySelector: Key, elementSelector: Value, keyComparer, valueComparer, cancellationToken);
+
+ ///
+ /// Creates an immutable dictionary from an async-enumerable sequence according to a specified key selector function, an element selector function, a key equality comparer and a value equality comparer.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ /// An equality comparer to compare keys.
+ /// An equality comparer to compare values.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// , , or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableDictionaryAsync(
+ this IAsyncEnumerable source,
+ Func keySelector, Func elementSelector,
+ IEqualityComparer? keyComparer, IEqualityComparer? valueComparer,
+ CancellationToken cancellationToken = default)
+ where TKey : notnull
+ {
+ if (source == null)
+ throw Error.ArgumentNull(nameof(source));
+ if (keySelector == null)
+ throw Error.ArgumentNull(nameof(keySelector));
+ if (elementSelector == null)
+ throw Error.ArgumentNull(nameof(elementSelector));
+
+ return Core(source, keySelector, elementSelector, keyComparer, valueComparer, cancellationToken);
+
+ static async ValueTask> Core(
+ IAsyncEnumerable source,
+ Func keySelector, Func elementSelector,
+ IEqualityComparer? keyComparer, IEqualityComparer? valueComparer,
+ CancellationToken cancellationToken = default)
+ {
+ var builder = ImmutableDictionary.CreateBuilder(keyComparer, valueComparer);
+
+ await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
+ {
+ builder.Add(keySelector(item), elementSelector(item));
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitAsyncCore(this IAsyncEnumerable source, Func> keySelector, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitAsyncCore(keySelector, elementSelector: IdentityAsync, keyComparer: null, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitAsyncCore(this IAsyncEnumerable source, Func> keySelector, Func> elementSelector, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitAsyncCore(keySelector, elementSelector, keyComparer: null, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitAsyncCore(this IAsyncEnumerable source, Func> keySelector, IEqualityComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitAsyncCore(keySelector, elementSelector: IdentityAsync, keyComparer, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitAsyncCore(this IAsyncEnumerable source, Func> keySelector, Func> elementSelector, IEqualityComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitAsyncCore(keySelector, elementSelector, keyComparer, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitAsyncCore(
+ this IAsyncEnumerable source,
+ Func> keySelector, Func> elementSelector,
+ IEqualityComparer? keyComparer, IEqualityComparer? valueComparer,
+ CancellationToken cancellationToken = default)
+ where TKey : notnull
+ {
+ if (source == null)
+ throw Error.ArgumentNull(nameof(source));
+ if (keySelector == null)
+ throw Error.ArgumentNull(nameof(keySelector));
+ if (elementSelector == null)
+ throw Error.ArgumentNull(nameof(elementSelector));
+
+ return Core(source, keySelector, elementSelector, keyComparer, valueComparer, cancellationToken);
+
+ static async ValueTask> Core(
+ IAsyncEnumerable source,
+ Func> keySelector, Func> elementSelector,
+ IEqualityComparer? keyComparer, IEqualityComparer? valueComparer,
+ CancellationToken cancellationToken = default)
+ {
+ var builder = ImmutableDictionary.CreateBuilder(keyComparer, valueComparer);
+
+ await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
+ {
+ builder.Add(await keySelector(item).ConfigureAwait(false), await elementSelector(item).ConfigureAwait(false));
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitWithCancellationAsyncCore(this IAsyncEnumerable source, Func> keySelector, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitWithCancellationAsyncCore(keySelector, elementSelector: IdentityAsync, keyComparer: null, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitWithCancellationAsyncCore(this IAsyncEnumerable source, Func> keySelector, Func> elementSelector, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitWithCancellationAsyncCore(keySelector, elementSelector, keyComparer: null, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitWithCancellationAsyncCore(this IAsyncEnumerable source, Func> keySelector, IEqualityComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitWithCancellationAsyncCore(keySelector, elementSelector: IdentityAsync, keyComparer, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitWithCancellationAsyncCore(this IAsyncEnumerable source, Func> keySelector, Func> elementSelector, IEqualityComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableDictionaryAwaitWithCancellationAsyncCore(keySelector, elementSelector, keyComparer, valueComparer: null, cancellationToken);
+
+ [GenerateAsyncOverload]
+ private static ValueTask> ToImmutableDictionaryAwaitWithCancellationAsyncCore(
+ this IAsyncEnumerable source,
+ Func> keySelector, Func> elementSelector,
+ IEqualityComparer? keyComparer, IEqualityComparer? valueComparer,
+ CancellationToken cancellationToken = default)
+ where TKey : notnull
+ {
+ if (source == null)
+ throw Error.ArgumentNull(nameof(source));
+ if (keySelector == null)
+ throw Error.ArgumentNull(nameof(keySelector));
+ if (elementSelector == null)
+ throw Error.ArgumentNull(nameof(elementSelector));
+
+ return Core(source, keySelector, elementSelector, keyComparer, valueComparer, cancellationToken);
+
+ static async ValueTask> Core(
+ IAsyncEnumerable source,
+ Func> keySelector, Func> elementSelector,
+ IEqualityComparer? keyComparer, IEqualityComparer? valueComparer,
+ CancellationToken cancellationToken = default)
+ {
+ var builder = ImmutableDictionary.CreateBuilder(keyComparer, valueComparer);
+
+ await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
+ {
+ builder.Add(await keySelector(item, cancellationToken).ConfigureAwait(false), await elementSelector(item, cancellationToken).ConfigureAwait(false));
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+ }
+}
From 840dcd8df2e63c6fada611c0d06557e61354d266 Mon Sep 17 00:00:00 2001
From: Ruben Schmidmeister <4602612+bash@users.noreply.github.com>
Date: Sun, 23 May 2021 22:39:00 +0200
Subject: [PATCH 03/11] Implement ToImmutableHashSetAsync
---
.../Linq/Operators/ToImmutableHashSet.cs | 48 ++++++++++++++++
.../Linq/Operators/ToImmutableHashSet.cs | 56 +++++++++++++++++++
2 files changed, 104 insertions(+)
create mode 100644 Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableHashSet.cs
create mode 100644 Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableHashSet.cs
diff --git a/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableHashSet.cs b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableHashSet.cs
new file mode 100644
index 0000000000..6875df62cf
--- /dev/null
+++ b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableHashSet.cs
@@ -0,0 +1,48 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+ public class ToImmutableHashSet : AsyncEnumerableTests
+ {
+ [Fact]
+ public async Task ToImmutableHashSet_Null()
+ {
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableHashSetAsync(default).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableHashSetAsync(default, CancellationToken.None).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableHashSetAsync(default, EqualityComparer.Default, CancellationToken.None).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableHashSet_Simple()
+ {
+ var xs = new[] { 1, 2, 1, 2, 3, 4, 1, 2, 3, 4 };
+ var res = xs.ToAsyncEnumerable().ToImmutableHashSetAsync();
+ Assert.True((await res).OrderBy(x => x).SequenceEqual(new[] { 1, 2, 3, 4 }));
+ }
+
+ [Fact]
+ public async Task ToImmutableHashSet_Comparer()
+ {
+ var xs = new[] { 1, 12, 11, 2, 3, 14, 1, 12, 13, 4 };
+ var res = xs.ToAsyncEnumerable().ToImmutableHashSetAsync(new Eq());
+ Assert.True((await res).OrderBy(x => x).SequenceEqual(new[] { 1, 3, 12, 14 }));
+ }
+
+ private class Eq : IEqualityComparer
+ {
+ public bool Equals(int x, int y) => x % 10 == y % 10;
+
+ public int GetHashCode(int obj) => obj % 10;
+ }
+ }
+}
diff --git a/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableHashSet.cs b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableHashSet.cs
new file mode 100644
index 0000000000..18751a69c8
--- /dev/null
+++ b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableHashSet.cs
@@ -0,0 +1,56 @@
+// 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.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Linq
+{
+ public static partial class AsyncEnumerable
+ {
+ ///
+ /// Creates an immutable hash set from an async-enumerable sequence.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The source async-enumerable sequence to get a hash set of elements for.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a hash set containing all the elements of the source sequence.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableHashSetAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default)
+ => ToImmutableHashSetAsync(source, equalityComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable hash set from an async-enumerable sequence according to a specified equality comparer.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The source async-enumerable sequence to get a hash set of elements for.
+ /// An equality comparer to compare elements of the sequence.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a hash set containing all the elements of the source sequence.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableHashSetAsync(this IAsyncEnumerable source, IEqualityComparer? equalityComparer, CancellationToken cancellationToken = default)
+ {
+ if (source == null)
+ throw Error.ArgumentNull(nameof(source));
+
+ return Core(source, equalityComparer, cancellationToken);
+
+ static async ValueTask> Core(IAsyncEnumerable source, IEqualityComparer? equalityComparer, CancellationToken cancellationToken)
+ {
+ var builder = ImmutableHashSet.CreateBuilder(equalityComparer);
+
+ await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
+ {
+ builder.Add(item);
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+ }
+}
From 7b5585905a962b1fa3be49a6d2a229fe15751fad Mon Sep 17 00:00:00 2001
From: Ruben Schmidmeister <4602612+bash@users.noreply.github.com>
Date: Mon, 24 May 2021 12:17:36 +0200
Subject: [PATCH 04/11] Implement ToImmutableSortedDictionaryAsync
---
.../Operators/ToImmutableSortedDictionary.cs | 106 +++++++++
.../Operators/ToImmutableSortedDictionary.cs | 222 ++++++++++++++++++
2 files changed, 328 insertions(+)
create mode 100644 Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableSortedDictionary.cs
create mode 100644 Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableSortedDictionary.cs
diff --git a/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableSortedDictionary.cs b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableSortedDictionary.cs
new file mode 100644
index 0000000000..d3c3f683d4
--- /dev/null
+++ b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/ToImmutableSortedDictionary.cs
@@ -0,0 +1,106 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+ public class ToImmutableSortedDictionary : AsyncEnumerableTests
+ {
+ [Fact]
+ public async Task ToImmutableSortedDictionary_Null()
+ {
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(default, x => 0, x => 0).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, default, x => 0).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, x => 0, default).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(default, x => 0, x => 0, Comparer.Default).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, default, x => 0, Comparer.Default).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, x => 0, default, Comparer.Default).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(default, x => 0, x => 0, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, default, x => 0, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, x => 0, default, CancellationToken.None).AsTask());
+
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(default, x => 0, x => 0, Comparer.Default, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, default, x => 0, Comparer.Default, CancellationToken.None).AsTask());
+ await Assert.ThrowsAsync(() => AsyncEnumerable.ToImmutableSortedDictionaryAsync(Return42, x => 0, default, Comparer.Default, CancellationToken.None).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary1Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableSortedDictionaryAsync(x => x % 2, x => x);
+ Assert.True(res[0] == 4);
+ Assert.True(res[1] == 1);
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary2Async()
+ {
+ var xs = new[] { 1, 4, 2 }.ToAsyncEnumerable();
+ await AssertThrowsAsync(xs.ToImmutableSortedDictionaryAsync(x => x % 2, x => x).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary3Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableSortedDictionaryAsync(x => x % 2, x => x + 1);
+ Assert.True(res[0] == 5);
+ Assert.True(res[1] == 2);
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary4Async()
+ {
+ var xs = new[] { 1, 4, 2 }.ToAsyncEnumerable();
+ await AssertThrowsAsync(xs.ToImmutableSortedDictionaryAsync(x => x % 2, x => x + 1).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary5Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableSortedDictionaryAsync(x => x % 2, x => x, new Eq());
+ Assert.True(res[0] == 4);
+ Assert.True(res[1] == 1);
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary6Async()
+ {
+ var xs = new[] { 1, 4, 2 }.ToAsyncEnumerable();
+ await AssertThrowsAsync(xs.ToImmutableSortedDictionaryAsync(x => x % 2, x => x, new Eq()).AsTask());
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary7Async()
+ {
+ var xs = new[] { 1, 4 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableSortedDictionaryAsync(x => x % 2, x => x, new Eq());
+ Assert.True(res[0] == 4);
+ Assert.True(res[1] == 1);
+ }
+
+ [Fact]
+ public async Task ToImmutableSortedDictionary8Async()
+ {
+ var xs = new[] { 5, 8, 7, 1, 9 }.ToAsyncEnumerable();
+ var res = await xs.ToImmutableSortedDictionaryAsync(x => x, x => x);
+ Assert.Equal(new[] { 1, 5, 7, 8, 9 }, res.Keys);
+ }
+
+ private sealed class Eq : IComparer
+ {
+ public int Compare(int x, int y) => Comparer.Default.Compare(Math.Abs(x), Math.Abs(y));
+ }
+ }
+}
diff --git a/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableSortedDictionary.cs b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableSortedDictionary.cs
new file mode 100644
index 0000000000..61a0bc4346
--- /dev/null
+++ b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToImmutableSortedDictionary.cs
@@ -0,0 +1,222 @@
+// 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.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using static System.Linq.Async.System.Linq.FunctionalHelpers;
+
+namespace System.Linq
+{
+ public static partial class AsyncEnumerable
+ {
+ ///
+ /// Creates an immutable sorted dictionary from an async-enumerable sequence according to a specified key selector function, and an element selector function.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// , , or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableSortedDictionaryAsync(this IAsyncEnumerable source, Func keySelector, Func elementSelector, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableSortedDictionaryAsync(keySelector, elementSelector, keyComparer: null, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable sorted dictionary from an async-enumerable sequence according to a specified key selector function, an element selector function, and a key comparer.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ /// A comparer to compare keys.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// , , or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableSortedDictionaryAsync(this IAsyncEnumerable source, Func keySelector, Func elementSelector, IComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableSortedDictionaryAsync(keySelector, elementSelector, keyComparer, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable sorted dictionary from an async-enumerable sequence of key/value pairs.
+ ///
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableSortedDictionaryAsync(this IAsyncEnumerable> source, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableSortedDictionaryAsync(keySelector: Key, elementSelector: Value, keyComparer: null, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable sorted dictionary from an async-enumerable sequence of key/value pairs according to a specified key comparer.
+ ///
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// A comparer to compare keys.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableSortedDictionaryAsync(this IAsyncEnumerable> source, IComparer? keyComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableSortedDictionaryAsync(keySelector: Key, elementSelector: Value, keyComparer, valueComparer: null, cancellationToken);
+
+ ///
+ /// Creates an immutable sorted dictionary from an async-enumerable sequence of key/value pairs according to a specified key comparer and a value equality comparer.
+ ///
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// A comparer to compare keys.
+ /// An equality comparer to compare values.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableSortedDictionaryAsync(this IAsyncEnumerable> source, IComparer? keyComparer, IEqualityComparer? valueComparer, CancellationToken cancellationToken = default) where TKey : notnull
+ => source.ToImmutableSortedDictionaryAsync(keySelector: Key, elementSelector: Value, keyComparer, valueComparer, cancellationToken);
+
+ ///
+ /// Creates an sorted immutable dictionary from an async-enumerable sequence according to a specified key selector function, an element selector function, a key comparer and a value equality comparer.
+ ///
+ /// The type of the elements in the source sequence.
+ /// The type of the dictionary key computed for each element in the source sequence.
+ /// The type of the dictionary value computed for each element in the source sequence.
+ /// An async-enumerable sequence to create a dictionary for.
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ /// A comparer to compare keys.
+ /// An equality comparer to compare values.
+ /// The optional cancellation token to be used for cancelling the sequence at any time.
+ /// An async-enumerable sequence containing a single element with a dictionary mapping unique key values onto the corresponding source sequence's element.
+ /// , , or is null.
+ /// The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.
+ public static ValueTask> ToImmutableSortedDictionaryAsync(
+ this IAsyncEnumerable source,
+ Func keySelector, Func elementSelector,
+ IComparer? keyComparer, IEqualityComparer? valueComparer,
+ CancellationToken cancellationToken = default)
+ where TKey : notnull
+ {
+ if (source == null)
+ throw Error.ArgumentNull(nameof(source));
+ if (keySelector == null)
+ throw Error.ArgumentNull(nameof(keySelector));
+ if (elementSelector == null)
+ throw Error.ArgumentNull(nameof(elementSelector));
+
+ return Core(source, keySelector, elementSelector, keyComparer, valueComparer, cancellationToken);
+
+ static async ValueTask> Core(
+ IAsyncEnumerable