Last active
May 13, 2021 16:04
-
-
Save tadija/8c307aa9a0590ab946c0715ebe8a50b2 to your computer and use it in GitHub Desktop.
AECombine
This file contains 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
/** | |
* https://gist.github.com/tadija/8c307aa9a0590ab946c0715ebe8a50b2 | |
* Revision 2 | |
* Copyright © 2021 Marko Tadić | |
* Licensed under the MIT license | |
*/ | |
import Foundation | |
import Combine | |
public extension Publisher { | |
func sink() -> AnyCancellable { | |
self.sink( | |
receiveCompletion: { _ in }, | |
receiveValue: { _ in } | |
) | |
} | |
} | |
public extension Publisher { | |
func mapToVoid() -> AnyPublisher<Void, Self.Failure> { | |
self.map { _ in () } | |
.eraseToAnyPublisher() | |
} | |
} | |
public extension Subscribers.Completion { | |
func mapToResult() -> Result<Void, Error> { | |
switch self { | |
case .finished: | |
return .success(()) | |
case .failure(let error): | |
return .failure(error) | |
} | |
} | |
} | |
/// - See: https://www.swiftbysundell.com/articles/combine-self-cancellable-memory-management | |
public extension Publisher where Failure == Never { | |
func weakAssign<T: AnyObject>( | |
to keyPath: ReferenceWritableKeyPath<T, Output>, | |
on object: T | |
) -> AnyCancellable { | |
sink { [weak object] value in | |
object?[keyPath: keyPath] = value | |
} | |
} | |
} | |
/// - See: https://www.swiftbysundell.com/articles/connecting-and-merging-combine-publishers-in-swift | |
public extension Publisher where Output: Sequence { | |
typealias Sorter = (Output.Element, Output.Element) -> Bool | |
func sort( | |
by sorter: @escaping Sorter | |
) -> Publishers.Map<Self, [Output.Element]> { | |
map { sequence in | |
sequence.sorted(by: sorter) | |
} | |
} | |
} | |
/// - See: https://www.swiftbysundell.com/articles/extending-combine-with-convenience-apis | |
public extension Publisher where Output == Data { | |
func decode<T: Decodable>( | |
as type: T.Type = T.self, | |
using decoder: JSONDecoder = .init() | |
) -> Publishers.Decode<Self, T, JSONDecoder> { | |
decode(type: type, decoder: decoder) | |
} | |
} | |
public extension Publisher where Output: Encodable { | |
func encode( | |
using encoder: JSONEncoder = .init() | |
) -> Publishers.Encode<Self, JSONEncoder> { | |
encode(encoder: encoder) | |
} | |
} | |
public extension Publisher { | |
func validate( | |
using validator: @escaping (Output) throws -> Void | |
) -> Publishers.TryMap<Self, Output> { | |
tryMap { output in | |
try validator(output) | |
return output | |
} | |
} | |
} | |
public extension Publisher { | |
func unwrap<T>( | |
orThrow error: @escaping @autoclosure () -> Failure | |
) -> Publishers.TryMap<Self, T> where Output == Optional<T> { | |
tryMap { output in | |
switch output { | |
case .some(let value): | |
return value | |
case nil: | |
throw error() | |
} | |
} | |
} | |
} | |
public extension Publisher { | |
func convertToResult() -> AnyPublisher<Result<Output, Failure>, Never> { | |
self.map(Result.success) | |
.catch { Just(.failure($0)) } | |
.eraseToAnyPublisher() | |
} | |
} | |
public extension AnyPublisher { | |
static func just(_ output: Output) -> Self { | |
Just(output) | |
.setFailureType(to: Failure.self) | |
.eraseToAnyPublisher() | |
} | |
static func fail(with error: Failure) -> Self { | |
Fail(error: error).eraseToAnyPublisher() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment