Last active
July 22, 2024 14:00
-
-
Save serhiybutz/59d1c674c53f8a23d2ac773490410940 to your computer and use it in GitHub Desktop.
Combine: withLatestFrom, 04
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
import Combine | |
extension Publishers { | |
public struct WithLatestFrom<Upstream: Publisher, Other: Publisher>: | |
Publisher where Upstream.Failure == Other.Failure | |
{ | |
// MARK: - Types | |
public typealias Output = (Upstream.Output, Other.Output) | |
public typealias Failure = Upstream.Failure | |
// MARK: - Properties | |
private let upstream: Upstream | |
private let other: Other | |
// MARK: - Initialization | |
init(upstream: Upstream, other: Other) { | |
self.upstream = upstream | |
self.other = other | |
} | |
// MARK: - Publisher Lifecycle | |
public func receive<S: Subscriber>(subscriber: S) | |
where S.Failure == Failure, S.Input == Output | |
{ | |
let merged = mergedStream(upstream, other) | |
let result = resultStream(from: merged) | |
result.subscribe(subscriber) | |
} | |
} | |
} | |
// MARK: - Helpers | |
private extension Publishers.WithLatestFrom { | |
// MARK: - Types | |
enum MergedElement { | |
case upstream1(Upstream.Output) | |
case upstream2(Other.Output) | |
} | |
typealias ScanResult = | |
(value1: Upstream.Output?, | |
value2: Other.Output?, shouldEmit: Bool) | |
// MARK: - Pipelines | |
func mergedStream(_ upstream1: Upstream, _ upstream2: Other) | |
-> AnyPublisher<MergedElement, Failure> | |
{ | |
let mergedElementUpstream1 = upstream1 | |
.map { MergedElement.upstream1($0) } | |
let mergedElementUpstream2 = upstream2 | |
.map { MergedElement.upstream2($0) } | |
return mergedElementUpstream1 | |
.merge(with: mergedElementUpstream2) | |
.eraseToAnyPublisher() | |
} | |
func resultStream( | |
from mergedStream: AnyPublisher<MergedElement, Failure> | |
) -> AnyPublisher<Output, Failure> | |
{ | |
mergedStream | |
.scan(nil) { | |
(prevResult: ScanResult?, | |
mergedElement: MergedElement) -> ScanResult? in | |
var newValue1: Upstream.Output? | |
var newValue2: Other.Output? | |
let shouldEmit: Bool | |
switch mergedElement { | |
case .upstream1(let v): | |
newValue1 = v | |
shouldEmit = prevResult?.value2 != nil | |
case .upstream2(let v): | |
newValue2 = v | |
shouldEmit = false | |
} | |
return ScanResult(value1: newValue1 ?? prevResult?.value1, | |
value2: newValue2 ?? prevResult?.value2, | |
shouldEmit: shouldEmit) | |
} | |
.compactMap { $0 } | |
.filter { $0.shouldEmit } | |
.map { Output($0.value1!, $0.value2!) } | |
.eraseToAnyPublisher() | |
} | |
} | |
extension Publisher { | |
func withLatestFrom<Other: Publisher>(_ other: Other) | |
-> Publishers.WithLatestFrom<Self, Other> | |
{ | |
return .init(upstream: self, other: other) | |
} | |
} |
Author
serhiybutz
commented
Jul 22, 2024
via email
Hi Seyoung,
Feel free to use any of my code at your discretion and responsibility.
Regards,
Serhiy
… On Jul 21, 2024, at 11:42 PM, seyoung.hyun ***@***.***> wrote:
@seyoung-hyun commented on this gist.
Thanks your code :)
Can I use your code in my commercial app?
Please let me know how I can use the code for commercial distribution.
—
Reply to this email directly, view it on GitHub <https://gist.github.com/serhiybutz/59d1c674c53f8a23d2ac773490410940#gistcomment-5128753> or unsubscribe <https://github.com/notifications/unsubscribe-auth/AFOAOKPLNO5ZGG4WOIIG3N3ZNR5QZBFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVEYTANBUG42TKNJZU52HE2LHM5SXFJTDOJSWC5DF>.
You are receiving this email because you authored the thread.
Triage notifications on the go with GitHub Mobile for iOS <https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675> or Android <https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment