Skip to content

Commit

Permalink
Custom error types
Browse files Browse the repository at this point in the history
  • Loading branch information
Wyatt Mufson committed Oct 1, 2019
1 parent a1b5f37 commit e34c89c
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 20 deletions.
8 changes: 4 additions & 4 deletions SwiftPromises/Classes/PromiseExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Value>(dispatchQueue: DispatchQueue? = nil, _ promises: [Promise<Value>], timeout: Int = 15000) -> Promise<[Value]> {
return Promise<[Value]>(dispatchQueue: dispatchQueue) { resolve, reject in
public func all<Value, ErrorType: Error>(dispatchQueue: DispatchQueue? = nil, _ promises: [BasePromise<Value, ErrorType>], timeout: Int = 15000) -> BasePromise<[Value], ErrorType> {
return BasePromise<[Value], ErrorType>(dispatchQueue: dispatchQueue) { resolve, reject in
if promises.count == 0 {
resolve([])
return
Expand Down Expand Up @@ -47,7 +47,7 @@ public func all<Value>(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)
}
})
}
Expand All @@ -58,7 +58,7 @@ public func all<Value>(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<Value>(dispatchQueue: DispatchQueue = .global(qos: .background), _ promise: Promise<Value>) throws -> Value {
public func await<Value, ErrorType: Error>(dispatchQueue: DispatchQueue = .global(qos: .background), _ promise: BasePromise<Value, ErrorType>) throws -> Value {
var result: Value!
var error: Error?

Expand Down
33 changes: 17 additions & 16 deletions SwiftPromises/Classes/SwiftPromises.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@

import Foundation

public typealias Promise<Value> = BasePromise<Value, Error>
/// A Promise is an object representing the eventual completion/failure of an asynchronous operation.
public final class Promise<Value> {
public final class BasePromise<Value, ErrorType: Error> {

internal enum State<T> {
internal enum State<T, E> {
case pending
case resolved(T)
case rejected(Error)
case rejected(E)
}

internal var state: State<Value> = .pending
internal var state: State<Value, ErrorType> = .pending
internal var val: Value? {
if case let .resolved(value) = state {
return value
Expand All @@ -29,7 +30,7 @@ public final class Promise<Value> {
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
Expand Down Expand Up @@ -68,13 +69,13 @@ public final class Promise<Value> {

/// 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())
}

Expand All @@ -90,8 +91,8 @@ public final class Promise<Value> {

/// Handles resolving the Promise (flatMap).
/// - Parameter onResolved: Block to execute when resolved.
public func then<NewValue>(_ onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> {
return Promise<NewValue> { resolve, reject in
public func then<NewValue>(_ onResolved: @escaping (Value) -> BasePromise<NewValue, ErrorType>) -> BasePromise<NewValue, ErrorType> {
return BasePromise<NewValue, ErrorType> { resolve, reject in
internalThen(onResolved: { (value) in
onResolved(value).then(resolve).catch(reject)
})
Expand All @@ -100,8 +101,8 @@ public final class Promise<Value> {

/// Handles resolving the Promise (map).
/// - Parameter onResolved: Block to execute when resolved.
public func then<NewValue>(_ onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> {
return Promise<NewValue> { resolve, reject in
public func then<NewValue>(_ onResolved: @escaping (Value) -> NewValue) -> BasePromise<NewValue, ErrorType> {
return BasePromise<NewValue, ErrorType> { resolve, reject in
return internalThen(onResolved: { (val) in
resolve(onResolved(val))
}, onRejected: { (error) in
Expand All @@ -124,10 +125,10 @@ public final class Promise<Value> {

/// The error callback for the given Promise. Returns another Promise.
/// - Parameter onRejected: The `Catch` block.
public func `catch`<NewValue>(_ onRejected: @escaping (Error) -> NewValue) -> Promise<NewValue> {
return Promise<NewValue> { resolve, reject in
public func `catch`<NewValue>(_ onRejected: @escaping (ErrorType) -> NewValue) -> BasePromise<NewValue, ErrorType> {
return BasePromise<NewValue, ErrorType> { 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))
})
Expand All @@ -144,7 +145,7 @@ public final class Promise<Value> {
})
}

private func reject(error: Error) {
private func reject(error: ErrorType) {
updateState(to: .rejected(error))
triggerErrorCallbacksIfRejected()
}
Expand All @@ -154,7 +155,7 @@ public final class Promise<Value> {
triggerCallbacksIfResolved()
}

private func updateState(to newState: State<Value>) {
private func updateState(to newState: State<Value, ErrorType>) {
guard case .pending = state else { return }
state = newState
}
Expand Down
10 changes: 10 additions & 0 deletions Tests/Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,16 @@ class Tests: XCTestCase {
self.wait(for: [expectation], timeout: 10)
}

func testCustomErrorType() {
typealias NPromise<Value> = BasePromise<Value, NSError>
let p = NPromise<Int>(15)
p.then { (i) in
XCTAssertEqual(i, 15)
}.catch { (e) in
XCTFail(e.domain)
}
}

func testMultiReject() {
let expectation = XCTestExpectation(description: "Test multi reject promise")

Expand Down

0 comments on commit e34c89c

Please sign in to comment.