-
Notifications
You must be signed in to change notification settings - Fork 187
Add async rethrowing initializers for RangeReplaceableCollection, SetAlgebra, and Dictionary for use with AsyncSequence types #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
61a30e6
Add async rethrowing initializers for RangeReplaceableCollection, Set…
phausler 5ee2e94
Add some additional tests for throwing coverage and documentation on …
phausler 36d9c60
Spelling fix of unique
phausler 81c2c95
Spelling fix for unique (throwing version)
phausler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift Async Algorithms open source project | ||
| // | ||
| // Copyright (c) 2021 Apple Inc. and the Swift project authors | ||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||
| // | ||
| // See https://swift.org/LICENSE.txt for license information | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| extension Dictionary { | ||
| /// Creates a new dictionary from the key-value pairs in the given asynchronous sequence. | ||
| /// | ||
| /// You use this initializer to create a dictionary when you have an asynchronous sequence | ||
| /// of key-value tuples with unique keys. Passing an asynchronous sequence with duplicate | ||
| /// keys to this initializer results in a runtime error. If your | ||
| /// asynchronous sequence might have duplicate keys, use the | ||
| /// `Dictionary(_:uniquingKeysWith:)` initializer instead. | ||
| /// | ||
| /// - Parameter keysAndValues: An asynchronous sequence of key-value pairs to use for | ||
| /// the new dictionary. Every key in `keysAndValues` must be unique. | ||
| /// - Returns: A new dictionary initialized with the elements of | ||
| /// `keysAndValues`. | ||
| /// - Precondition: The sequence must not have duplicate keys. | ||
| @inlinable | ||
| public init<S: AsyncSequence>(uniqueKeysWithValues keysAndValues: S) async rethrows where S.Element == (Key, Value) { | ||
| self.init(uniqueKeysWithValues: try await Array(keysAndValues)) | ||
| } | ||
|
|
||
| /// Creates a new dictionary from the key-value pairs in the given asynchronous sequence, | ||
| /// using a combining closure to determine the value for any duplicate keys. | ||
| /// | ||
| /// You use this initializer to create a dictionary when you have a sequence | ||
| /// of key-value tuples that might have duplicate keys. As the dictionary is | ||
| /// built, the initializer calls the `combine` closure with the current and | ||
| /// new values for any duplicate keys. Pass a closure as `combine` that | ||
| /// returns the value to use in the resulting dictionary: The closure can | ||
| /// choose between the two values, combine them to produce a new value, or | ||
| /// even throw an error. | ||
| /// | ||
| /// - Parameters: | ||
| /// - keysAndValues: An asynchronous sequence of key-value pairs to use for the new | ||
| /// dictionary. | ||
| /// - combine: A closure that is called with the values for any duplicate | ||
| /// keys that are encountered. The closure returns the desired value for | ||
| /// the final dictionary. | ||
| @inlinable | ||
| public init<S: AsyncSequence>(_ keysAndValues: S, uniquingKeysWith combine: (Value, Value) async throws -> Value) async rethrows where S.Element == (Key, Value) { | ||
| self.init() | ||
| for try await (key, value) in keysAndValues { | ||
| if let existing = self[key] { | ||
| self[key] = try await combine(existing, value) | ||
| } else { | ||
| self[key] = value | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Creates a new dictionary whose keys are the groupings returned by the | ||
| /// given closure and whose values are arrays of the elements that returned | ||
| /// each key. | ||
| /// | ||
| /// The arrays in the "values" position of the new dictionary each contain at | ||
| /// least one element, with the elements in the same order as the source | ||
| /// asynchronous sequence. | ||
| /// | ||
| /// - Parameters: | ||
| /// - values: An asynchronous sequence of values to group into a dictionary. | ||
| /// - keyForValue: A closure that returns a key for each element in | ||
| /// `values`. | ||
| @inlinable | ||
| public init<S: AsyncSequence>(grouping values: S, by keyForValue: (S.Element) async throws -> Key) async rethrows where Value == [S.Element] { | ||
| self.init() | ||
| for try await value in values { | ||
| let key = try await keyForValue(value) | ||
| self[key, default: []].append(value) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift Async Algorithms open source project | ||
| // | ||
| // Copyright (c) 2021 Apple Inc. and the Swift project authors | ||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||
| // | ||
| // See https://swift.org/LICENSE.txt for license information | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| extension RangeReplaceableCollection { | ||
| /// Creates a new instance of a collection containing the elements of an asynchronous sequence. | ||
| /// | ||
| /// - Parameter surce: The asynchronous sequence of elements for the new collection. | ||
| @inlinable | ||
| public init<Source: AsyncSequence>(_ source: Source) async rethrows where Source.Element == Element { | ||
| self.init() | ||
| for try await item in source { | ||
| append(item) | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift Async Algorithms open source project | ||
| // | ||
| // Copyright (c) 2021 Apple Inc. and the Swift project authors | ||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||
| // | ||
| // See https://swift.org/LICENSE.txt for license information | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| extension SetAlgebra { | ||
| /// Creates a new set from an asynchronous sequence of items. | ||
| /// | ||
| /// Use this initializer to create a new set from an asynchronous sequence | ||
| /// | ||
| /// - Parameter source: The elements to use as members of the new set. | ||
| @inlinable | ||
| public init<Source: AsyncSequence>(_ source: Source) async rethrows where Source.Element == Element { | ||
| self.init() | ||
| for try await item in source { | ||
| insert(item) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift Async Algorithms open source project | ||
| // | ||
| // Copyright (c) 2021 Apple Inc. and the Swift project authors | ||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||
| // | ||
| // See https://swift.org/LICENSE.txt for license information | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import XCTest | ||
| import AsyncAlgorithms | ||
|
|
||
| final class TestDictionary: XCTestCase { | ||
| func test_uniqueKeysAndValues() async { | ||
| let source = [(1, "a"), (2, "b"), (3, "c")] | ||
| let expected = Dictionary(uniqueKeysWithValues: source) | ||
| let actual = await Dictionary(uniqueKeysWithValues: source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_throwing_uniqueKeysAndValues() async { | ||
| let source = Array([1, 2, 3, 4, 5, 6]) | ||
| let input = source.async.map { (value: Int) async throws -> (Int, Int) in | ||
| if value == 4 { throw NSError(domain: NSCocoaErrorDomain, code: -1, userInfo: nil) } | ||
| return (value, value) | ||
| } | ||
| do { | ||
| _ = try await Dictionary(uniqueKeysWithValues: input) | ||
| XCTFail() | ||
| } catch { | ||
| XCTAssertEqual((error as NSError).code, -1) | ||
| } | ||
| } | ||
|
|
||
| func test_uniquingWith() async { | ||
| let source = [("a", 1), ("b", 2), ("a", 3), ("b", 4)] | ||
| let expected = Dictionary(source) { first, _ in first } | ||
| let actual = await Dictionary(source.async) { first, _ in first } | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_throwing_uniquingWith() async { | ||
| let source = Array([1, 2, 3, 4, 5, 6]) | ||
| let input = source.async.map { (value: Int) async throws -> (Int, Int) in | ||
| if value == 4 { throw NSError(domain: NSCocoaErrorDomain, code: -1, userInfo: nil) } | ||
| return (value, value) | ||
| } | ||
| do { | ||
| _ = try await Dictionary(input) { first, _ in first } | ||
| XCTFail() | ||
| } catch { | ||
| XCTAssertEqual((error as NSError).code, -1) | ||
| } | ||
| } | ||
|
|
||
| func test_grouping() async { | ||
| let source = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"] | ||
| let expected = Dictionary(grouping: source, by: { $0.first! }) | ||
| let actual = await Dictionary(grouping: source.async, by: { $0.first! }) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_throwing_grouping() async { | ||
| let source = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"] | ||
| let input = source.async.map { (value: String) async throws -> String in | ||
| if value == "Kweku" { throw NSError(domain: NSCocoaErrorDomain, code: -1, userInfo: nil) } | ||
| return value | ||
| } | ||
| do { | ||
| _ = try await Dictionary(grouping: input, by: { $0.first! }) | ||
| XCTFail() | ||
| } catch { | ||
| XCTAssertEqual((error as NSError).code, -1) | ||
| } | ||
| } | ||
| } |
57 changes: 57 additions & 0 deletions
57
Tests/AsyncAlgorithmsTests/TestRangeReplacableCollection.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift Async Algorithms open source project | ||
| // | ||
| // Copyright (c) 2021 Apple Inc. and the Swift project authors | ||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||
| // | ||
| // See https://swift.org/LICENSE.txt for license information | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import XCTest | ||
| import AsyncAlgorithms | ||
|
|
||
| final class TestRangeReplacableCollection: XCTestCase { | ||
| func test_String() async { | ||
| let source = "abc" | ||
| let expected = source | ||
| let actual = await String(source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_Data() async { | ||
| let source = Data([1, 2, 3]) | ||
| let expected = source | ||
| let actual = await Data(source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_ContiguousArray() async { | ||
| let source = ContiguousArray([1, 2, 3]) | ||
| let expected = source | ||
| let actual = await ContiguousArray(source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_Array() async { | ||
| let source = Array([1, 2, 3]) | ||
| let expected = source | ||
| let actual = await Array(source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_throwing() async { | ||
| let source = Array([1, 2, 3, 4, 5, 6]) | ||
| let input = source.async.map { (value: Int) async throws -> Int in | ||
| if value == 4 { throw NSError(domain: NSCocoaErrorDomain, code: -1, userInfo: nil) } | ||
| return value | ||
| } | ||
| do { | ||
| _ = try await Array(input) | ||
| XCTFail() | ||
| } catch { | ||
| XCTAssertEqual((error as NSError).code, -1) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift Async Algorithms open source project | ||
| // | ||
| // Copyright (c) 2021 Apple Inc. and the Swift project authors | ||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||
| // | ||
| // See https://swift.org/LICENSE.txt for license information | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import XCTest | ||
| import AsyncAlgorithms | ||
|
|
||
| final class TestSetAlgebra: XCTestCase { | ||
| func test_Set() async { | ||
| let source = [1, 2, 3] | ||
| let expected = Set(source) | ||
| let actual = await Set(source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_Set_duplicate() async { | ||
| let source = [1, 2, 3, 3] | ||
| let expected = Set(source) | ||
| let actual = await Set(source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_IndexSet() async { | ||
| let source = [1, 2, 3] | ||
| let expected = IndexSet(source) | ||
| let actual = await IndexSet(source.async) | ||
| XCTAssertEqual(expected, actual) | ||
| } | ||
|
|
||
| func test_throwing() async { | ||
| let source = Array([1, 2, 3, 4, 5, 6]) | ||
| let input = source.async.map { (value: Int) async throws -> Int in | ||
| if value == 4 { throw NSError(domain: NSCocoaErrorDomain, code: -1, userInfo: nil) } | ||
| return value | ||
| } | ||
| do { | ||
| _ = try await Set(input) | ||
| XCTFail() | ||
| } catch { | ||
| XCTAssertEqual((error as NSError).code, -1) | ||
| } | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AsyncSequencedoesn't have any notion ofunderestimatedCount, does it?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope;
AsyncSequenceis about 50/50 finite/indefinite so that was decided to be skipped during the initial design.