Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions Sources/Box.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,3 @@ class EmptyBox<T>: Box<T> {
}
}
}


extension Optional where Wrapped: DispatchQueue {
@inline(__always)
func async(flags: DispatchWorkItemFlags?, _ body: @escaping() -> Void) {
switch self {
case .none:
body()
case .some(let q):
if let flags = flags {
q.async(flags: flags, execute: body)
} else {
q.async(execute: body)
}
}
}
}
47 changes: 23 additions & 24 deletions Sources/Catchable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ public extension CatchMixin {
of a chain. Often utility promises will not have a catch, instead
delegating the error handling to the caller.

- Parameter on: The queue to which the provided closure dispatches.
- Parameter on: The dispatcher that executes the provided closure.
- Parameter policy: The default policy does not execute your handler for cancellation errors.
- Parameter execute: The handler to execute if this promise is rejected.
- Returns: A promise finalizer.
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
*/
@discardableResult
func `catch`(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer {
func `catch`(on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer {
let finalizer = PMKFinalizer()
pipe {
switch $0 {
case .rejected(let error):
guard policy == .allErrors || !error.isCancelled else {
fallthrough
}
on.async(flags: flags) {
on.dispatch {
body(error)
finalizer.pending.resolve(())
}
Expand All @@ -45,8 +45,8 @@ public class PMKFinalizer {
let pending = Guarantee<Void>.pending()

/// `finally` is the same as `ensure`, but it is not chainable
public func finally(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) {
pending.guarantee.done(on: on, flags: flags) {
public func finally(on: Dispatcher = conf.D.return, _ body: @escaping () -> Void) {
pending.guarantee.done(on: on) {
body()
}
}
Expand All @@ -68,19 +68,19 @@ public extension CatchMixin {
return .value(CLLocation.chicago)
}

- Parameter on: The queue to which the provided closure dispatches.
- Parameter on: The dispatcher that executes the provided closure.
- Parameter body: The handler to execute if this promise is rejected.
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
*/
func recover<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> U) -> Promise<T> where U.T == T {
func recover<U: Thenable>(on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> U) -> Promise<T> where U.T == T {
let rp = Promise<U.T>(.pending)
pipe {
switch $0 {
case .fulfilled(let value):
rp.box.seal(.fulfilled(value))
case .rejected(let error):
if policy == .allErrors || !error.isCancelled {
on.async(flags: flags) {
on.dispatch {
do {
let rv = try body(error)
guard rv !== rp else { throw PMKError.returnedSelf }
Expand All @@ -101,19 +101,19 @@ public extension CatchMixin {
The provided closure executes when this promise rejects.
This variant of `recover` requires the handler to return a Guarantee, thus it returns a Guarantee itself and your closure cannot `throw`.
- Note it is logically impossible for this to take a `catchPolicy`, thus `allErrors` are handled.
- Parameter on: The queue to which the provided closure dispatches.
- Parameter on: The dispatcher that executes the provided closure.
- Parameter body: The handler to execute if this promise is rejected.
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
*/
@discardableResult
func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Guarantee<T>) -> Guarantee<T> {
func recover(on: Dispatcher = conf.D.map, _ body: @escaping(Error) -> Guarantee<T>) -> Guarantee<T> {
let rg = Guarantee<T>(.pending)
pipe {
switch $0 {
case .fulfilled(let value):
rg.box.seal(value)
case .rejected(let error):
on.async(flags: flags) {
on.dispatch {
body(error).pipe(to: rg.box.seal)
}
}
Expand All @@ -134,14 +134,14 @@ public extension CatchMixin {
//…
}

- Parameter on: The queue to which the provided closure dispatches.
- Parameter on: The dispatcher that executes the provided closure.
- Parameter body: The closure that executes when this promise resolves.
- Returns: A new promise, resolved with this promise’s resolution.
*/
func ensure(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) -> Promise<T> {
func ensure(on: Dispatcher = conf.D.return, _ body: @escaping () -> Void) -> Promise<T> {
let rp = Promise<T>(.pending)
pipe { result in
on.async(flags: flags) {
on.dispatch {
body()
rp.box.seal(result)
}
Expand All @@ -163,14 +163,14 @@ public extension CatchMixin {
//…
}

- Parameter on: The queue to which the provided closure dispatches.
- Parameter on: The dispatcher that executes the provided closure.
- Parameter body: The closure that executes when this promise resolves.
- Returns: A new promise, resolved with this promise’s resolution.
*/
func ensureThen(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Guarantee<Void>) -> Promise<T> {
func ensureThen(on: Dispatcher = conf.D.return, _ body: @escaping () -> Guarantee<Void>) -> Promise<T> {
let rp = Promise<T>(.pending)
pipe { result in
on.async(flags: flags) {
on.dispatch {
body().done {
rp.box.seal(result)
}
Expand All @@ -180,7 +180,6 @@ public extension CatchMixin {
}



/**
Consumes the Swift unused-result warning.
- Note: You should `catch`, but in situations where you know you don’t need a `catch`, `cauterize` makes your intentions clear.
Expand All @@ -201,19 +200,19 @@ public extension CatchMixin where T == Void {

This variant of `recover` is specialized for `Void` promises and de-errors your chain returning a `Guarantee`, thus you cannot `throw` and you must handle all errors including cancellation.

- Parameter on: The queue to which the provided closure dispatches.
- Parameter on: The dispatcher that executes the provided closure.
- Parameter body: The handler to execute if this promise is rejected.
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
*/
@discardableResult
func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Void) -> Guarantee<Void> {
func recover(on: Dispatcher = conf.D.map, _ body: @escaping(Error) -> Void) -> Guarantee<Void> {
let rg = Guarantee<Void>(.pending)
pipe {
switch $0 {
case .fulfilled:
rg.box.seal(())
case .rejected(let error):
on.async(flags: flags) {
on.dispatch {
body(error)
rg.box.seal(())
}
Expand All @@ -227,19 +226,19 @@ public extension CatchMixin where T == Void {

This variant of `recover` ensures that no error is thrown from the handler and allows specifying a catch policy.

- Parameter on: The queue to which the provided closure dispatches.
- Parameter on: The dispatcher that executes the provided closure.
- Parameter body: The handler to execute if this promise is rejected.
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
*/
func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> Void) -> Promise<Void> {
func recover(on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> Void) -> Promise<Void> {
let rg = Promise<Void>(.pending)
pipe {
switch $0 {
case .fulfilled:
rg.box.seal(.fulfilled(()))
case .rejected(let error):
if policy == .allErrors || !error.isCancelled {
on.async(flags: flags) {
on.dispatch {
do {
rg.box.seal(.fulfilled(try body(error)))
} catch {
Expand Down
10 changes: 8 additions & 2 deletions Sources/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ import Dispatch
We would like it to be, but sadly `Swift` does not expose `dispatch_once` et al. which is what we used to use in order to make the configuration immutable once first used.
*/
public struct PMKConfiguration {
/// The default queues that promises handlers dispatch to
public var Q: (map: DispatchQueue?, return: DispatchQueue?) = (map: DispatchQueue.main, return: DispatchQueue.main)
/// Backward compatibility: default DispatchQueues that promise handlers dispatch to
public var Q: (map: DispatchQueue?, return: DispatchQueue?) {
get { return (map: D.map as? DispatchQueue, return: D.return as? DispatchQueue) }
set { D = (map: newValue.map ?? CurrentThreadDispatcher(), return: newValue.return ?? CurrentThreadDispatcher()) }
}

/// The default Dispatchers that promise handlers dispatch to
public var D: (map: Dispatcher, return: Dispatcher) = (map: DispatchQueue.main, return: DispatchQueue.main)

/// The default catch-policy for all `catch` and `resolve`
public var catchPolicy = CatchPolicy.allErrorsExceptCancellation
Expand Down
Loading