diff --git a/Sources/Pwomise/Pwomise.swift b/Sources/Pwomise/Pwomise.swift index ef7808c..45d1a2c 100644 --- a/Sources/Pwomise/Pwomise.swift +++ b/Sources/Pwomise/Pwomise.swift @@ -39,6 +39,10 @@ public class Promise: CustomDebugStringConvertible { case .success(let output): outputs.append(output) case .failure(let error): + guard superPromise.pending else { + return + } + superPromise.result = .resolved(.failure(error)) } } @@ -49,6 +53,8 @@ public class Promise: CustomDebugStringConvertible { public var resolveQueue: _Scheduler = DispatchQueue.main + private var resolutionStackTrace: [String] = [] + /// The underlying status of the promise internal var result: Pending = .pending { didSet { @@ -58,9 +64,10 @@ public class Promise: 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 } } @@ -77,14 +84,26 @@ public class Promise: 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)) }) } @@ -136,7 +155,7 @@ public class Promise: CustomDebugStringConvertible { let newPromise = Promise() newPromise.resolveQueue = queue - always { result in + listeners.append { result in newPromise.result = .resolved(result) } @@ -147,6 +166,7 @@ public class Promise: CustomDebugStringConvertible { @discardableResult public func always(_ cb: @escaping (Completion) throws -> R) -> Promise { let promise = Promise() + listeners.append { result in do { promise.result = .resolved(.success(try cb(result))) @@ -162,6 +182,7 @@ public class Promise: CustomDebugStringConvertible { @discardableResult public func always(_ cb: @escaping (Completion) throws -> R) -> Promise { let promise = Promise() + listeners.append { result in do { try cb(result).asPromise.always { result in