Skip to content

Commit

Permalink
Add more resolution safety and debugging tools when a double-resolve …
Browse files Browse the repository at this point in the history
…happens
  • Loading branch information
EricRabil committed Sep 2, 2021
1 parent 1649e40 commit 2b004b1
Showing 1 changed file with 23 additions and 2 deletions.
25 changes: 23 additions & 2 deletions Sources/Pwomise/Pwomise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public class Promise<Output>: CustomDebugStringConvertible {
case .success(let output):
outputs.append(output)
case .failure(let error):
guard superPromise.pending else {
return
}

superPromise.result = .resolved(.failure(error))
}
}
Expand All @@ -49,6 +53,8 @@ public class Promise<Output>: CustomDebugStringConvertible {

public var resolveQueue: _Scheduler = DispatchQueue.main

private var resolutionStackTrace: [String] = []

/// The underlying status of the promise
internal var result: Pending = .pending {
didSet {
Expand All @@ -58,9 +64,10 @@ public class Promise<Output>: CustomDebugStringConvertible {
willSet {
guard result == .pending, newValue != .pending else {
/// Result can only be set once – its a promise of a result, not a publisher
print(Thread.callStackSymbols.joined(separator: "\n"))
print(resolutionStackTrace.joined(separator: "\n"))
preconditionFailure("result is omnidirectional, from pending to resolved.")
}
resolutionStackTrace = Thread.callStackSymbols
}
}

Expand All @@ -77,14 +84,26 @@ public class Promise<Output>: CustomDebugStringConvertible {

public init(_ cb: (@escaping Resolve, @escaping Reject) -> ()) {
cb({ output in
guard self.pending else {
preconditionFailure("cannot overwrite promise state")
}

self.result = .resolved(.success(output))
}, { error in
guard self.pending else {
preconditionFailure("cannot overwrite promise state")
}

self.result = .resolved(.failure(error))
})
}

public init(_ cb: (@escaping Resolve) -> ()) {
cb({ output in
guard self.pending else {
preconditionFailure("cannot overwrite promise state")
}

self.result = .resolved(.success(output))
})
}
Expand Down Expand Up @@ -136,7 +155,7 @@ public class Promise<Output>: CustomDebugStringConvertible {
let newPromise = Promise()
newPromise.resolveQueue = queue

always { result in
listeners.append { result in
newPromise.result = .resolved(result)
}

Expand All @@ -147,6 +166,7 @@ public class Promise<Output>: CustomDebugStringConvertible {
@discardableResult
public func always<R>(_ cb: @escaping (Completion) throws -> R) -> Promise<R> {
let promise = Promise<R>()

listeners.append { result in
do {
promise.result = .resolved(.success(try cb(result)))
Expand All @@ -162,6 +182,7 @@ public class Promise<Output>: CustomDebugStringConvertible {
@discardableResult
public func always<R: PromiseConvertible>(_ cb: @escaping (Completion) throws -> R) -> Promise<R.Output> {
let promise = Promise<R.Output>()

listeners.append { result in
do {
try cb(result).asPromise.always { result in
Expand Down

0 comments on commit 2b004b1

Please sign in to comment.