// // Promise+Zip.swift // then // // Created by Sacha Durand Saint Omer on 10/08/2017. // Copyright © 2017 s4cha. All rights reserved. // import Foundation import Dispatch extension Promises { public static func zip(_ p1: Promise, _ p2: Promise) -> Promise<(T, U)> { let p = Promise<(T, U)>() var t: T! var u: U! var error: Error? let group = DispatchGroup() // We run the promises concurrently on a concurent queue and go back // to a local queue to read/modify global variables. // .barrier blocks concurrency so that we can write values // without then beeing read at the same time. // It pauses reads until write are done let concurentQueue = DispatchQueue(label: "then.zip.concurrent", attributes: .concurrent) let localQueue = DispatchQueue(label: "then.zip.local", attributes: .concurrent) group.enter() concurentQueue.async { p1.then { aT in localQueue.async(flags: .barrier) { t = aT } }.onError { e in localQueue.async(flags: .barrier) { error = e } }.finally { localQueue.async { // barrier needed? group.leave() } } } group.enter() concurentQueue.async { p2.then { aU in localQueue.async(flags: .barrier) { u = aU } }.onError { e in localQueue.async(flags: .barrier) { error = e } }.finally { localQueue.async { group.leave() } } } let callingQueue = OperationQueue.current?.underlyingQueue let queue = callingQueue ?? DispatchQueue.main group.notify(queue: queue) { localQueue.async { if let e = error { p.reject(e) } else { p.fulfill((t, u)) } } } return p } // zip 3 public static func zip(_ p1: Promise, _ p2: Promise, _ p3: Promise) -> Promise<(T, U, V)> { return zip(zip(p1, p2), p3).then { ($0.0, $0.1, $1) } } // zip 4 public static func zip(_ p1: Promise, _ p2: Promise, _ p3: Promise, _ p4: Promise) -> Promise<(A, B, C, D)> { return zip(zip(p1, p2, p3), p4).then { ($0.0, $0.1, $0.2, $1) } } // zip 5 public static func zip(_ p1: Promise, _ p2: Promise, _ p3: Promise, _ p4: Promise, _ p5: Promise) -> Promise<(A, B, C, D, E)> { return zip(zip(p1, p2, p3, p4), p5).then { ($0.0, $0.1, $0.2, $0.3, $1) } } // zip 6 public static func zip(_ p1: Promise, _ p2: Promise, _ p3: Promise, _ p4: Promise, _ p5: Promise, _ p6: Promise) -> Promise<(A, B, C, D, E, F)> { return zip(zip(p1, p2, p3, p4, p5), p6 ).then { ($0.0, $0.1, $0.2, $0.3, $0.4, $1) } } // zip 7 public static func zip(_ p1: Promise, _ p2: Promise, _ p3: Promise, _ p4: Promise, _ p5: Promise, _ p6: Promise, _ p7: Promise) -> Promise<(A, B, C, D, E, F, G)> { return zip(zip(p1, p2, p3, p4, p5, p6), p7).then { ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $1) } } // zip 8 public static func zip(_ p1: Promise, _ p2: Promise, _ p3: Promise, _ p4: Promise, _ p5: Promise, _ p6: Promise, _ p7: Promise, _ p8: Promise) -> Promise<(A, B, C, D, E, F, G, H)> { return zip(zip(p1, p2, p3, p4, p5, p6, p7), p8).then { ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $1) } } }