Skip to content

Commit efe3af1

Browse files
committed
Merge remote-tracking branch 'origin/develop' into swift4.0
2 parents b34b2ba + 1641fc5 commit efe3af1

File tree

18 files changed

+1903
-38
lines changed

18 files changed

+1903
-38
lines changed

.jazzy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ custom_categories:
7474
- Enumerated
7575
- Error
7676
- Filter
77+
- First
7778
- Generate
7879
- GroupBy
7980
- Just

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file.
55

66
## Master
77

8+
* Adds `materialize()` operator for RxBlocking's `BlockingObservable`. #1383
9+
* Adds `first` operator to ObservableType.
10+
811
## [4.0.0-alpha.1](https://github.com/ReactiveX/RxSwift/releases/tag/4.0.0-alpha.1)
912

1013
* Merge of `3.6.1` changes.

Documentation/UnitTests.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ It's easy to define `RxTests` extensions so you can write your tests in a readab
8686

8787
It is also possible to write integration tests by using `RxBlocking` operators.
8888

89-
Importing operators from `RxBlocking` library will enable blocking the current thread and wait for sequence results.
89+
Using `RxBlocking`'s `toBlocking()` method, you can block the current thread and wait for the sequence to complete, allowing you to synchronously access its result.
90+
91+
A simple way to test the result of your sequence is using the `toArray` method. It will return an array of all elements emitted once a sequence has completed successfully, or `throw` if an error caused the sequence to terminate.
9092

9193
```swift
9294
let result = try fetchResource(location)
@@ -95,3 +97,28 @@ let result = try fetchResource(location)
9597

9698
XCTAssertEqual(result, expectedResult)
9799
```
100+
101+
Another option would be to use the `materialize` operator which lets you more granularly examine your sequence. It will return a `MaterializedSequenceResult` enumeration that could be either `.completed` along with the emitted elements if the sequence completed successfully, or `failed` if the sequence terminated with an error, along with the emitted error.
102+
103+
```swift
104+
let result = try fetchResource(location)
105+
.toBlocking()
106+
.materialize()
107+
108+
// For testing the results or error in the case of terminating with error
109+
switch result {
110+
case .completed:
111+
XCTFail("Expected result to complete with error, but result was successful.")
112+
case .failed(let elements, let error):
113+
XCTAssertEqual(elements, expectedResult)
114+
XCTAssertErrorEqual(error, expectedError)
115+
}
116+
117+
// For testing the results in the case of termination with completion
118+
switch result {
119+
case .completed(let elements):
120+
XCTAssertEqual(elements, expectedResult)
121+
case .failed(_, let error):
122+
XCTFail("Expected result to complete without error, but received \(error).")
123+
}
124+
```

Rx.xcodeproj/project.pbxproj

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959
7F600F411C5D0C6E00535B1D /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F600F3D1C5D0C0100535B1D /* UIRefreshControl+Rx.swift */; };
6060
7FE849471C5D0D6A00845C0E /* UIRefreshControl+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F600F421C5D0D2D00535B1D /* UIRefreshControl+RxTests.swift */; };
6161
7FE849481C5D0D6B00845C0E /* UIRefreshControl+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F600F421C5D0D2D00535B1D /* UIRefreshControl+RxTests.swift */; };
62+
819C2F091F2FBC7F009104B6 /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 819C2F081F2FBC7F009104B6 /* First.swift */; };
63+
819C2F0A1F2FBC88009104B6 /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 819C2F081F2FBC7F009104B6 /* First.swift */; };
64+
819C2F0B1F2FBC88009104B6 /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 819C2F081F2FBC7F009104B6 /* First.swift */; };
65+
819C2F0C1F2FBC89009104B6 /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 819C2F081F2FBC7F009104B6 /* First.swift */; };
6266
842A5A2C1C357F92003568D5 /* NSTextStorage+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842A5A281C357F7D003568D5 /* NSTextStorage+Rx.swift */; };
6367
842A5A2D1C357F93003568D5 /* NSTextStorage+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842A5A281C357F7D003568D5 /* NSTextStorage+Rx.swift */; };
6468
842A5A2E1C357F94003568D5 /* NSTextStorage+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842A5A281C357F7D003568D5 /* NSTextStorage+Rx.swift */; };
@@ -485,10 +489,6 @@
485489
C820A9291EB4DA5A00D431BC /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A8251EB4DA5900D431BC /* CombineLatest+arity.swift */; };
486490
C820A92A1EB4DA5A00D431BC /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A8251EB4DA5900D431BC /* CombineLatest+arity.swift */; };
487491
C820A92B1EB4DA5A00D431BC /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A8251EB4DA5900D431BC /* CombineLatest+arity.swift */; };
488-
C820A92C1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A8261EB4DA5900D431BC /* CombineLatest+arity.tt */; };
489-
C820A92D1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A8261EB4DA5900D431BC /* CombineLatest+arity.tt */; };
490-
C820A92E1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A8261EB4DA5900D431BC /* CombineLatest+arity.tt */; };
491-
C820A92F1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A8261EB4DA5900D431BC /* CombineLatest+arity.tt */; };
492492
C820A9301EB4DA5A00D431BC /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A8271EB4DA5900D431BC /* Producer.swift */; };
493493
C820A9311EB4DA5A00D431BC /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A8271EB4DA5900D431BC /* Producer.swift */; };
494494
C820A9321EB4DA5A00D431BC /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A8271EB4DA5900D431BC /* Producer.swift */; };
@@ -505,10 +505,6 @@
505505
C820A93D1EB4DA5A00D431BC /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A82A1EB4DA5900D431BC /* Zip+arity.swift */; };
506506
C820A93E1EB4DA5A00D431BC /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A82A1EB4DA5900D431BC /* Zip+arity.swift */; };
507507
C820A93F1EB4DA5A00D431BC /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A82A1EB4DA5900D431BC /* Zip+arity.swift */; };
508-
C820A9401EB4DA5A00D431BC /* Zip+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A82B1EB4DA5900D431BC /* Zip+arity.tt */; };
509-
C820A9411EB4DA5A00D431BC /* Zip+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A82B1EB4DA5900D431BC /* Zip+arity.tt */; };
510-
C820A9421EB4DA5A00D431BC /* Zip+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A82B1EB4DA5900D431BC /* Zip+arity.tt */; };
511-
C820A9431EB4DA5A00D431BC /* Zip+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C820A82B1EB4DA5900D431BC /* Zip+arity.tt */; };
512508
C820A9451EB4E06800D431BC /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A9441EB4E06800D431BC /* Deprecated.swift */; };
513509
C820A9461EB4E06800D431BC /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A9441EB4E06800D431BC /* Deprecated.swift */; };
514510
C820A9471EB4E06800D431BC /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C820A9441EB4E06800D431BC /* Deprecated.swift */; };
@@ -993,7 +989,6 @@
993989
C896A68B1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C896A68A1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift */; };
994990
C896A68C1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C896A68A1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift */; };
995991
C896A68D1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C896A68A1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift */; };
996-
C89814761E75A18A0035949C /* PrimitiveSequence+Zip+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C89814751E75A18A0035949C /* PrimitiveSequence+Zip+arity.tt */; };
997992
C89814781E75A7D70035949C /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89814771E75A7D70035949C /* PrimitiveSequence+Zip+arity.swift */; };
998993
C89814791E75A7E70035949C /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89814771E75A7D70035949C /* PrimitiveSequence+Zip+arity.swift */; };
999994
C898147A1E75A7E80035949C /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89814771E75A7D70035949C /* PrimitiveSequence+Zip+arity.swift */; };
@@ -1049,10 +1044,6 @@
10491044
C89AB1EB1DAAC3350065FBE6 /* SharedSequence+Operators+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B61DAAC3350065FBE6 /* SharedSequence+Operators+arity.swift */; };
10501045
C89AB1EC1DAAC3350065FBE6 /* SharedSequence+Operators+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B61DAAC3350065FBE6 /* SharedSequence+Operators+arity.swift */; };
10511046
C89AB1ED1DAAC3350065FBE6 /* SharedSequence+Operators+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B61DAAC3350065FBE6 /* SharedSequence+Operators+arity.swift */; };
1052-
C89AB1EE1DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C89AB1B71DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt */; };
1053-
C89AB1EF1DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C89AB1B71DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt */; };
1054-
C89AB1F01DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C89AB1B71DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt */; };
1055-
C89AB1F11DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */ = {isa = PBXBuildFile; fileRef = C89AB1B71DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt */; };
10561047
C89AB1F21DAAC3350065FBE6 /* SharedSequence+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B81DAAC3350065FBE6 /* SharedSequence+Operators.swift */; };
10571048
C89AB1F31DAAC3350065FBE6 /* SharedSequence+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B81DAAC3350065FBE6 /* SharedSequence+Operators.swift */; };
10581049
C89AB1F41DAAC3350065FBE6 /* SharedSequence+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B81DAAC3350065FBE6 /* SharedSequence+Operators.swift */; };
@@ -1757,6 +1748,7 @@
17571748
7EDBAEB71C89B9B7006CBE67 /* UITabBarItem+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITabBarItem+Rx.swift"; sourceTree = "<group>"; };
17581749
7F600F3D1C5D0C0100535B1D /* UIRefreshControl+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+Rx.swift"; sourceTree = "<group>"; };
17591750
7F600F421C5D0D2D00535B1D /* UIRefreshControl+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+RxTests.swift"; sourceTree = "<group>"; };
1751+
819C2F081F2FBC7F009104B6 /* First.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = First.swift; sourceTree = "<group>"; };
17601752
842A5A281C357F7D003568D5 /* NSTextStorage+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTextStorage+Rx.swift"; sourceTree = "<group>"; };
17611753
844BC8AA1CE4FA5600F5C7CB /* RxPickerViewDelegateProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxPickerViewDelegateProxy.swift; sourceTree = "<group>"; };
17621754
844BC8B31CE4FD7500F5C7CB /* UIPickerView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIPickerView+Rx.swift"; sourceTree = "<group>"; };
@@ -2498,6 +2490,7 @@
24982490
C8E390621F379041004FC993 /* Enumerated.swift */,
24992491
C820A8141EB4DA5900D431BC /* Error.swift */,
25002492
C820A7FB1EB4DA5900D431BC /* Filter.swift */,
2493+
819C2F081F2FBC7F009104B6 /* First.swift */,
25012494
C820A7F31EB4DA5900D431BC /* Generate.swift */,
25022495
C820A7F41EB4DA5900D431BC /* GroupBy.swift */,
25032496
C820A8151EB4DA5900D431BC /* Just.swift */,
@@ -3931,15 +3924,13 @@
39313924
isa = PBXResourcesBuildPhase;
39323925
buildActionMask = 2147483647;
39333926
files = (
3934-
C89AB1EE1DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */,
39353927
);
39363928
runOnlyForDeploymentPostprocessing = 0;
39373929
};
39383930
C80939E21B8A71840088E94D /* Resources */ = {
39393931
isa = PBXResourcesBuildPhase;
39403932
buildActionMask = 2147483647;
39413933
files = (
3942-
C89AB1EF1DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */,
39433934
);
39443935
runOnlyForDeploymentPostprocessing = 0;
39453936
};
@@ -3989,8 +3980,6 @@
39893980
isa = PBXResourcesBuildPhase;
39903981
buildActionMask = 2147483647;
39913982
files = (
3992-
C820A92D1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */,
3993-
C820A9411EB4DA5A00D431BC /* Zip+arity.tt in Resources */,
39943983
);
39953984
runOnlyForDeploymentPostprocessing = 0;
39963985
};
@@ -4026,9 +4015,6 @@
40264015
isa = PBXResourcesBuildPhase;
40274016
buildActionMask = 2147483647;
40284017
files = (
4029-
C820A92C1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */,
4030-
C820A9401EB4DA5A00D431BC /* Zip+arity.tt in Resources */,
4031-
C89814761E75A18A0035949C /* PrimitiveSequence+Zip+arity.tt in Resources */,
40324018
);
40334019
runOnlyForDeploymentPostprocessing = 0;
40344020
};
@@ -4043,16 +4029,13 @@
40434029
isa = PBXResourcesBuildPhase;
40444030
buildActionMask = 2147483647;
40454031
files = (
4046-
C820A92F1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */,
4047-
C820A9431EB4DA5A00D431BC /* Zip+arity.tt in Resources */,
40484032
);
40494033
runOnlyForDeploymentPostprocessing = 0;
40504034
};
40514035
C8F0C0461BBBFBB9001B112F /* Resources */ = {
40524036
isa = PBXResourcesBuildPhase;
40534037
buildActionMask = 2147483647;
40544038
files = (
4055-
C89AB1F11DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */,
40564039
);
40574040
runOnlyForDeploymentPostprocessing = 0;
40584041
};
@@ -4067,16 +4050,13 @@
40674050
isa = PBXResourcesBuildPhase;
40684051
buildActionMask = 2147483647;
40694052
files = (
4070-
C89AB1F01DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt in Resources */,
40714053
);
40724054
runOnlyForDeploymentPostprocessing = 0;
40734055
};
40744056
D2EA280A1BB9B5A200880ED3 /* Resources */ = {
40754057
isa = PBXResourcesBuildPhase;
40764058
buildActionMask = 2147483647;
40774059
files = (
4078-
C820A92E1EB4DA5A00D431BC /* CombineLatest+arity.tt in Resources */,
4079-
C820A9421EB4DA5A00D431BC /* Zip+arity.tt in Resources */,
40804060
);
40814061
runOnlyForDeploymentPostprocessing = 0;
40824062
};
@@ -4793,6 +4773,7 @@
47934773
C820A8B91EB4DA5A00D431BC /* Concat.swift in Sources */,
47944774
C820A8311EB4DA5900D431BC /* Switch.swift in Sources */,
47954775
601AE3DB1EE24E5A00617386 /* SwiftSupport.swift in Sources */,
4776+
819C2F0A1F2FBC88009104B6 /* First.swift in Sources */,
47964777
C820A8B51EB4DA5A00D431BC /* TakeUntil.swift in Sources */,
47974778
C80EEC351D42D06E00131C39 /* DispatchQueueConfiguration.swift in Sources */,
47984779
C820A8851EB4DA5A00D431BC /* Dematerialize.swift in Sources */,
@@ -5032,6 +5013,7 @@
50325013
C820A8B81EB4DA5A00D431BC /* Concat.swift in Sources */,
50335014
C820A8301EB4DA5900D431BC /* Switch.swift in Sources */,
50345015
601AE3DA1EE24E4F00617386 /* SwiftSupport.swift in Sources */,
5016+
819C2F091F2FBC7F009104B6 /* First.swift in Sources */,
50355017
C820A8B41EB4DA5A00D431BC /* TakeUntil.swift in Sources */,
50365018
C80EEC341D42D06E00131C39 /* DispatchQueueConfiguration.swift in Sources */,
50375019
C820A8841EB4DA5A00D431BC /* Dematerialize.swift in Sources */,
@@ -5195,6 +5177,7 @@
51955177
C820A8BB1EB4DA5A00D431BC /* Concat.swift in Sources */,
51965178
C820A8331EB4DA5900D431BC /* Switch.swift in Sources */,
51975179
601AE3DD1EE24E5B00617386 /* SwiftSupport.swift in Sources */,
5180+
819C2F0B1F2FBC88009104B6 /* First.swift in Sources */,
51985181
C820A8B71EB4DA5A00D431BC /* TakeUntil.swift in Sources */,
51995182
C80EEC371D42D06E00131C39 /* DispatchQueueConfiguration.swift in Sources */,
52005183
C820A8871EB4DA5A00D431BC /* Dematerialize.swift in Sources */,
@@ -5566,6 +5549,7 @@
55665549
C820A8BA1EB4DA5A00D431BC /* Concat.swift in Sources */,
55675550
C820A8321EB4DA5900D431BC /* Switch.swift in Sources */,
55685551
601AE3DC1EE24E5B00617386 /* SwiftSupport.swift in Sources */,
5552+
819C2F0C1F2FBC89009104B6 /* First.swift in Sources */,
55695553
C820A8B61EB4DA5A00D431BC /* TakeUntil.swift in Sources */,
55705554
D2EBEAE11BB9B697003A27DC /* ImmediateSchedulerType.swift in Sources */,
55715555
C820A8861EB4DA5A00D431BC /* Dematerialize.swift in Sources */,

RxBlocking/BlockingObservable+Operators.swift

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,28 @@
1010
import RxSwift
1111
#endif
1212

13+
/// The `MaterializedSequenceResult` enum represents the materialized
14+
/// output of a BlockingObservable.
15+
///
16+
/// If the sequence terminates successfully, the result is represented
17+
/// by `.completed` with the array of elements.
18+
///
19+
/// If the sequence terminates with error, the result is represented
20+
/// by `.failed` with both the array of elements and the terminating error.
21+
public enum MaterializedSequenceResult<T> {
22+
case completed(elements: [T])
23+
case failed(elements: [T], error: Error)
24+
}
25+
1326
extension BlockingObservable {
1427
/// Blocks current thread until sequence terminates.
1528
///
1629
/// If sequence terminates with error, terminating error will be thrown.
1730
///
1831
/// - returns: All elements of sequence.
1932
public func toArray() throws -> [E] {
20-
return try convertToArray()
33+
let results = materializeResult()
34+
return try elementsOrThrow(results)
2135
}
2236
}
2337

@@ -28,7 +42,8 @@ extension BlockingObservable {
2842
///
2943
/// - returns: First element of sequence. If sequence is empty `nil` is returned.
3044
public func first() throws -> E? {
31-
return try convertToArray(max: 1).first
45+
let results = materializeResult(max: 1)
46+
return try elementsOrThrow(results).first
3247
}
3348
}
3449

@@ -39,7 +54,8 @@ extension BlockingObservable {
3954
///
4055
/// - returns: Last element in the sequence. If sequence is empty `nil` is returned.
4156
public func last() throws -> E? {
42-
return try convertToArray().last
57+
let results = materializeResult()
58+
return try elementsOrThrow(results).last
4359
}
4460
}
4561

@@ -60,7 +76,8 @@ extension BlockingObservable {
6076
/// - parameter predicate: A function to test each source element for a condition.
6177
/// - 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.
6278
public func single(_ predicate: @escaping (E) throws -> Bool) throws -> E? {
63-
let elements = try convertToArray(max: 2, predicate: predicate)
79+
let results = materializeResult(max: 2, predicate: predicate)
80+
let elements = try elementsOrThrow(results)
6481

6582
switch elements.count {
6683
case 0:
@@ -74,9 +91,19 @@ extension BlockingObservable {
7491
}
7592

7693
extension BlockingObservable {
77-
fileprivate func convertToArray(max: Int? = nil, predicate: @escaping (E) throws -> Bool = { _ in true }) throws -> [E] {
94+
/// Blocks current thread until sequence terminates.
95+
///
96+
/// The sequence is materialized as a result type capturing how the sequence terminated (completed or error), along with any elements up to that point.
97+
///
98+
/// - 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.
99+
public func materialize() -> MaterializedSequenceResult<E> {
100+
return materializeResult()
101+
}
102+
}
103+
104+
extension BlockingObservable {
105+
fileprivate func materializeResult(max: Int? = nil, predicate: @escaping (E) throws -> Bool = { _ in true }) -> MaterializedSequenceResult<E> {
78106
var elements: [E] = Array<E>()
79-
80107
var error: Swift.Error?
81108

82109
let lock = RunLoopLock(timeout: timeout)
@@ -127,9 +154,18 @@ extension BlockingObservable {
127154
}
128155

129156
if let error = error {
130-
throw error
157+
return MaterializedSequenceResult.failed(elements: elements, error: error)
131158
}
132159

133-
return elements
160+
return MaterializedSequenceResult.completed(elements: elements)
161+
}
162+
163+
fileprivate func elementsOrThrow(_ results: MaterializedSequenceResult<E>) throws -> [E] {
164+
switch results {
165+
case .failed(_, let error):
166+
throw error
167+
case .completed(let elements):
168+
return elements
169+
}
134170
}
135171
}

0 commit comments

Comments
 (0)