Skip to content

Commit

Permalink
Implement CombineLatest (#16)
Browse files Browse the repository at this point in the history
* Implement CombineLatest

* Update Publishers.Zip

* Update Merge

* Update CombineLatest

* Add CombineLatestTests

* Update CombineLatest doc

* Fix compile issue on Linux

---------

Co-authored-by: Sergej Jaskiewicz <[email protected]>
  • Loading branch information
Kyle-Ye and broadwaylamb authored Dec 28, 2023
1 parent f746dc3 commit a7315a9
Show file tree
Hide file tree
Showing 9 changed files with 1,677 additions and 269 deletions.
196 changes: 0 additions & 196 deletions RemainingCombineInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,165 +2,6 @@
// Please remove the corresponding piece from this file if you implement something,
// and complement this file as features are added in Apple's Combine

extension Publishers {

/// A publisher that receives and combines the latest elements from two publishers.
public struct CombineLatest<A, B> : Publisher where A : Publisher, B : Publisher, A.Failure == B.Failure {

/// The kind of values published by this publisher.
public typealias Output = (A.Output, B.Output)

/// The kind of errors this publisher might publish.
///
/// Use `Never` if this `Publisher` does not publish errors.
public typealias Failure = A.Failure

public let a: A

public let b: B

public init(_ a: A, _ b: B)

/// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)`
///
/// - SeeAlso: `subscribe(_:)`
/// - Parameters:
/// - subscriber: The subscriber to attach to this `Publisher`.
/// once attached it can begin to receive values.
public func receive<S>(subscriber: S) where S : Subscriber, B.Failure == S.Failure, S.Input == (A.Output, B.Output)
}

/// A publisher that receives and combines the latest elements from three publishers.
public struct CombineLatest3<A, B, C> : Publisher where A : Publisher, B : Publisher, C : Publisher, A.Failure == B.Failure, B.Failure == C.Failure {

/// The kind of values published by this publisher.
public typealias Output = (A.Output, B.Output, C.Output)

/// The kind of errors this publisher might publish.
///
/// Use `Never` if this `Publisher` does not publish errors.
public typealias Failure = A.Failure

public let a: A

public let b: B

public let c: C

public init(_ a: A, _ b: B, _ c: C)

/// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)`
///
/// - SeeAlso: `subscribe(_:)`
/// - Parameters:
/// - subscriber: The subscriber to attach to this `Publisher`.
/// once attached it can begin to receive values.
public func receive<S>(subscriber: S) where S : Subscriber, C.Failure == S.Failure, S.Input == (A.Output, B.Output, C.Output)
}

/// A publisher that receives and combines the latest elements from four publishers.
public struct CombineLatest4<A, B, C, D> : Publisher where A : Publisher, B : Publisher, C : Publisher, D : Publisher, A.Failure == B.Failure, B.Failure == C.Failure, C.Failure == D.Failure {

/// The kind of values published by this publisher.
public typealias Output = (A.Output, B.Output, C.Output, D.Output)

/// The kind of errors this publisher might publish.
///
/// Use `Never` if this `Publisher` does not publish errors.
public typealias Failure = A.Failure

public let a: A

public let b: B

public let c: C

public let d: D

public init(_ a: A, _ b: B, _ c: C, _ d: D)

/// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)`
///
/// - SeeAlso: `subscribe(_:)`
/// - Parameters:
/// - subscriber: The subscriber to attach to this `Publisher`.
/// once attached it can begin to receive values.
public func receive<S>(subscriber: S) where S : Subscriber, D.Failure == S.Failure, S.Input == (A.Output, B.Output, C.Output, D.Output)
}
}

extension Publisher {

/// Subscribes to an additional publisher and publishes a tuple upon receiving output from either publisher.
///
/// The combined publisher passes through any requests to *all* upstream publishers. However, it still obeys the demand-fulfilling rule of only sending the request amount downstream. If the demand isn’t `.unlimited`, it drops values from upstream publishers. It implements this by using a buffer size of 1 for each upstream, and holds the most recent value in each buffer.
/// All upstream publishers need to finish for this publisher to finsh. If an upstream publisher never publishes a value, this publisher never finishes.
/// If any of the combined publishers terminates with a failure, this publisher also fails.
/// - Parameters:
/// - other: Another publisher to combine with this one.
/// - Returns: A publisher that receives and combines elements from this and another publisher.
public func combineLatest<P>(_ other: P) -> Publishers.CombineLatest<Self, P> where P : Publisher, Self.Failure == P.Failure

/// Subscribes to an additional publisher and invokes a closure upon receiving output from either publisher.
///
/// The combined publisher passes through any requests to *all* upstream publishers. However, it still obeys the demand-fulfilling rule of only sending the request amount downstream. If the demand isn’t `.unlimited`, it drops values from upstream publishers. It implements this by using a buffer size of 1 for each upstream, and holds the most recent value in each buffer.
/// All upstream publishers need to finish for this publisher to finsh. If an upstream publisher never publishes a value, this publisher never finishes.
/// If any of the combined publishers terminates with a failure, this publisher also fails.
/// - Parameters:
/// - other: Another publisher to combine with this one.
/// - transform: A closure that receives the most recent value from each publisher and returns a new value to publish.
/// - Returns: A publisher that receives and combines elements from this and another publisher.
public func combineLatest<P, T>(_ other: P, _ transform: @escaping (Self.Output, P.Output) -> T) -> Publishers.Map<Publishers.CombineLatest<Self, P>, T> where P : Publisher, Self.Failure == P.Failure

/// Subscribes to two additional publishers and publishes a tuple upon receiving output from any of the publishers.
///
/// The combined publisher passes through any requests to *all* upstream publishers. However, it still obeys the demand-fulfilling rule of only sending the request amount downstream. If the demand isn’t `.unlimited`, it drops values from upstream publishers. It implements this by using a buffer size of 1 for each upstream, and holds the most recent value in each buffer.
/// All upstream publishers need to finish for this publisher to finish. If an upstream publisher never publishes a value, this publisher never finishes.
/// If any of the combined publishers terminates with a failure, this publisher also fails.
/// - Parameters:
/// - publisher1: A second publisher to combine with this one.
/// - publisher2: A third publisher to combine with this one.
/// - Returns: A publisher that receives and combines elements from this publisher and two other publishers.
public func combineLatest<P, Q>(_ publisher1: P, _ publisher2: Q) -> Publishers.CombineLatest3<Self, P, Q> where P : Publisher, Q : Publisher, Self.Failure == P.Failure, P.Failure == Q.Failure

/// Subscribes to two additional publishers and invokes a closure upon receiving output from any of the publishers.
///
/// The combined publisher passes through any requests to *all* upstream publishers. However, it still obeys the demand-fulfilling rule of only sending the request amount downstream. If the demand isn’t `.unlimited`, it drops values from upstream publishers. It implements this by using a buffer size of 1 for each upstream, and holds the most recent value in each buffer.
/// All upstream publishers need to finish for this publisher to finish. If an upstream publisher never publishes a value, this publisher never finishes.
/// If any of the combined publishers terminates with a failure, this publisher also fails.
/// - Parameters:
/// - publisher1: A second publisher to combine with this one.
/// - publisher2: A third publisher to combine with this one.
/// - transform: A closure that receives the most recent value from each publisher and returns a new value to publish.
/// - Returns: A publisher that receives and combines elements from this publisher and two other publishers.
public func combineLatest<P, Q, T>(_ publisher1: P, _ publisher2: Q, _ transform: @escaping (Self.Output, P.Output, Q.Output) -> T) -> Publishers.Map<Publishers.CombineLatest3<Self, P, Q>, T> where P : Publisher, Q : Publisher, Self.Failure == P.Failure, P.Failure == Q.Failure

/// Subscribes to three additional publishers and publishes a tuple upon receiving output from any of the publishers.
///
/// The combined publisher passes through any requests to *all* upstream publishers. However, it still obeys the demand-fulfilling rule of only sending the request amount downstream. If the demand isn’t `.unlimited`, it drops values from upstream publishers. It implements this by using a buffer size of 1 for each upstream, and holds the most recent value in each buffer.
/// All upstream publishers need to finish for this publisher to finish. If an upstream publisher never publishes a value, this publisher never finishes.
/// If any of the combined publishers terminates with a failure, this publisher also fails.
/// - Parameters:
/// - publisher1: A second publisher to combine with this one.
/// - publisher2: A third publisher to combine with this one.
/// - publisher3: A fourth publisher to combine with this one.
/// - Returns: A publisher that receives and combines elements from this publisher and three other publishers.
public func combineLatest<P, Q, R>(_ publisher1: P, _ publisher2: Q, _ publisher3: R) -> Publishers.CombineLatest4<Self, P, Q, R> where P : Publisher, Q : Publisher, R : Publisher, Self.Failure == P.Failure, P.Failure == Q.Failure, Q.Failure == R.Failure

/// Subscribes to three additional publishers and invokes a closure upon receiving output from any of the publishers.
///
/// The combined publisher passes through any requests to *all* upstream publishers. However, it still obeys the demand-fulfilling rule of only sending the request amount downstream. If the demand isn’t `.unlimited`, it drops values from upstream publishers. It implements this by using a buffer size of 1 for each upstream, and holds the most recent value in each buffer.
/// All upstream publishers need to finish for this publisher to finish. If an upstream publisher never publishes a value, this publisher never finishes.
/// If any of the combined publishers terminates with a failure, this publisher also fails.
/// - Parameters:
/// - publisher1: A second publisher to combine with this one.
/// - publisher2: A third publisher to combine with this one.
/// - publisher3: A fourth publisher to combine with this one.
/// - transform: A closure that receives the most recent value from each publisher and returns a new value to publish.
/// - Returns: A publisher that receives and combines elements from this publisher and three other publishers.
public func combineLatest<P, Q, R, T>(_ publisher1: P, _ publisher2: Q, _ publisher3: R, _ transform: @escaping (Self.Output, P.Output, Q.Output, R.Output) -> T) -> Publishers.Map<Publishers.CombineLatest4<Self, P, Q, R>, T> where P : Publisher, Q : Publisher, R : Publisher, Self.Failure == P.Failure, P.Failure == Q.Failure, Q.Failure == R.Failure
}

extension Publishers {

/// A strategy for collecting received elements.
Expand Down Expand Up @@ -243,40 +84,3 @@ extension Publisher {
/// a single array of the collection.
public func collect<S>(_ strategy: Publishers.TimeGroupingStrategy<S>, options: S.SchedulerOptions? = nil) -> Publishers.CollectByTime<Self, S> where S : Scheduler
}

extension Publishers.CombineLatest : Equatable where A : Equatable, B : Equatable {

/// Returns a Boolean value that indicates whether two publishers are equivalent.
///
/// - Parameters:
/// - lhs: A combineLatest publisher to compare for equality.
/// - rhs: Another combineLatest publisher to compare for equality.
/// - Returns: `true` if the corresponding upstream publishers of each combineLatest publisher are equal, `false` otherwise.
public static func == (lhs: Publishers.CombineLatest<A, B>, rhs: Publishers.CombineLatest<A, B>) -> Bool
}

extension Publishers.CombineLatest3 : Equatable where A : Equatable, B : Equatable, C : Equatable {

/// Returns a Boolean value indicating whether two values are equal.
///
/// Equality is the inverse of inequality. For any values `a` and `b`,
/// `a == b` implies that `a != b` is `false`.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
public static func == (lhs: Publishers.CombineLatest3<A, B, C>, rhs: Publishers.CombineLatest3<A, B, C>) -> Bool
}

extension Publishers.CombineLatest4 : Equatable where A : Equatable, B : Equatable, C : Equatable, D : Equatable {

/// Returns a Boolean value indicating whether two values are equal.
///
/// Equality is the inverse of inequality. For any values `a` and `b`,
/// `a == b` implies that `a != b` is `false`.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
public static func == (lhs: Publishers.CombineLatest4<A, B, C, D>, rhs: Publishers.CombineLatest4<A, B, C, D>) -> Bool
}
2 changes: 1 addition & 1 deletion Sources/OpenCombine/AnyPublisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// OpenCombine
//
// Created by Sergej Jaskiewicz on 10.06.2019.
// Audited for Combine 2023
// Audited for 2023 Release

extension Publisher {
/// Wraps this publisher with a type eraser.
Expand Down
10 changes: 6 additions & 4 deletions Sources/OpenCombine/Helpers/Violations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ internal func APIViolationUnexpectedCompletion(file: StaticString = #file,
fatalError("API Violation: received an unexpected completion", file: file, line: line)
}

internal func abstractMethod(file: StaticString = #file, line: UInt = #line) -> Never {
fatalError("Abstract method call", file: file, line: line)
@_transparent
@inline(__always)
func abstractMethod(file: StaticString = #file, line: UInt = #line) -> Never {
fatalError("Abstract method", file: file, line: line)
}

extension Subscribers.Demand {
@_transparent
@inline(__always)
internal func assertNonZero() {
precondition(rawValue != .zero)
func assertNonZero() {
precondition(self != 0)
}
}
Loading

0 comments on commit a7315a9

Please sign in to comment.