-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- 8.2.0
- 8.1.2
- 8.1.1
- 8.1.0
- 8.0.0
- 7.0.0-rc2
- 7.0.0-rc1
- 7.0.0-alpha3
- 7.0.0-alpha2
- 7.0.0-alpha1
- 6.22.1
- 6.22.0
- 6.21.0
- 6.20.0
- 6.19.0
- 6.18.1
- 6.18.0
- 6.17.1
- 6.17.0
- 6.16.3
- 6.16.2
- 6.16.1
- 6.16.0
- 6.15.3
- 6.15.2
- 6.15.1
- 6.15.0
- 6.14.0
- 6.13.3
- 6.13.2
- 6.13.1
- 6.13.0
- 6.12.0
- 6.11.0
- 6.10.0
- 6.9.0
- 6.8.5
- 6.8.4
- 6.8.3
- 6.8.2
- 6.8.1
- 6.8.0
- 6.7.1
- 6.7.0
- 6.6.1
- 6.6.0
- 6.5.3
- 6.5.2
- 6.5.1
- 6.5.0
- 6.4.1
- 6.4.0
- 6.3.5
- 6.3.4
- 6.3.3
- 6.3.2
- 6.3.1
- 6.3.0
- 6.2.9
- 6.2.8
- 6.2.7
- 6.2.6
- 6.2.5
- 6.2.4
- 6.2.3
- 6.2.2
- 6.2.1
- 6.2.0
- 6.1.2
- 6.1.1
- 6.1.0
- 6.0.3
- 6.0.2
- 6.0.1
- 6.0.0
- 5.0.6
- 5.0.5
- 5.0.4
- 5.0.3
- 5.0.2
- 5.0.1
- 5.0.0
Showing
86 changed files
with
1,790 additions
and
2,608 deletions.
There are no files selected for viewing
Submodule AVFoundation
updated
4 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+3 −5 | Sources/AVAudioSession+Promise.swift | |
+9 −1 | Tests/TestAVFoundation.swift |
Submodule Accounts
updated
4 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+8 −8 | Sources/ACAccountStore+Promise.swift | |
+4 −4 | Tests/TestAccounts.swift |
Submodule AddressBook
updated
4 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+6 −6 | Sources/ABAddressBookRequestAccess+Promise.swift | |
+3 −2 | Tests/TestAddressBook.swift |
Submodule Alamofire
updated
from 33bd93 to 4466b9
Submodule AssetsLibrary
updated
4 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+10 −10 | Sources/ALAssetsLibrary+Promise.swift | |
+1 −1 | Tests/app.swift |
Submodule Bolts
updated
4 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+7 −26 | Sources/BFTask+Promise.swift | |
+1 −1 | Tests/TestBolts.swift |
Submodule CloudKit
updated
5 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+8 −8 | Sources/CKContainer+Promise.swift | |
+14 −14 | Sources/CKDatabase+Promise.swift | |
+17 −12 | Tests/TestCloudKit.swift |
Submodule CoreBluetooth
updated
3 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+7 −8 | Sources/CBCentralManager+Promise.swift |
Submodule CoreLocation
updated
9 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+1 −0 | Cartfile.resolved | |
+1 −1 | README.markdown | |
+0 −4 | Sources/CLGeocoder+AnyPromise.m | |
+14 −40 | Sources/CLGeocoder+Promise.swift | |
+32 −60 | Sources/CLLocationManager+Promise.swift | |
+12 −12 | Tests/CLGeocoderTests.swift | |
+4 −17 | Tests/CLLocationManagerTests.swift |
Submodule EventKit
updated
from 35da7f to a11691
Submodule Foundation
updated
17 files
+1 −1 | Cartfile | |
+1 −1 | Cartfile.resolved | |
+0 −4 | PMKFoundation.xcodeproj/project.pbxproj | |
+0 −8 | PMKFoundation.xcodeproj/xcshareddata/xcschemes/PMKFoundation.xcscheme | |
+10 −1 | Package.swift | |
+4 −4 | README.markdown | |
+9 −21 | Sources/NSNotificationCenter+Promise.swift | |
+5 −12 | Sources/NSObject+Promise.swift | |
+13 −0 | Sources/NSURLSession+AnyPromise.h | |
+162 −14 | Sources/NSURLSession+Promise.swift | |
+61 −92 | Sources/Process+Promise.swift | |
+0 −121 | Sources/URLDataPromise.swift | |
+3 −3 | Sources/afterlife.swift | |
+3 −4 | Tests/TestNSNotificationCenter.swift | |
+10 −10 | Tests/TestNSObject.swift | |
+14 −7 | Tests/TestNSTask.swift | |
+9 −5 | Tests/TestNSURLSession.swift |
Submodule MapKit
updated
6 files
+1 −0 | .gitignore | |
+1 −1 | Cartfile | |
+1 −1 | README.markdown | |
+3 −3 | Sources/MKDirections+Promise.swift | |
+2 −2 | Sources/MKMapSnapshotter+Promise.swift | |
+3 −3 | Tests/TestMapKit.swift |
Submodule MessagesUI
updated
6 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+1 −1 | README.markdown | |
+7 −7 | Sources/MFMailComposeViewController+Promise.swift | |
+6 −6 | Sources/MFMessageComposeViewController+Promise.swift | |
+4 −4 | Tests/TestMessageUI.swift |
Submodule OMGHTTPURLRQ
updated
from 111d2b to 97bcc0
Submodule Photos
updated
4 files
+1 −1 | Cartfile | |
+1 −1 | README.markdown | |
+2 −2 | Sources/PHPhotoLibrary+Promise.swift | |
+1 −1 | Tests/PHPhototLibraryTests.swift |
Submodule QuartzCore
updated
3 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+21 −8 | PMKQuartzCore.xcodeproj/project.pbxproj |
Submodule Social
updated
6 files
+1 −1 | .gitignore | |
+2 −2 | Cartfile | |
+1 −1 | README.markdown | |
+4 −4 | Sources/SLComposeViewController+Promise.swift | |
+14 −4 | Sources/SLRequest+Promise.swift | |
+3 −3 | Tests/TestSocial.swift |
Submodule StoreKit
updated
6 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+7 −7 | Sources/SKPayment+Promise.swift | |
+12 −12 | Sources/SKProductsRequest+Promise.swift | |
+8 −8 | Sources/SKReceiptRefreshRequest+Promise.swift | |
+2 −23 | Tests/TestStoreKit.swift |
Submodule UIKit
updated
16 files
+22 −30 | .travis.yml | |
+1 −1 | Cartfile | |
+1 −0 | Cartfile.resolved | |
+0 −12 | PMKUIKit.xcodeproj/project.pbxproj | |
+3 −0 | PMKUIKit.xcodeproj/xcshareddata/xcschemes/PMKUIKit.xcscheme | |
+6 −4 | README.markdown | |
+6 −0 | Sources/PMKUIKit.h | |
+7 −37 | Sources/UIImagePickerController+Promise.swift | |
+7 −3 | Sources/UIView+Promise.swift | |
+3 −3 | Sources/UIViewController+AnyPromise.m | |
+0 −111 | Sources/UIViewController+Promise.swift | |
+3 −30 | Tests/TestUIImagePickerController.swift | |
+2 −2 | Tests/TestUIView.swift | |
+0 −99 | Tests/TestUIViewController.swift | |
+5 −0 | UITests/TestUIImagePickerController.swift | |
+3 −3 | UITests/app.swift |
Submodule WatchConnectivity
updated
4 files
+1 −1 | .gitignore | |
+1 −1 | Cartfile | |
+3 −3 | Sources/WCSession+Promise.swift | |
+2 −2 | Tests/TestWatchConnectivity.swift |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ Pod::Spec.new do |s| | |
|
||
`xcodebuild -project PromiseKit.xcodeproj -showBuildSettings` =~ /CURRENT_PROJECT_VERSION = ((\d\.)+\d)/ | ||
abort("No version detected") if $1.nil? | ||
abort("Not tagged") unless `git tag`.split.include? $1 | ||
s.version = $1 | ||
|
||
s.source = { | ||
|
@@ -19,7 +18,7 @@ Pod::Spec.new do |s| | |
s.social_media_url = 'https://twitter.com/mxcl' | ||
s.authors = { 'Max Howell' => '[email protected]' } | ||
s.documentation_url = 'http://promisekit.org/docs/' | ||
s.default_subspecs = 'Foundation', 'UIKit', 'QuartzCore' | ||
s.default_subspecs = 'CorePromise' | ||
s.requires_arc = true | ||
|
||
# CocoaPods requires us to specify the root deployment targets | ||
|
@@ -29,6 +28,10 @@ Pod::Spec.new do |s| | |
s.osx.deployment_target = '10.11' | ||
s.watchos.deployment_target = '2.0' | ||
s.tvos.deployment_target = '9.0' | ||
|
||
s.pod_target_xcconfig = { | ||
'OTHER_SWIFT_FLAGS' => '-DPMKCocoaPods', | ||
} | ||
|
||
s.subspec 'Accounts' do |ss| | ||
ss.ios.source_files = ss.osx.source_files = 'Extensions/Accounts/Sources/*' | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
PromiseKit.xcodeproj/xcshareddata/xcschemes/PromiseKit.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import Dispatch | ||
|
||
enum Sealant<R> { | ||
case pending(Handlers<R>) | ||
case resolved(R) | ||
} | ||
|
||
class Handlers<R> { | ||
var bodies: [(R) -> Void] = [] | ||
func append(_ item: @escaping(R) -> Void) { bodies.append(item) } | ||
} | ||
|
||
/// - Remark: not protocol ∵ http://www.russbishop.net/swift-associated-types-cont | ||
class Box<T> { | ||
func inspect() -> Sealant<T> { fatalError() } | ||
func inspect(_: (Sealant<T>) -> Void) { fatalError() } | ||
func seal(_: T) {} | ||
} | ||
|
||
class SealedBox<T>: Box<T> { | ||
let value: T | ||
|
||
init(value: T) { | ||
self.value = value | ||
} | ||
|
||
override func inspect() -> Sealant<T> { | ||
return .resolved(value) | ||
} | ||
} | ||
|
||
class EmptyBox<T>: Box<T> { | ||
private var sealant = Sealant<T>.pending(.init()) | ||
private let barrier = DispatchQueue(label: "org.promisekit.barrier", attributes: .concurrent) | ||
|
||
override func seal(_ value: T) { | ||
var handlers: Handlers<T>! | ||
barrier.sync(flags: .barrier) { | ||
guard case .pending(let _handlers) = self.sealant else { | ||
return // already fulfilled! | ||
} | ||
handlers = _handlers | ||
self.sealant = .resolved(value) | ||
} | ||
|
||
//FIXME we are resolved so should `pipe(to:)` be called at this instant, “thens are called in order” would be invalid | ||
//NOTE we don’t do this in the above `sync` because that could potentially deadlock | ||
//THOUGH since `then` etc. typically invoke after a run-loop cycle, this issue is somewhat less severe | ||
|
||
if let handlers = handlers { | ||
handlers.bodies.forEach{ $0(value) } | ||
} | ||
|
||
//TODO solution is an unfortunate third state “sealed” where then's get added | ||
// to a separate handler pool for that state | ||
// any other solution has potential races | ||
} | ||
|
||
override func inspect() -> Sealant<T> { | ||
var rv: Sealant<T>! | ||
barrier.sync { | ||
rv = self.sealant | ||
} | ||
return rv | ||
} | ||
|
||
override func inspect(_ body: (Sealant<T>) -> Void) { | ||
var sealed = false | ||
barrier.sync(flags: .barrier) { | ||
switch sealant { | ||
case .pending: | ||
// body will append to handlers, so we must stay barrier’d | ||
body(sealant) | ||
case .resolved: | ||
sealed = true | ||
} | ||
} | ||
if sealed { | ||
// we do this outside the barrier to prevent potential deadlocks | ||
// it's safe because we never transition away from this state | ||
body(sealant) | ||
} | ||
} | ||
} | ||
|
||
|
||
extension Optional where Wrapped: DispatchQueue { | ||
func async(_ body: @escaping() -> Void) { | ||
switch self { | ||
case .none: | ||
body() | ||
case .some(let q): | ||
q.async(execute: body) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import Dispatch | ||
|
||
public protocol CatchMixin: Thenable | ||
{} | ||
|
||
public extension CatchMixin { | ||
@discardableResult | ||
func `catch`(on: DispatchQueue? = conf.Q.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 { | ||
body(error) | ||
finalizer.pending.resolve(()) | ||
} | ||
case .fulfilled: | ||
finalizer.pending.resolve(()) | ||
} | ||
} | ||
return finalizer | ||
} | ||
} | ||
|
||
public class PMKFinalizer { | ||
let pending = Guarantee<Void>.pending() | ||
|
||
public func finally(_ body: @escaping () -> Void) { | ||
pending.guarantee.done(body) | ||
} | ||
} | ||
|
||
|
||
public extension CatchMixin { | ||
func recover<U: Thenable>(on: DispatchQueue? = conf.Q.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 { | ||
do { | ||
let rv = try body(error) | ||
guard rv !== rp else { throw PMKError.returnedSelf } | ||
rv.pipe(to: rp.box.seal) | ||
} catch { | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
} else { | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
} | ||
return rp | ||
} | ||
|
||
/// recover into a Guarantee, note it is logically impossible for this to take a catchPolicy, thus allErrors are handled | ||
@discardableResult | ||
func recover(on: DispatchQueue? = conf.Q.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 { | ||
body(error).pipe(to: rg.box.seal) | ||
} | ||
} | ||
} | ||
return rg | ||
} | ||
|
||
func ensure(on: DispatchQueue? = conf.Q.return, _ body: @escaping () -> Void) -> Promise<T> { | ||
let rp = Promise<T>(.pending) | ||
pipe { result in | ||
on.async { | ||
body() | ||
rp.box.seal(result) | ||
} | ||
} | ||
return rp | ||
} | ||
|
||
func cauterize() { | ||
self.catch { | ||
print("PromiseKit:cauterized-error:", $0) | ||
} | ||
} | ||
} | ||
|
||
|
||
public extension CatchMixin where T == Void { | ||
@discardableResult | ||
func recover(on: DispatchQueue? = conf.Q.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 { | ||
body(error) | ||
rg.box.seal(()) | ||
} | ||
} | ||
} | ||
return rg | ||
} | ||
|
||
func recover(on: DispatchQueue? = conf.Q.map, _ 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): | ||
on.async { | ||
do { | ||
rg.box.seal(.fulfilled(try body(error))) | ||
} catch { | ||
rg.box.seal(.rejected(error)) | ||
} | ||
} | ||
} | ||
} | ||
return rg | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import Dispatch | ||
|
||
public struct PMKConfiguration { | ||
/// the default queues that promises handlers dispatch to | ||
public var Q = (map: DispatchQueue.main, return: DispatchQueue.main) | ||
|
||
public var catchPolicy = CatchPolicy.allErrorsExceptCancellation | ||
} | ||
|
||
//TODO disallow modification of this after first promise instantiation | ||
//TODO this should be per module too, eg. frameworks you use that provide promises | ||
// should be confident about the queues their code runs on | ||
public var conf = PMKConfiguration() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
extension Promise: CustomStringConvertible { | ||
public var description: String { | ||
switch result { | ||
case nil: | ||
return "Promise(…\(T.self))" | ||
case .rejected(let error)?: | ||
return "Promise(\(error))" | ||
case .fulfilled(let value)?: | ||
return "Promise(\(value))" | ||
} | ||
} | ||
} | ||
|
||
extension Promise: CustomDebugStringConvertible { | ||
public var debugDescription: String { | ||
switch box.inspect() { | ||
case .pending(let handlers): | ||
return "Promise<\(T.self)>.pending(handlers: \(handlers.bodies.count))" | ||
case .resolved(.rejected(let error)): | ||
return "Promise<\(T.self)>.rejected(\(type(of: error)).\(error))" | ||
case .resolved(.fulfilled(let value)): | ||
return "Promise<\(T.self)>.fulfilled(\(value))" | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import class Foundation.Thread | ||
import Dispatch | ||
|
||
public class Guarantee<T>: Thenable { | ||
let box: Box<T> | ||
|
||
public init(value: T) { | ||
box = SealedBox(value: value) | ||
} | ||
|
||
public init(_: PMKUnambiguousInitializer, resolver body: (@escaping(T) -> Void) -> Void) { | ||
box = EmptyBox() | ||
body(box.seal) | ||
} | ||
|
||
public func pipe(to: @escaping(Result<T>) -> Void) { | ||
pipe{ to(.fulfilled($0)) } | ||
} | ||
|
||
func pipe(to: @escaping(T) -> Void) { | ||
switch box.inspect() { | ||
case .pending: | ||
box.inspect { | ||
switch $0 { | ||
case .pending(let handlers): | ||
handlers.append(to) | ||
case .resolved(let value): | ||
to(value) | ||
} | ||
} | ||
case .resolved(let value): | ||
to(value) | ||
} | ||
} | ||
|
||
public var result: Result<T>? { | ||
switch box.inspect() { | ||
case .pending: | ||
return nil | ||
case .resolved(let value): | ||
return .fulfilled(value) | ||
} | ||
} | ||
|
||
init(_: PMKUnambiguousInitializer) { | ||
box = EmptyBox() | ||
} | ||
|
||
public class func pending() -> (guarantee: Guarantee<T>, resolve: (T) -> Void) { | ||
return { ($0, $0.box.seal) }(Guarantee<T>(.pending)) | ||
} | ||
} | ||
|
||
public extension Guarantee { | ||
@discardableResult | ||
func done(on: DispatchQueue? = conf.Q.return, _ body: @escaping(T) -> Void) -> Guarantee<Void> { | ||
let rg = Guarantee<Void>(.pending) | ||
pipe { (value: T) in | ||
on.async { | ||
body(value) | ||
rg.box.seal(()) | ||
} | ||
} | ||
return rg | ||
} | ||
|
||
func map<U>(on: DispatchQueue? = conf.Q.map, _ body: @escaping(T) -> U) -> Guarantee<U> { | ||
let rg = Guarantee<U>(.pending) | ||
pipe { value in | ||
on.async { | ||
rg.box.seal(body(value)) | ||
} | ||
} | ||
return rg | ||
} | ||
|
||
@discardableResult | ||
func then<U>(on: DispatchQueue? = conf.Q.map, _ body: @escaping(T) -> Guarantee<U>) -> Guarantee<U> { | ||
let rg = Guarantee<U>(.pending) | ||
pipe { value in | ||
on.async { | ||
body(value).pipe(to: rg.box.seal) | ||
} | ||
} | ||
return rg | ||
} | ||
|
||
public func asVoid() -> Guarantee<Void> { | ||
return map(on: nil) { _ in } | ||
} | ||
|
||
/** | ||
Blocks this thread, so you know, don’t call this on a serial thread that | ||
any part of your chain may use. Like the main thread for example. | ||
*/ | ||
public func wait() -> T { | ||
|
||
if Thread.isMainThread { | ||
print("PromiseKit: warning: `wait()` called on main thread!") | ||
} | ||
|
||
var result = value | ||
|
||
if result == nil { | ||
let group = DispatchGroup() | ||
group.enter() | ||
pipe { (foo: T) in result = foo; group.leave() } | ||
group.wait() | ||
} | ||
|
||
return result! | ||
} | ||
} | ||
|
||
#if swift(>=3.1) | ||
public extension Guarantee where T == Void { | ||
convenience init() { | ||
self.init(value: Void()) | ||
} | ||
} | ||
#endif | ||
|
||
|
||
public extension DispatchQueue { | ||
/** | ||
Asynchronously executes the provided closure on a dispatch queue. | ||
|
||
DispatchQueue.global().async(.promise) { | ||
md5(input) | ||
}.done { md5 in | ||
//… | ||
} | ||
|
||
- Parameter body: The closure that resolves this promise. | ||
- Returns: A new `Guarantee` resolved by the result of the provided closure. | ||
- Note: There is no Promise/Thenable version of this due to Swift compiler ambiguity issues. | ||
*/ | ||
final func async<T>(_: PMKNamespacer, group: DispatchGroup? = nil, qos: DispatchQoS = .default, flags: DispatchWorkItemFlags = [], execute body: @escaping () -> T) -> Guarantee<T> { | ||
let rg = Guarantee<T>(.pending) | ||
async(group: group, qos: qos, flags: flags) { | ||
rg.box.seal(body()) | ||
} | ||
return rg | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
public class Resolver<T> { | ||
let box: Box<Result<T>> | ||
|
||
init(_ box: Box<Result<T>>) { | ||
self.box = box | ||
} | ||
|
||
deinit { | ||
if case .pending = box.inspect() { | ||
print("PromiseKit: warning: pending promise deallocated") | ||
} | ||
} | ||
} | ||
|
||
public extension Resolver { | ||
func fulfill(_ value: T) { | ||
box.seal(.fulfilled(value)) | ||
} | ||
|
||
func reject(_ error: Error) { | ||
box.seal(.rejected(error)) | ||
} | ||
|
||
public func resolve(_ result: Result<T>) { | ||
box.seal(result) | ||
} | ||
|
||
public func resolve(_ obj: T?, _ error: Error?) { | ||
if let error = error { | ||
reject(error) | ||
} else if let obj = obj { | ||
fulfill(obj) | ||
} else { | ||
reject(PMKError.invalidCallingConvention) | ||
} | ||
} | ||
|
||
public func resolve(_ obj: T, _ error: Error?) { | ||
if let error = error { | ||
reject(error) | ||
} else { | ||
fulfill(obj) | ||
} | ||
} | ||
|
||
public func resolve(_ error: Error?, _ obj: T?) { | ||
resolve(obj, error) | ||
} | ||
} | ||
|
||
#if swift(>=3.1) | ||
extension Resolver where T == Void { | ||
public func resolve(_ error: Error?) { | ||
if let error = error { | ||
reject(error) | ||
} else { | ||
fulfill(()) | ||
} | ||
} | ||
} | ||
#endif | ||
|
||
public enum Result<T> { | ||
case fulfilled(T) | ||
case rejected(Error) | ||
} | ||
|
||
public extension PromiseKit.Result { | ||
var isFulfilled: Bool { | ||
switch self { | ||
case .fulfilled: | ||
return true | ||
case .rejected: | ||
return false | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
import Dispatch | ||
|
||
|
||
//TODO fire off a message to the Queue's runloop to avoid zalgo | ||
// if no runloop, show warning about zalgo | ||
// in case of `nil` don't do that and also don't dispatch to queue later | ||
// in caes of `main` we can optimize and avoid a dispatch if we're on the main queue and zalgo was avoided | ||
|
||
|
||
public protocol Thenable: class { | ||
associatedtype T | ||
func pipe(to: @escaping(Result<T>) -> Void) | ||
var result: Result<T>? { get } | ||
} | ||
|
||
public extension Thenable { | ||
public func then<U: Thenable>(on: DispatchQueue? = conf.Q.map, file: StaticString = #file, line: UInt = #line, _ body: @escaping(T) throws -> U) -> Promise<U.T> { | ||
let rp = Promise<U.T>(.pending) | ||
pipe { | ||
switch $0 { | ||
case .fulfilled(let value): | ||
on.async { | ||
do { | ||
let rv = try body(value) | ||
guard rv !== rp else { throw PMKError.returnedSelf } | ||
rv.pipe(to: rp.box.seal) | ||
} catch { | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
case .rejected(let error): | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
return rp | ||
} | ||
|
||
func map<U>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T) throws -> U) -> Promise<U> { | ||
let rp = Promise<U>(.pending) | ||
pipe { | ||
switch $0 { | ||
case .fulfilled(let value): | ||
on.async { | ||
do { | ||
rp.box.seal(.fulfilled(try transform(value))) | ||
} catch { | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
case .rejected(let error): | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
return rp | ||
} | ||
|
||
func flatMap<U>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T) throws -> U?) -> Promise<U> { | ||
let rp = Promise<U>(.pending) | ||
pipe { | ||
switch $0 { | ||
case .fulfilled(let value): | ||
on.async { | ||
do { | ||
if let rv = try transform(value) { | ||
rp.box.seal(.fulfilled(rv)) | ||
} else { | ||
throw PMKError.flatMap(value, U.self) | ||
} | ||
} catch { | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
case .rejected(let error): | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
return rp | ||
} | ||
|
||
func done(on: DispatchQueue? = conf.Q.return, _ body: @escaping(T) throws -> Void) -> Promise<Void> { | ||
let rp = Promise<Void>(.pending) | ||
pipe { | ||
switch $0 { | ||
case .fulfilled(let value): | ||
on.async { | ||
do { | ||
try body(value) | ||
rp.box.seal(.fulfilled(())) | ||
} catch { | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
case .rejected(let error): | ||
rp.box.seal(.rejected(error)) | ||
} | ||
} | ||
return rp | ||
} | ||
|
||
/// Immutably access the fulfilled value; the returned Promise maintains that value. | ||
func get(_ body: @escaping (T) throws -> Void) -> Promise<T> { | ||
return map(on: PromiseKit.conf.Q.return) { | ||
try body($0) | ||
return $0 | ||
} | ||
} | ||
|
||
public func asVoid() -> Promise<Void> { | ||
return map(on: nil) { _ in } | ||
} | ||
} | ||
|
||
public extension Thenable { | ||
/** | ||
- Returns: The error with which this promise was rejected; `nil` if this promise is not rejected. | ||
*/ | ||
var error: Error? { | ||
switch result { | ||
case .none: | ||
return nil | ||
case .some(.fulfilled): | ||
return nil | ||
case .some(.rejected(let error)): | ||
return error | ||
} | ||
} | ||
|
||
/** | ||
- Returns: `true` if the promise has not yet resolved. | ||
*/ | ||
var isPending: Bool { | ||
return result == nil | ||
} | ||
|
||
/** | ||
- Returns: `true` if the promise has resolved. | ||
*/ | ||
var isResolved: Bool { | ||
return !isPending | ||
} | ||
|
||
/** | ||
- Returns: `true` if the promise was fulfilled. | ||
*/ | ||
var isFulfilled: Bool { | ||
return value != nil | ||
} | ||
|
||
/** | ||
- Returns: `true` if the promise was rejected. | ||
*/ | ||
var isRejected: Bool { | ||
return error != nil | ||
} | ||
|
||
/** | ||
- Returns: The value with which this promise was fulfilled or `nil` if this promise is pending or rejected. | ||
*/ | ||
var value: T? { | ||
switch result { | ||
case .none: | ||
return nil | ||
case .some(.fulfilled(let value)): | ||
return value | ||
case .some(.rejected): | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
public extension Thenable where T: Sequence { | ||
func map<U>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]> { | ||
return map(on: on){ try $0.map(transform) } | ||
} | ||
|
||
func thenMap<U: Thenable>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T]> { | ||
return then(on: on) { | ||
when(fulfilled: try $0.map(transform)) | ||
} | ||
} | ||
|
||
func flatMap<U>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U?) -> Promise<[U]> { | ||
return map(on: on){ try $0.flatMap(transform) } | ||
} | ||
|
||
func thenFlatMap<U: Thenable>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T.Iterator.Element]> where U.T: Sequence { | ||
return then(on: on){ | ||
when(fulfilled: try $0.map(transform)) | ||
}.map(on: nil) { | ||
$0.flatMap{ $0 } | ||
} | ||
} | ||
|
||
func filter(on: DispatchQueue? = conf.Q.map, test: @escaping (T.Iterator.Element) -> Bool) -> Promise<[T.Iterator.Element]> { | ||
return map(on: on) { $0.filter(test) } | ||
} | ||
} | ||
|
||
public extension Thenable where T: Collection { | ||
var first: Promise<T.Iterator.Element> { | ||
return map(on: nil) { aa in | ||
if let a1 = aa.first { | ||
return a1 | ||
} else { | ||
throw PMKError.badInput | ||
} | ||
} | ||
} | ||
|
||
var last: Promise<T.Iterator.Element> { | ||
return map(on: nil) { aa in | ||
if aa.isEmpty { | ||
throw PMKError.badInput | ||
} else { | ||
let i = aa.index(aa.endIndex, offsetBy: -1) | ||
return aa[i] | ||
} | ||
} | ||
} | ||
} | ||
|
||
public extension Thenable where T: Sequence, T.Iterator.Element: Comparable { | ||
func sorted(on: DispatchQueue? = conf.Q.map) -> Promise<[T.Iterator.Element]> { | ||
return map(on: on){ $0.sorted() } | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,38 @@ | ||
import struct Foundation.TimeInterval | ||
import Dispatch | ||
|
||
/** | ||
- Returns: A new promise that fulfills after the specified duration. | ||
*/ | ||
@available(*, deprecated: 4.3, message: "Use after(seconds:)") | ||
public func after(interval: TimeInterval) -> Promise<Void> { | ||
return after(seconds: interval) | ||
} | ||
|
||
/** | ||
after(.seconds(2)).then { | ||
//… | ||
} | ||
|
||
- Returns: A new promise that fulfills after the specified duration. | ||
*/ | ||
public func after(seconds: TimeInterval) -> Promise<Void> { | ||
return Promise { fulfill, _ in | ||
let when = DispatchTime.now() + seconds | ||
DispatchQueue.global().asyncAfter(deadline: when) { fulfill(()) } | ||
} | ||
public func after(seconds: TimeInterval) -> Guarantee<Void> { | ||
let (rg, seal) = Guarantee<Void>.pending() | ||
let when = DispatchTime.now() + seconds | ||
#if swift(>=4.0) | ||
DispatchQueue.global().asyncAfter(deadline: when) { seal(()) } | ||
#else | ||
DispatchQueue.global().asyncAfter(deadline: when, execute: seal) | ||
#endif | ||
return rg | ||
} | ||
|
||
/** | ||
after(seconds: 1.5).then { | ||
//… | ||
} | ||
|
||
- Returns: A new promise that fulfills after the specified duration. | ||
*/ | ||
public func after(interval: DispatchTimeInterval) -> Promise<Void> { | ||
return Promise { fulfill, _ in | ||
let when = DispatchTime.now() + interval | ||
#if swift(>=4.0) | ||
DispatchQueue.global().asyncAfter(deadline: when) { fulfill(()) } | ||
#else | ||
DispatchQueue.global().asyncAfter(deadline: when, execute: fulfill) | ||
#endif | ||
} | ||
public func after(_ interval: DispatchTimeInterval) -> Guarantee<Void> { | ||
let (rg, seal) = Guarantee<Void>.pending() | ||
let when = DispatchTime.now() + interval | ||
#if swift(>=4.0) | ||
DispatchQueue.global().asyncAfter(deadline: when) { seal(()) } | ||
#else | ||
DispatchQueue.global().asyncAfter(deadline: when, execute: seal) | ||
#endif | ||
return rg | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import Dispatch | ||
|
||
/** | ||
Judicious use of `firstly` *may* make chains more readable. | ||
|
||
Compare: | ||
|
||
URLSession.shared.dataTask(url: url1).then { | ||
URLSession.shared.dataTask(url: url2) | ||
}.then { | ||
URLSession.shared.dataTask(url: url3) | ||
} | ||
|
||
With: | ||
|
||
firstly { | ||
URLSession.shared.dataTask(url: url1) | ||
}.then { | ||
URLSession.shared.dataTask(url: url2) | ||
}.then { | ||
URLSession.shared.dataTask(url: url3) | ||
} | ||
*/ | ||
public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> { | ||
do { | ||
let rp = Promise<U.T>(.pending) | ||
try body().pipe(to: rp.box.seal) | ||
return rp | ||
} catch { | ||
return Promise(error: error) | ||
} | ||
} | ||
|
||
/// - See: firstly() | ||
public func firstly<T>(execute body: () -> Guarantee<T>) -> Guarantee<T> { | ||
return body() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.