From e34c89cccbf1566a9032839184012c72931487fa Mon Sep 17 00:00:00 2001 From: Wyatt Mufson Date: Tue, 1 Oct 2019 15:15:38 -0500 Subject: [PATCH] Custom error types --- SwiftPromises/Classes/PromiseExtensions.swift | 8 ++--- SwiftPromises/Classes/SwiftPromises.swift | 33 ++++++++++--------- Tests/Tests.swift | 10 ++++++ 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/SwiftPromises/Classes/PromiseExtensions.swift b/SwiftPromises/Classes/PromiseExtensions.swift index 9be9fbf..9d363a5 100644 --- a/SwiftPromises/Classes/PromiseExtensions.swift +++ b/SwiftPromises/Classes/PromiseExtensions.swift @@ -15,8 +15,8 @@ import Foundation /// Defaults to `nil` /// - Parameter promises: The array of Promises to execute. /// - Parameter timeout: The amount of milliseconds to pass before triggering a timeout error. -public func all(dispatchQueue: DispatchQueue? = nil, _ promises: [Promise], timeout: Int = 15000) -> Promise<[Value]> { - return Promise<[Value]>(dispatchQueue: dispatchQueue) { resolve, reject in +public func all(dispatchQueue: DispatchQueue? = nil, _ promises: [BasePromise], timeout: Int = 15000) -> BasePromise<[Value], ErrorType> { + return BasePromise<[Value], ErrorType>(dispatchQueue: dispatchQueue) { resolve, reject in if promises.count == 0 { resolve([]) return @@ -47,7 +47,7 @@ public func all(dispatchQueue: DispatchQueue? = nil, _ promises: [Promise DispatchQueue.global().asyncAfter(deadline: .now() + .milliseconds(timeout), execute: { if !resolved { resolved = true - reject(NSError(domain: "Timeout", code: -1, userInfo: [:])) + reject(NSError(domain: "Timeout", code: -1, userInfo: [:]) as! ErrorType) } }) } @@ -58,7 +58,7 @@ public func all(dispatchQueue: DispatchQueue? = nil, _ promises: [Promise /// - Parameter dispatchQueue: The `DispatchQueue` to run the given Promise on. /// Defaults to `.global(qos: .background)` /// - Parameter promise: The Promise to execute. -public func await(dispatchQueue: DispatchQueue = .global(qos: .background), _ promise: Promise) throws -> Value { +public func await(dispatchQueue: DispatchQueue = .global(qos: .background), _ promise: BasePromise) throws -> Value { var result: Value! var error: Error? diff --git a/SwiftPromises/Classes/SwiftPromises.swift b/SwiftPromises/Classes/SwiftPromises.swift index c5ceede..a7d6b72 100644 --- a/SwiftPromises/Classes/SwiftPromises.swift +++ b/SwiftPromises/Classes/SwiftPromises.swift @@ -8,16 +8,17 @@ import Foundation +public typealias Promise = BasePromise /// A Promise is an object representing the eventual completion/failure of an asynchronous operation. -public final class Promise { +public final class BasePromise { - internal enum State { + internal enum State { case pending case resolved(T) - case rejected(Error) + case rejected(E) } - internal var state: State = .pending + internal var state: State = .pending internal var val: Value? { if case let .resolved(value) = state { return value @@ -29,7 +30,7 @@ public final class Promise { public typealias Then = (Value) -> Void /// A `Catch` block. - public typealias Catch = (Error) -> Void + public typealias Catch = (ErrorType) -> Void /// An `Always` block. public typealias Always = () -> Void @@ -68,13 +69,13 @@ public final class Promise { /// Intialize a rejected Promise. /// - Parameter error: The Promise's error. - public init(_ error: Error) { + public init(_ error: ErrorType) { state = .rejected(error) } /// Intialize a rejected Promise. /// - Parameter errorValue: The function returning the Promise's error. - public init(_ errorValue: @escaping () -> Error) { + public init(_ errorValue: @escaping () -> ErrorType) { state = .rejected(errorValue()) } @@ -90,8 +91,8 @@ public final class Promise { /// Handles resolving the Promise (flatMap). /// - Parameter onResolved: Block to execute when resolved. - public func then(_ onResolved: @escaping (Value) -> Promise) -> Promise { - return Promise { resolve, reject in + public func then(_ onResolved: @escaping (Value) -> BasePromise) -> BasePromise { + return BasePromise { resolve, reject in internalThen(onResolved: { (value) in onResolved(value).then(resolve).catch(reject) }) @@ -100,8 +101,8 @@ public final class Promise { /// Handles resolving the Promise (map). /// - Parameter onResolved: Block to execute when resolved. - public func then(_ onResolved: @escaping (Value) -> NewValue) -> Promise { - return Promise { resolve, reject in + public func then(_ onResolved: @escaping (Value) -> NewValue) -> BasePromise { + return BasePromise { resolve, reject in return internalThen(onResolved: { (val) in resolve(onResolved(val)) }, onRejected: { (error) in @@ -124,10 +125,10 @@ public final class Promise { /// The error callback for the given Promise. Returns another Promise. /// - Parameter onRejected: The `Catch` block. - public func `catch`(_ onRejected: @escaping (Error) -> NewValue) -> Promise { - return Promise { resolve, reject in + public func `catch`(_ onRejected: @escaping (ErrorType) -> NewValue) -> BasePromise { + return BasePromise { resolve, reject in return internalThen(onResolved: { (val) in - reject(NSError(domain: "", code: 0, userInfo: [:])) // The error to be returned and ignored by Always + reject(NSError(domain: "", code: 0, userInfo: [:]) as! ErrorType) // The error to be returned and ignored by Always }, onRejected: { (error) in resolve(onRejected(error)) }) @@ -144,7 +145,7 @@ public final class Promise { }) } - private func reject(error: Error) { + private func reject(error: ErrorType) { updateState(to: .rejected(error)) triggerErrorCallbacksIfRejected() } @@ -154,7 +155,7 @@ public final class Promise { triggerCallbacksIfResolved() } - private func updateState(to newState: State) { + private func updateState(to newState: State) { guard case .pending = state else { return } state = newState } diff --git a/Tests/Tests.swift b/Tests/Tests.swift index 9121916..9697266 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -493,6 +493,16 @@ class Tests: XCTestCase { self.wait(for: [expectation], timeout: 10) } + func testCustomErrorType() { + typealias NPromise = BasePromise + let p = NPromise(15) + p.then { (i) in + XCTAssertEqual(i, 15) + }.catch { (e) in + XCTFail(e.domain) + } + } + func testMultiReject() { let expectation = XCTestExpectation(description: "Test multi reject promise")