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.
 
 
 
 

137 lines
4.6 KiB

//
// WhenAll.swift
// then
//
// Created by Sacha Durand Saint Omer on 08/04/16.
// Copyright © 2016 s4cha. All rights reserved.
//
import Foundation
import Dispatch
public class Promises {}
extension Promises {
public static func whenAll<T>(_ promises: [Promise<T>], callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return reduceWhenAll(promises, callbackQueue: callbackQueue) { (result, element) in
result.append(element)
}
}
public static func whenAll<T>(_ promises: Promise<T>..., callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return whenAll(promises, callbackQueue: callbackQueue)
}
public static func lazyWhenAll<T>(_ promises: [Promise<T>], callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return lazyReduceWhenAll(promises, callbackQueue: callbackQueue) { (result, element) in
result.append(element)
}
}
public static func lazyWhenAll<T>(_ promises: Promise<T>..., callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return lazyWhenAll(promises, callbackQueue: callbackQueue)
}
// Array version
public static func whenAll<T>(_ promises: [Promise<[T]>], callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return reduceWhenAll(promises, callbackQueue: callbackQueue) { (result, element) in
result.append(contentsOf: element)
}
}
public static func whenAll<T>(_ promises: Promise<[T]>..., callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return whenAll(promises, callbackQueue: callbackQueue)
}
public static func lazyWhenAll<T>(_ promises: [Promise<[T]>], callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return lazyReduceWhenAll(promises, callbackQueue: callbackQueue) { (result, element) in
result.append(contentsOf: element)
}
}
public static func lazyWhenAll<T>(
_ promises: Promise<[T]>...,
callbackQueue: DispatchQueue? = nil) -> Promise<[T]> {
return lazyWhenAll(promises, callbackQueue: callbackQueue)
}
// Private implementations
private static func lazyReduceWhenAll<Result, Source>(
_ promises: [Promise<Source>],
callbackQueue: DispatchQueue?,
updatePartialResult: @escaping (_ result: inout [Result], _ element: Source) -> Void) -> Promise<[Result]> {
return Promise { fulfill, reject in
reducePromises(
promises,
callbackQueue: callbackQueue,
fulfill: fulfill,
reject: reject,
updatePartialResult: updatePartialResult)
}
}
private static func reduceWhenAll<Result, Source>(
_ promises: [Promise<Source>],
callbackQueue: DispatchQueue?,
updatePartialResult: @escaping (_ result: inout [Result], _ element: Source) -> Void) -> Promise<[Result]> {
let p = Promise<[Result]>()
reducePromises(
promises,
callbackQueue: callbackQueue,
fulfill: p.fulfill,
reject: p.reject,
updatePartialResult: updatePartialResult)
return p
}
private static func reducePromises<Result, Source>(
_ promises: [Promise<Source>],
callbackQueue: DispatchQueue?,
fulfill: @escaping ([Result]) -> Void,
reject: @escaping (Error) -> Void,
updatePartialResult: @escaping (_ result: inout [Result], _ element: Source) -> Void) {
let ts = ArrayContainer<Result>()
var error: Error?
let group = DispatchGroup()
for p in promises {
group.enter()
p.then { element in
updatePartialResult(&ts.array, element)
}
.onError { error = $0 }
.finally { group.leave() }
}
let callingQueue = OperationQueue.current?.underlyingQueue
let queue = callbackQueue ?? callingQueue ?? DispatchQueue.main
group.notify(queue: queue) {
if let e = error {
reject(e)
} else {
fulfill(ts.array)
}
}
}
private class ArrayContainer<T> {
private var _array: [T] = []
private let lockQueue = DispatchQueue(label: "com.freshOS.then.whenAll.lockQueue", qos: .userInitiated)
var array: [T] {
get {
return lockQueue.sync {
_array
}
}
set {
lockQueue.sync {
_array = newValue
}
}
}
}
}