You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

132 lines
5.1 KiB

//
// 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<T, U>(_ p1: Promise<T>, _ p2: Promise<U>) -> 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<T, U, V>(_ p1: Promise<T>, _ p2: Promise<U>, _ p3: Promise<V>) -> Promise<(T, U, V)> {
return zip(zip(p1, p2), p3).then { ($0.0, $0.1, $1) }
}
// zip 4
public static func zip<A, B, C, D>(_ p1: Promise<A>,
_ p2: Promise<B>,
_ p3: Promise<C>,
_ p4: Promise<D>) -> 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<A, B, C, D, E>(_ p1: Promise<A>,
_ p2: Promise<B>,
_ p3: Promise<C>,
_ p4: Promise<D>,
_ p5: Promise<E>) -> 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<A, B, C, D, E, F>(_ p1: Promise<A>,
_ p2: Promise<B>,
_ p3: Promise<C>,
_ p4: Promise<D>,
_ p5: Promise<E>,
_ p6: Promise<F>) -> 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<A, B, C, D, E, F, G>(_ p1: Promise<A>,
_ p2: Promise<B>,
_ p3: Promise<C>,
_ p4: Promise<D>,
_ p5: Promise<E>,
_ p6: Promise<F>,
_ p7: Promise<G>) -> 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<A, B, C, D, E, F, G, H>(_ p1: Promise<A>,
_ p2: Promise<B>,
_ p3: Promise<C>,
_ p4: Promise<D>,
_ p5: Promise<E>,
_ p6: Promise<F>,
_ p7: Promise<G>,
_ p8: Promise<H>) -> 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) }
}
}