import Foundation public enum PMKError: Error { /** The completionHandler with form `(T?, Error?)` was called with `(nil, nil)`. This is invalid as per Cocoa/Apple calling conventions. */ case invalidCallingConvention /** A handler returned its own promise. 99% of the time, this is likely a programming error. It is also invalid per Promises/A+. */ case returnedSelf /** `when()`, `race()` etc. were called with invalid parameters, eg. an empty array. */ case badInput /// The operation was cancelled case cancelled /// `nil` was returned from `flatMap` @available(*, deprecated, message: "See: `compactMap`") case flatMap(Any, Any.Type) /// `nil` was returned from `compactMap` case compactMap(Any, Any.Type) /** The lastValue or firstValue of a sequence was requested but the sequence was empty. Also used if all values of this collection failed the test passed to `firstValue(where:)`. */ case emptySequence /// no winner in `race(fulfilled:)` case noWinner } extension PMKError: CustomDebugStringConvertible { public var debugDescription: String { switch self { case .flatMap(let obj, let type): return "Could not `flatMap<\(type)>`: \(obj)" case .compactMap(let obj, let type): return "Could not `compactMap<\(type)>`: \(obj)" case .invalidCallingConvention: return "A closure was called with an invalid calling convention, probably (nil, nil)" case .returnedSelf: return "A promise handler returned itself" case .badInput: return "Bad input was provided to a PromiseKit function" case .cancelled: return "The asynchronous sequence was cancelled" case .emptySequence: return "The first or last element was requested for an empty sequence" case .noWinner: return "All thenables passed to race(fulfilled:) were rejected" } } } extension PMKError: LocalizedError { public var errorDescription: String? { return debugDescription } } //////////////////////////////////////////////////////////// Cancellation /// An error that may represent the cancelled condition public protocol CancellableError: Error { /// returns true if this Error represents a cancelled condition var isCancelled: Bool { get } } extension Error { public var isCancelled: Bool { do { throw self } catch PMKError.cancelled { return true } catch let error as CancellableError { return error.isCancelled } catch URLError.cancelled { return true } catch CocoaError.userCancelled { return true } catch let error as NSError { #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) let domain = error.domain let code = error.code return ("SKErrorDomain", 2) == (domain, code) #else return false #endif } catch { return false } } } /// Used by `catch` and `recover` public enum CatchPolicy { /// Indicates that `catch` or `recover` handle all error types including cancellable-errors. case allErrors /// Indicates that `catch` or `recover` handle all error except cancellable-errors. case allErrorsExceptCancellation }