-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
New materialize() operator over BlockingObservable
#1383
Changes from 7 commits
9a04baf
cdebf0b
a04fe8b
58acfae
6848692
326f902
75b0e39
4cd73a6
d416ff5
0f7a1ce
1086b4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,14 +10,20 @@ | |
import RxSwift | ||
#endif | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should document this, what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually added this in the documentation: https://github.com/ReactiveX/RxSwift/pull/1383/files/d416ff5e5c4f461c8afe262824f7d34f73d06e81#diff-6eb6c44aac5cc628cd1c254752e52e36R101 Did you want to see something besides that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or your mean inline documentation block for that enum ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've tweaked the Although if you mean inline docs like @freak4pc mentioned, I can add that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I looked through other parts of the RxSwift codebase and thought an inline comment describing the |
||
public enum MaterializedSequenceResult<T> { | ||
case completed(elements: [T]) | ||
case failed(elements: [T], error: Error) | ||
} | ||
|
||
extension BlockingObservable { | ||
/// Blocks current thread until sequence terminates. | ||
/// | ||
/// If sequence terminates with error, terminating error will be thrown. | ||
/// | ||
/// - returns: All elements of sequence. | ||
public func toArray() throws -> [E] { | ||
return try convertToArray() | ||
let results = materializeResult() | ||
return try elementsOrThrow(results) | ||
} | ||
} | ||
|
||
|
@@ -28,7 +34,8 @@ extension BlockingObservable { | |
/// | ||
/// - returns: First element of sequence. If sequence is empty `nil` is returned. | ||
public func first() throws -> E? { | ||
return try convertToArray(max: 1).first | ||
let results = materializeResult(max: 1) | ||
return try elementsOrThrow(results).first | ||
} | ||
} | ||
|
||
|
@@ -39,7 +46,8 @@ extension BlockingObservable { | |
/// | ||
/// - returns: Last element in the sequence. If sequence is empty `nil` is returned. | ||
public func last() throws -> E? { | ||
return try convertToArray().last | ||
let results = materializeResult() | ||
return try elementsOrThrow(results).last | ||
} | ||
} | ||
|
||
|
@@ -60,7 +68,8 @@ extension BlockingObservable { | |
/// - parameter predicate: A function to test each source element for a condition. | ||
/// - returns: Returns the only element of an sequence that satisfies the condition in the predicate, and reports an error if there is not exactly one element in the sequence. | ||
public func single(_ predicate: @escaping (E) throws -> Bool) throws -> E? { | ||
let elements = try convertToArray(max: 2, predicate: predicate) | ||
let results = materializeResult(max: 2, predicate: predicate) | ||
let elements = try elementsOrThrow(results) | ||
|
||
switch elements.count { | ||
case 0: | ||
|
@@ -74,9 +83,19 @@ extension BlockingObservable { | |
} | ||
|
||
extension BlockingObservable { | ||
fileprivate func convertToArray(max: Int? = nil, predicate: @escaping (E) throws -> Bool = { _ in true }) throws -> [E] { | ||
/// Blocks current thread until sequence terminates. | ||
/// | ||
/// The sequence is materialized as a result type capturing how the sequence terminated (completed or error), along with any elements up to that point. | ||
/// | ||
/// - returns: On completion, returns the list of elements in the sequence. On error, returns the list of elements up to that point, along with the error itself. | ||
public func materialize() -> MaterializedSequenceResult<E> { | ||
return materializeResult() | ||
} | ||
} | ||
|
||
extension BlockingObservable { | ||
fileprivate func materializeResult(max: Int? = nil, predicate: @escaping (E) throws -> Bool = { _ in true }) -> MaterializedSequenceResult<E> { | ||
var elements: [E] = Array<E>() | ||
|
||
var error: Swift.Error? | ||
|
||
let lock = RunLoopLock(timeout: timeout) | ||
|
@@ -127,9 +146,18 @@ extension BlockingObservable { | |
} | ||
|
||
if let error = error { | ||
throw error | ||
return MaterializedSequenceResult.failed(elements: elements, error: error) | ||
} | ||
|
||
return elements | ||
return MaterializedSequenceResult.completed(elements: elements) | ||
} | ||
|
||
fileprivate func elementsOrThrow(_ results: MaterializedSequenceResult<E>) throws -> [E] { | ||
switch results { | ||
case .failed(_, let error): | ||
throw error | ||
case .completed(let elements): | ||
return elements | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -337,3 +337,54 @@ extension ObservableBlockingTest { | |
} | ||
} | ||
} | ||
|
||
// materialize | ||
|
||
extension ObservableBlockingTest { | ||
func testMaterialize_empty() { | ||
let result = Observable<Int>.empty().toBlocking().materialize() | ||
|
||
switch result { | ||
case .completed(let elements): | ||
XCTAssertEqual(elements, []) | ||
case .failed: | ||
XCTFail("Expected result to be complete successfully, but result was failed.") | ||
} | ||
} | ||
|
||
func testMaterialize_empty_fail() { | ||
let result = Observable<Int>.error(testError).toBlocking().materialize() | ||
|
||
switch result { | ||
case .completed: | ||
XCTFail("Expected result to be complete eith error, but result was successful.") | ||
case .failed(let elements, let error): | ||
XCTAssertEqual(elements, []) | ||
XCTAssertErrorEqual(error, testError) | ||
} | ||
} | ||
|
||
func testMaterialize_someData() { | ||
let result = Observable.of(42, 43, 44, 45).toBlocking().materialize() | ||
|
||
switch result { | ||
case .completed(let elements): | ||
XCTAssertEqual(elements, [42, 43, 44, 45]) | ||
case .failed: | ||
XCTFail("Expected result to be complete successfully, but result was failed.") | ||
} | ||
} | ||
|
||
func testMaterialize_someData_fail() { | ||
let sequence = Observable.concat(Observable.of(42, 43, 44, 45), Observable<Int>.error(testError)) | ||
let result = sequence.toBlocking().materialize() | ||
|
||
switch result { | ||
case .completed: | ||
XCTFail("Expected result to be complete eith error, but result was successful.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo |
||
case .failed(let elements, let error): | ||
XCTAssertEqual(elements, [42, 43, 44, 45]) | ||
XCTAssertErrorEqual(error, testError) | ||
} | ||
} | ||
} |
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.
eith
->with
?