Skip to content

Instantly share code, notes, and snippets.

@GeekAndDad
Last active August 15, 2023 08:20
Show Gist options
  • Save GeekAndDad/5e381557dc8ba6bc96ebecb17442290e to your computer and use it in GitHub Desktop.
Save GeekAndDad/5e381557dc8ba6bc96ebecb17442290e to your computer and use it in GitHub Desktop.
A sketch of a possible approach to mapping a CurrentValueSubject<A,Never> to a CurrentValueSubject<B,Never>. Likely can be simplified and cleaned up, but seems to work...
Test Suite 'Tests' started at 2023-08-15 01:16:43.640
Test Case '-[TestCombineChainingCurrentValueSubjectTests.Tests test]' started.
1
12
13
exiting
Test Case '-[TestCombineChainingCurrentValueSubjectTests.Tests test]' passed (0.001 seconds).
Test Suite 'Tests' passed at 2023-08-15 01:16:43.642.
Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.002) seconds
Program ended with exit code: 0
import XCTest
import Cocoa
import Combine
final public class MappedCurrentValueSubject<A, B, Failure, S: CurrentValueSubject<A, Failure>> : Subject
where Failure == S.Failure
{
public typealias Output = B
let upstream: AnyPublisher<S.Output, S.Failure>
private let wrapped: CurrentValueSubject<Output, Failure>
private let transform: (S.Output) -> Output
private var cancellable: AnyCancellable? = nil
init(upstream toBeMappedCurrentValueSubject: S, transform: @escaping (S.Output) -> Output)
where S.Failure == Failure
{
self.upstream = toBeMappedCurrentValueSubject.eraseToAnyPublisher()
self.wrapped = CurrentValueSubject<Output, Failure>(transform(toBeMappedCurrentValueSubject.value))
self.transform = transform
self.cancellable = upstream.sink { completion in
self.send(completion: completion)
} receiveValue: { value in
self.send(transform(value))
}
}
public func send(_ value: Output) {
wrapped.send(value)
}
public func send(completion: Subscribers.Completion<Failure>) {
wrapped.send(completion: completion)
}
public func send(subscription: Subscription) {
wrapped.send(subscription: subscription)
}
public func receive<Downstream: Subscriber>(subscriber: Downstream)
where Failure == Downstream.Failure, Output == Downstream.Input
{
wrapped.subscribe(subscriber)
}
public func asCurrentValueSubject() -> CurrentValueSubject<Output, Failure> {
return wrapped
}
}
extension CurrentValueSubject where Failure == Never {
func mappedCurrentValueSubject<T>(
transform: @escaping (Output) -> T
) -> CurrentValueSubject<T, Failure>
{
return MappedCurrentValueSubject<Output, T, Never, CurrentValueSubject<Output, Failure>>(
upstream: self,
transform: transform
).asCurrentValueSubject()
}
}
// Example usage
final class Tests: XCTestCase {
func test() throws {
var cancellables: [AnyCancellable] = []
let num = CurrentValueSubject<Int, Never>(1)
let s = num.mappedCurrentValueSubject(transform: { "\($0)" })
s.sink { s in
print(s)
}
.store(in: &cancellables)
num.send(12)
num.send(13)
num.send(completion: .finished)
print("exiting")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment