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

  1. //
  2. // Promise+Zip.swift
  3. // then
  4. //
  5. // Created by Sacha Durand Saint Omer on 10/08/2017.
  6. // Copyright © 2017 s4cha. All rights reserved.
  7. //
  8. import Foundation
  9. import Dispatch
  10. extension Promises {
  11. public static func zip<T, U>(_ p1: Promise<T>, _ p2: Promise<U>) -> Promise<(T, U)> {
  12. let p = Promise<(T, U)>()
  13. var t: T!
  14. var u: U!
  15. var error: Error?
  16. let group = DispatchGroup()
  17. // We run the promises concurrently on a concurent queue and go back
  18. // to a local queue to read/modify global variables.
  19. // .barrier blocks concurrency so that we can write values
  20. // without then beeing read at the same time.
  21. // It pauses reads until write are done
  22. let concurentQueue = DispatchQueue(label: "then.zip.concurrent", attributes: .concurrent)
  23. let localQueue = DispatchQueue(label: "then.zip.local", attributes: .concurrent)
  24. group.enter()
  25. concurentQueue.async {
  26. p1.then { aT in
  27. localQueue.async(flags: .barrier) {
  28. t = aT
  29. }
  30. }.onError { e in
  31. localQueue.async(flags: .barrier) {
  32. error = e
  33. }
  34. }.finally {
  35. localQueue.async { // barrier needed?
  36. group.leave()
  37. }
  38. }
  39. }
  40. group.enter()
  41. concurentQueue.async {
  42. p2.then { aU in
  43. localQueue.async(flags: .barrier) {
  44. u = aU
  45. }
  46. }.onError { e in
  47. localQueue.async(flags: .barrier) {
  48. error = e
  49. }
  50. }.finally {
  51. localQueue.async {
  52. group.leave()
  53. }
  54. }
  55. }
  56. let callingQueue = OperationQueue.current?.underlyingQueue
  57. let queue = callingQueue ?? DispatchQueue.main
  58. group.notify(queue: queue) {
  59. localQueue.async {
  60. if let e = error {
  61. p.reject(e)
  62. } else {
  63. p.fulfill((t, u))
  64. }
  65. }
  66. }
  67. return p
  68. }
  69. // zip 3
  70. public static func zip<T, U, V>(_ p1: Promise<T>, _ p2: Promise<U>, _ p3: Promise<V>) -> Promise<(T, U, V)> {
  71. return zip(zip(p1, p2), p3).then { ($0.0, $0.1, $1) }
  72. }
  73. // zip 4
  74. public static func zip<A, B, C, D>(_ p1: Promise<A>,
  75. _ p2: Promise<B>,
  76. _ p3: Promise<C>,
  77. _ p4: Promise<D>) -> Promise<(A, B, C, D)> {
  78. return zip(zip(p1, p2, p3), p4).then { ($0.0, $0.1, $0.2, $1) }
  79. }
  80. // zip 5
  81. public static func zip<A, B, C, D, E>(_ p1: Promise<A>,
  82. _ p2: Promise<B>,
  83. _ p3: Promise<C>,
  84. _ p4: Promise<D>,
  85. _ p5: Promise<E>) -> Promise<(A, B, C, D, E)> {
  86. return zip(zip(p1, p2, p3, p4), p5).then { ($0.0, $0.1, $0.2, $0.3, $1) }
  87. }
  88. // zip 6
  89. public static func zip<A, B, C, D, E, F>(_ p1: Promise<A>,
  90. _ p2: Promise<B>,
  91. _ p3: Promise<C>,
  92. _ p4: Promise<D>,
  93. _ p5: Promise<E>,
  94. _ p6: Promise<F>) -> Promise<(A, B, C, D, E, F)> {
  95. return zip(zip(p1, p2, p3, p4, p5), p6 ).then { ($0.0, $0.1, $0.2, $0.3, $0.4, $1) }
  96. }
  97. // zip 7
  98. public static func zip<A, B, C, D, E, F, G>(_ p1: Promise<A>,
  99. _ p2: Promise<B>,
  100. _ p3: Promise<C>,
  101. _ p4: Promise<D>,
  102. _ p5: Promise<E>,
  103. _ p6: Promise<F>,
  104. _ p7: Promise<G>) -> Promise<(A, B, C, D, E, F, G)> {
  105. return zip(zip(p1, p2, p3, p4, p5, p6), p7).then { ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $1) }
  106. }
  107. // zip 8
  108. public static func zip<A, B, C, D, E, F, G, H>(_ p1: Promise<A>,
  109. _ p2: Promise<B>,
  110. _ p3: Promise<C>,
  111. _ p4: Promise<D>,
  112. _ p5: Promise<E>,
  113. _ p6: Promise<F>,
  114. _ p7: Promise<G>,
  115. _ p8: Promise<H>) -> Promise<(A, B, C, D, E, F, G, H)> {
  116. 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) }
  117. }
  118. }