Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,37 @@ subscription = ints
.finished
```

### liftErrorFromResult

Transforms a publisher of type `AnyPublisher<Result<T, E>, Never>` to `AnyPublisher<T, E>`

```swift
enum AnError: Error {
case someError
}

let subject = PassthroughSubject<Result<Int, AnError>, Never>()

let subscription = subject
.liftErrorFromResult()
.sink(receiveCompletion: { print("completion: \($0)") },
receiveValue: { print("value: \($0)") })

subject.send(.success(1))
subject.send(.success(2))
subject.send(.success(3))
subject.send(.failure(.someError))
```

#### Output

```none
value: 1
value: 2
value: 3
completion: failure(AnError.someError)
```

## Publishers

This section outlines some of the custom Combine publishers CombineExt provides
Expand Down
34 changes: 34 additions & 0 deletions Sources/Operators/LiftErrorFromResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// LiftErrorFromResult.swift
// CombineExt
//
// Created by Yurii Zadoianchuk on 12/03/2021.
// Copyright © 2021 Combine Community. All rights reserved.
//

#if canImport(Combine)
import Combine

@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public extension Publisher where Self.Failure == Never {
/// Transform a never-failing publisher with Result<T, E> as output
/// to a new publisher that unwraps Result and sets T as Output and E as Failure
/// - Returns: a type-erased publisher of type <T, E>
func liftErrorFromResult<T, E>() -> AnyPublisher<T, E>
where Output == Result<T, E> {
setFailureType(to: E.self)
.flatMap { (result: Result<T, E>) -> AnyPublisher<T, E> in
switch result {
case .success(let some):
return Just(some)
.setFailureType(to: E.self)
.eraseToAnyPublisher()
case .failure(let error):
return Fail(error: error)
.eraseToAnyPublisher()
}
}.eraseToAnyPublisher()
}
}

#endif
79 changes: 79 additions & 0 deletions Tests/LiftErrorFromResultTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// LiftErrorFromResultTests.swift
// CombineExtTests
//
// Created by Yurii Zadoianchuk on 12/03/2021.
// Copyright © 2021 Combine Community. All rights reserved.
//

#if !os(watchOS)
import XCTest
import Combine
import CombineExt

@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
class LiftErrorFromResultTests: XCTestCase {
var subscription: AnyCancellable!

enum LiftErrorFromResultError: Error {
case someError
}

func testLiftNoError() {
let subject = PassthroughSubject<Result<Int, LiftErrorFromResultError>, Never>()
let testInt = 5
var completion: Subscribers.Completion<LiftErrorFromResultError>? = nil
var result: Int? = nil

subscription = subject
.liftErrorFromResult()
.sink(receiveCompletion: { completion = $0 },
receiveValue: { result = $0 })

subject.send(.success(testInt))
XCTAssertNotNil(result)
XCTAssertEqual(result!, testInt)
XCTAssertNil(completion)
}

func testLiftError() {
let subject = PassthroughSubject<Result<Int, LiftErrorFromResultError>, Never>()
let testError = LiftErrorFromResultError.someError
var completion: Subscribers.Completion<LiftErrorFromResultError>? = nil
var result: Int? = nil

subscription = subject
.liftErrorFromResult()
.sink(receiveCompletion: { completion = $0 },
receiveValue: { result = $0 })

subject.send(.failure(testError))
XCTAssertNil(result)
XCTAssertNotNil(completion)
XCTAssert(completion! == .failure(testError))
}

func testLiftErrorMultipleResults() {
let subject = PassthroughSubject<Result<Int, LiftErrorFromResultError>, Never>()
let testInts = [5, 6, 7]
let testError = LiftErrorFromResultError.someError
var completions: [Subscribers.Completion<LiftErrorFromResultError>] = []
var results: [Int] = []

subscription = subject
.liftErrorFromResult()
.sink(receiveCompletion: { completions.append($0) },
receiveValue: { results.append($0) })

subject.send(.success(testInts[0]))
subject.send(.success(testInts[1]))
subject.send(.success(testInts[2]))
subject.send(.failure(testError))

XCTAssertEqual(testInts, results)
XCTAssertEqual(completions.count, 1)
XCTAssertEqual(completions.first!, .failure(testError))
}
}

#endif