Skip to content

Instantly share code, notes, and snippets.

View swhitty's full-sized avatar

Simon Whitty swhitty

View GitHub Profile
import Combine
import RxSwift
import Foundation
extension ObservableType {
var publisher: RxPublisher<Self> {
RxPublisher(self)
}
}
import Foundation
/// @Awaiting wraps optional properties and projects an async function that waits
/// when `wrappedValue` is nil, until some value is set.
///
/// Throws `CancellationError` when task is cancelled.
///
/// ```
/// @Awaiting var name: String?
/// ...
extension Deferred {
init<T>(operation: @escaping @Sendable () async -> T) where DeferredPublisher == AsyncDeferredPublisher<T, Never> {
self.init { AsyncDeferredPublisher(operation: operation) }
}
init<T>(operation: @escaping @Sendable () async throws -> T) where DeferredPublisher == AsyncDeferredPublisher<T, Error> {
self.init { AsyncDeferredPublisher(operation: operation) }
}
}
extension Task where Failure == Error {
// Start a new Task with a timeout. If the timeout expires before the operation is
// completed then the task is cancelled and an error is thrown.
init(priority: TaskPriority? = nil, timeout: TimeInterval, operation: @escaping @Sendable () async throws -> Success) {
self = Task(priority: priority) {
try await withThrowingTaskGroup(of: Success.self) { group -> Success in
group.addTask(operation: operation)
group.addTask {
try await _Concurrency.Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000))
import Combine
extension Publisher {
/// Converts publisher to AsyncSequence.
@available(iOS, deprecated: 15.0, message: "Use publisher.values directly")
var valuesAsync: AsyncThrowingPublisher<Self> {
AsyncThrowingPublisher(self)
}
}
import Combine
extension Publisher where Failure == Never {
/// Converts publisher to AsyncSequence
@available(iOS, deprecated: 15.0, message: "Use publisher.values directly")
var valuesAsync: AsyncPublisher<Self> {
AsyncPublisher(self)
}
}
extension NSAttributedString {
/// Iterates over all embedded `UIImage` instances within the string, updating the configuration
/// to include the provided `UITraitCollection`.
///
func updatingImageAttachments(to traitCollection: UITraitCollection) -> NSAttributedString {
var updatedImages = [(Int, UIImage)]()
enumerateAttributes(in: NSRange(location: 0, length: length), options: .init(rawValue: 0)) { attributes, range, _ in
if let attachment = attributes[.attachment] as? NSTextAttachment,
let image = attachment.image ?? attachment.image(forBounds: .zero, textContainer: nil, characterIndex: 0),
@swhitty
swhitty / AnyPub.swift
Last active September 17, 2021 23:43
// Publisher type erasure that uses SE-0309 + unsafebitcast instead of the subclass approach of AnyPublisher.
// https://github.com/apple/swift-evolution/blob/main/proposals/0309-unlock-existential-types-for-all-protocols.md
// Available in latest toolchains on swift.org
// OpenCombine.AnyPublisher
// https://github.com/OpenCombine/OpenCombine/blob/master/Sources/OpenCombine/AnyPublisher.swift
extension Publisher {
func eraseToAnyPub() -> AnyPub<Output, Failure> {
AnyPub(self)
// Combine.Publishers.ReceiveOn is seriously broken on iOS 13.0–2
// https://forums.swift.org/t/combine-receive-on-runloop-main-loses-sent-value-how-can-i-make-it-work/28631
// Provides fix by using OpenCombine version on iOS 13.0–2 and Combine version for iOS 13.3+
import Combine
import Foundation
@available(iOS, deprecated: 13.3, message: "use receive(on:)")
public extension Publisher {
import Combine
extension Publisher {
/// Binds a publisher to a subscriber with a resulting cancellable
func bind<S: Subscriber>(to subscriber: S) -> AnyCancellable where S.Failure == Failure, S.Input == Output {
let binding = Binding(subscriber)
subscribe(binding)
return AnyCancellable(binding.cancel)
}
}