From b6d37d16f186a16b0b48e8701dd62030709bb788 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Sat, 20 Dec 2014 20:45:37 -0800 Subject: [PATCH 1/2] Add combineLatest and zip over multiple HotSignals --- ReactiveCocoa.xcodeproj/project.pbxproj | 6 ++ ReactiveCocoa/Swift/HotSignal.swift | 108 ++++++++++++++++++++++ ReactiveCocoa/Swift/TupleExtensions.swift | 52 +++++++++++ 3 files changed, 166 insertions(+) create mode 100644 ReactiveCocoa/Swift/TupleExtensions.swift diff --git a/ReactiveCocoa.xcodeproj/project.pbxproj b/ReactiveCocoa.xcodeproj/project.pbxproj index eb5c9fd1b2..ec1c3ce4cb 100644 --- a/ReactiveCocoa.xcodeproj/project.pbxproj +++ b/ReactiveCocoa.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* Begin PBXBuildFile section */ 270DE4451A1EAB4600151031 /* ObservablePropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277F6A951A1EAA10003E0EC9 /* ObservablePropertySpec.swift */; }; 270DE4461A1EACA200151031 /* ObservablePropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277F6A951A1EAA10003E0EC9 /* ObservablePropertySpec.swift */; }; + D00004091A46864E000E7D41 /* TupleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00004081A46864E000E7D41 /* TupleExtensions.swift */; }; + D000040A1A46864E000E7D41 /* TupleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00004081A46864E000E7D41 /* TupleExtensions.swift */; }; D01792021A34D79100A7B229 /* ColdSignalSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01792011A34D79100A7B229 /* ColdSignalSpec.swift */; }; D01792031A34D79100A7B229 /* ColdSignalSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01792011A34D79100A7B229 /* ColdSignalSpec.swift */; }; D01B7B6219EDD8FE00D26E01 /* Nimble.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D05E662419EDD82000904ACA /* Nimble.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -474,6 +476,7 @@ /* Begin PBXFileReference section */ 277F6A951A1EAA10003E0EC9 /* ObservablePropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObservablePropertySpec.swift; sourceTree = ""; }; + D00004081A46864E000E7D41 /* TupleExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TupleExtensions.swift; sourceTree = ""; }; D01792011A34D79100A7B229 /* ColdSignalSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColdSignalSpec.swift; sourceTree = ""; }; D037642A19EDA41200A782A9 /* NSArray+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+RACSequenceAdditions.h"; sourceTree = ""; }; D037642B19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+RACSequenceAdditions.m"; sourceTree = ""; }; @@ -1116,6 +1119,7 @@ D0C312BB19EF2A5800984962 /* Atomic.swift */, D0C312BC19EF2A5800984962 /* Bag.swift */, D0C312C519EF2A5800984962 /* OptionalExtensions.swift */, + D00004081A46864E000E7D41 /* TupleExtensions.swift */, ); name = "Internal Utilities"; sourceTree = ""; @@ -1588,6 +1592,7 @@ D03765C819EDA41200A782A9 /* RACScopedDisposable.m in Sources */, D03764FE19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m in Sources */, D03764EA19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m in Sources */, + D00004091A46864E000E7D41 /* TupleExtensions.swift in Sources */, D0C312E119EF2A5800984962 /* OptionalExtensions.swift in Sources */, D03765C019EDA41200A782A9 /* RACScheduler.m in Sources */, D0C312D519EF2A5800984962 /* Errors.swift in Sources */, @@ -1792,6 +1797,7 @@ D03B4A3E19F4C39A009E02AC /* FoundationExtensions.swift in Sources */, D037657519EDA41200A782A9 /* RACDynamicSequence.m in Sources */, D037657119EDA41200A782A9 /* RACDisposable.m in Sources */, + D000040A1A46864E000E7D41 /* TupleExtensions.swift in Sources */, D03765DB19EDA41200A782A9 /* RACSignalProvider.d in Sources */, D037653319EDA41200A782A9 /* NSSet+RACSequenceAdditions.m in Sources */, D037665319EDA41200A782A9 /* UISwitch+RACSignalSupport.m in Sources */, diff --git a/ReactiveCocoa/Swift/HotSignal.swift b/ReactiveCocoa/Swift/HotSignal.swift index 971c05fd66..75dc80175f 100644 --- a/ReactiveCocoa/Swift/HotSignal.swift +++ b/ReactiveCocoa/Swift/HotSignal.swift @@ -592,6 +592,114 @@ extension HotSignal { } } +/// An overloaded function that combines the values of up to 10 signals, in the +/// manner described by HotSignal.combineLatestWith(). +public func combineLatest(a: HotSignal, b: HotSignal) -> HotSignal<(A, B)> { + return a.combineLatestWith(b) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal) -> HotSignal<(A, B, C)> { + return combineLatest(a, b) + .combineLatestWith(c) + .map(repack) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal) -> HotSignal<(A, B, C, D)> { + return combineLatest(a, b, c) + .combineLatestWith(d) + .map(repack) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal) -> HotSignal<(A, B, C, D, E)> { + return combineLatest(a, b, c, d) + .combineLatestWith(e) + .map(repack) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal) -> HotSignal<(A, B, C, D, E, F)> { + return combineLatest(a, b, c, d, e) + .combineLatestWith(f) + .map(repack) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal) -> HotSignal<(A, B, C, D, E, F, G)> { + return combineLatest(a, b, c, d, e, f) + .combineLatestWith(g) + .map(repack) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal, h: HotSignal) -> HotSignal<(A, B, C, D, E, F, G, H)> { + return combineLatest(a, b, c, d, e, f, g) + .combineLatestWith(h) + .map(repack) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal, h: HotSignal, i: HotSignal) -> HotSignal<(A, B, C, D, E, F, G, H, I)> { + return combineLatest(a, b, c, d, e, f, g, h) + .combineLatestWith(i) + .map(repack) +} + +public func combineLatest(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal, h: HotSignal, i: HotSignal, j: HotSignal) -> HotSignal<(A, B, C, D, E, F, G, H, I, J)> { + return combineLatest(a, b, c, d, e, f, g, h, i) + .combineLatestWith(j) + .map(repack) +} + +/// An overloaded function that zips the values of up to 10 signals, in the +/// manner described by HotSignal.zipWith(). +public func zip(a: HotSignal, b: HotSignal) -> HotSignal<(A, B)> { + return a.zipWith(b) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal) -> HotSignal<(A, B, C)> { + return zip(a, b) + .zipWith(c) + .map(repack) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal) -> HotSignal<(A, B, C, D)> { + return zip(a, b, c) + .zipWith(d) + .map(repack) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal) -> HotSignal<(A, B, C, D, E)> { + return zip(a, b, c, d) + .zipWith(e) + .map(repack) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal) -> HotSignal<(A, B, C, D, E, F)> { + return zip(a, b, c, d, e) + .zipWith(f) + .map(repack) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal) -> HotSignal<(A, B, C, D, E, F, G)> { + return zip(a, b, c, d, e, f) + .zipWith(g) + .map(repack) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal, h: HotSignal) -> HotSignal<(A, B, C, D, E, F, G, H)> { + return zip(a, b, c, d, e, f, g) + .zipWith(h) + .map(repack) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal, h: HotSignal, i: HotSignal) -> HotSignal<(A, B, C, D, E, F, G, H, I)> { + return zip(a, b, c, d, e, f, g, h) + .zipWith(i) + .map(repack) +} + +public func zip(a: HotSignal, b: HotSignal, c: HotSignal, d: HotSignal, e: HotSignal, f: HotSignal, g: HotSignal, h: HotSignal, i: HotSignal, j: HotSignal) -> HotSignal<(A, B, C, D, E, F, G, H, I, J)> { + return zip(a, b, c, d, e, f, g, h, i) + .zipWith(j) + .map(repack) +} + /// Conversions from HotSignal to ColdSignal. extension HotSignal { /// Buffers `count` values, starting at the time of the method invocation. diff --git a/ReactiveCocoa/Swift/TupleExtensions.swift b/ReactiveCocoa/Swift/TupleExtensions.swift new file mode 100644 index 0000000000..3e17547758 --- /dev/null +++ b/ReactiveCocoa/Swift/TupleExtensions.swift @@ -0,0 +1,52 @@ +// +// TupleExtensions.swift +// ReactiveCocoa +// +// Created by Justin Spahr-Summers on 2014-12-20. +// Copyright (c) 2014 GitHub. All rights reserved. +// + +import Foundation + +/// Adds a value into an N-tuple, returning an (N+1)-tuple. +/// +/// Supports creating tuples up to 10 elements long. +internal func repack(t: (), value: A) -> (A) { + return (value) +} + +internal func repack(t: (A), value: B) -> (A, B) { + return (t.0, value) +} + +internal func repack(t: (A, B), value: C) -> (A, B, C) { + return (t.0, t.1, value) +} + +internal func repack(t: (A, B, C), value: D) -> (A, B, C, D) { + return (t.0, t.1, t.2, value) +} + +internal func repack(t: (A, B, C, D), value: E) -> (A, B, C, D, E) { + return (t.0, t.1, t.2, t.3, value) +} + +internal func repack(t: (A, B, C, D, E), value: F) -> (A, B, C, D, E, F) { + return (t.0, t.1, t.2, t.3, t.4, value) +} + +internal func repack(t: (A, B, C, D, E, F), value: G) -> (A, B, C, D, E, F, G) { + return (t.0, t.1, t.2, t.3, t.4, t.5, value) +} + +internal func repack(t: (A, B, C, D, E, F, G), value: H) -> (A, B, C, D, E, F, G, H) { + return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, value) +} + +internal func repack(t: (A, B, C, D, E, F, G, H), value: I) -> (A, B, C, D, E, F, G, H, I) { + return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, value) +} + +internal func repack(t: (A, B, C, D, E, F, G, H, I), value: J) -> (A, B, C, D, E, F, G, H, I, J) { + return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, value) +} From 2daee111f82bf5a62c5597384f249881487592ee Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Sat, 20 Dec 2014 20:46:45 -0800 Subject: [PATCH 2/2] Add combineLatest & zip over multiple ColdSignals --- ReactiveCocoa/Swift/ColdSignal.swift | 108 +++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/ReactiveCocoa/Swift/ColdSignal.swift b/ReactiveCocoa/Swift/ColdSignal.swift index a3f617ac04..c0e6174e58 100644 --- a/ReactiveCocoa/Swift/ColdSignal.swift +++ b/ReactiveCocoa/Swift/ColdSignal.swift @@ -1087,6 +1087,114 @@ extension ColdSignal { } } +/// An overloaded function that combines the values of up to 10 signals, in the +/// manner described by ColdSignal.combineLatestWith(). +public func combineLatest(a: ColdSignal, b: ColdSignal) -> ColdSignal<(A, B)> { + return a.combineLatestWith(b) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal) -> ColdSignal<(A, B, C)> { + return combineLatest(a, b) + .combineLatestWith(c) + .map(repack) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal) -> ColdSignal<(A, B, C, D)> { + return combineLatest(a, b, c) + .combineLatestWith(d) + .map(repack) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal) -> ColdSignal<(A, B, C, D, E)> { + return combineLatest(a, b, c, d) + .combineLatestWith(e) + .map(repack) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal) -> ColdSignal<(A, B, C, D, E, F)> { + return combineLatest(a, b, c, d, e) + .combineLatestWith(f) + .map(repack) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G)> { + return combineLatest(a, b, c, d, e, f) + .combineLatestWith(g) + .map(repack) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal, h: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G, H)> { + return combineLatest(a, b, c, d, e, f, g) + .combineLatestWith(h) + .map(repack) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal, h: ColdSignal, i: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G, H, I)> { + return combineLatest(a, b, c, d, e, f, g, h) + .combineLatestWith(i) + .map(repack) +} + +public func combineLatest(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal, h: ColdSignal, i: ColdSignal, j: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G, H, I, J)> { + return combineLatest(a, b, c, d, e, f, g, h, i) + .combineLatestWith(j) + .map(repack) +} + +/// An overloaded function that zips the values of up to 10 signals, in the +/// manner described by ColdSignal.zipWith(). +public func zip(a: ColdSignal, b: ColdSignal) -> ColdSignal<(A, B)> { + return a.zipWith(b) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal) -> ColdSignal<(A, B, C)> { + return zip(a, b) + .zipWith(c) + .map(repack) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal) -> ColdSignal<(A, B, C, D)> { + return zip(a, b, c) + .zipWith(d) + .map(repack) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal) -> ColdSignal<(A, B, C, D, E)> { + return zip(a, b, c, d) + .zipWith(e) + .map(repack) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal) -> ColdSignal<(A, B, C, D, E, F)> { + return zip(a, b, c, d, e) + .zipWith(f) + .map(repack) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G)> { + return zip(a, b, c, d, e, f) + .zipWith(g) + .map(repack) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal, h: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G, H)> { + return zip(a, b, c, d, e, f, g) + .zipWith(h) + .map(repack) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal, h: ColdSignal, i: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G, H, I)> { + return zip(a, b, c, d, e, f, g, h) + .zipWith(i) + .map(repack) +} + +public func zip(a: ColdSignal, b: ColdSignal, c: ColdSignal, d: ColdSignal, e: ColdSignal, f: ColdSignal, g: ColdSignal, h: ColdSignal, i: ColdSignal, j: ColdSignal) -> ColdSignal<(A, B, C, D, E, F, G, H, I, J)> { + return zip(a, b, c, d, e, f, g, h, i) + .zipWith(j) + .map(repack) +} + /// Blocking methods for receiving values. extension ColdSignal { /// Starts the receiver, then returns the first value received.