This commit is contained in:
Anthony Shoumikhin committed 2018-01-19 01:11:34 -08:00
commit 543d70a02d
139 files changed
+12415

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
BasedOnStyle: Google
AlignOperands: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
BreakBeforeTernaryOperators: false
ColumnLimit: 100
PointerBindsToType: false
+98
View File
@@ -0,0 +1,98 @@
# Generic build products
*.[oa]
[Bb]uild/
[Pp]re-[Bb]uild/
[Dd]eliverables/
[Dd]istribution/
[Dd]ocumentation/
[Dd]ocs/
# Swift PM
Packages/
.build/
*.xcodeproj
*.resolved
# Bazel
bazel-*
# Other VCS
.hg
.svn
*.prej
*.mine
CVS
# OSX
.DS_Store
.DS_Store?
._*
.~*
~$*
*.lock
.AppleDouble
.LSOverride
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
ehthumbs.db
Thumbs.db
.AppleDB
.AppleDesktop
.apdisk
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp
*.lnk
# Xcode
DerivedData/
xcuserdata/
project.xcworkspace/
*.mode1
*.mode1v3
*.mode2v3
*.perspective
*.perspectivev3
*.pbxuser
*.xccheckout
*.moved-aside
*.xcuserstate
*.xctimeline
# JetBrains
.idea/
# CocoaPods
!Podfile.lock
!Pods/Manifest.lock
Pods/Documentation
#Carthage
Carthage/
# SublimeText
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
+100
View File
@@ -0,0 +1,100 @@
syntax: glob
# Generic build products
*.[oa]
[Bb]uild/
[Pp]re-[Bb]uild/
[Dd]eliverables/
[Dd]istribution/
[Dd]ocumentation/
[Dd]ocs/
# Swift PM
Packages/
.build/
*.xcodeproj
*.resolved
# Bazel
bazel-*
# Other VCS
.hg
.svn
*.prej
*.mine
CVS
# OSX
.DS_Store
.DS_Store?
._*
.~*
~$*
*.lock
.AppleDouble
.LSOverride
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
ehthumbs.db
Thumbs.db
.AppleDB
.AppleDesktop
.apdisk
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp
*.lnk
# Xcode
DerivedData/
xcuserdata/
project.xcworkspace/
*.mode1
*.mode1v3
*.mode2v3
*.perspective
*.perspectivev3
*.pbxuser
*.xccheckout
*.moved-aside
*.xcuserstate
*.xctimeline
# JetBrains
.idea/
# CocoaPods
!Podfile.lock
!Pods/Manifest.lock
Pods/Documentation
#Carthage
Carthage/
# SublimeText
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
+18
View File
@@ -0,0 +1,18 @@
disabled_rules:
- xctfail_message
line_length: 100
function_body_length:
warning: 100
error: 200
type_body_length:
warning: 500
error: 1000
file_length:
warning: 1000
error: 2000
nesting:
type_level:
warning: 3
error: 5
cyclomatic_complexity: 15
+172
View File
@@ -0,0 +1,172 @@
package(default_visibility = ["//visibility:public"])
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
load("@build_bazel_rules_apple//apple:swift.bzl", "swift_library")
OBJC_COPTS = [
"-Werror",
"-Wextra",
"-Wall",
"-Wdocumentation",
]
SWIFT_COPTS = [
"-wmo",
]
swift_library(
name = "Promises",
srcs = glob([
"Sources/Promises/*.swift",
]),
copts = SWIFT_COPTS,
module_name = "Promises",
deps = [
":FBLPromises",
],
)
swift_library(
name = "PromisesTestHelpers",
testonly = 1,
srcs = glob([
"Sources/PromisesTestHelpers/*.swift",
]),
copts = SWIFT_COPTS,
module_name = "PromisesTestHelpers",
deps = [
":Promises",
],
)
objc_library(
name = "FBLPromises",
srcs = glob([
"Sources/FBLPromises/*.m",
"Sources/FBLPromises/DotSyntax/*.m",
]),
hdrs = glob([
"Sources/FBLPromises/include/*.h",
"Sources/FBLPromises/include/DotSyntax/*.h",
]) + [
"FBLPromises.h",
],
copts = OBJC_COPTS,
defines = [
"FBL_PROMISES_DOT_SYNTAX_IS_DEPRECATED",
],
includes = [
"Sources/FBLPromises/include",
],
module_map = "Sources/FBLPromises/include/module.modulemap",
)
objc_library(
name = "FBLPromisesTestHelpers",
testonly = 1,
srcs = glob([
"Sources/FBLPromisesTestHelpers/*.m",
]),
hdrs = glob([
"Sources/FBLPromisesTestHelpers/include/*.h",
]),
copts = OBJC_COPTS,
includes = [
"Sources/FBLPromisesTestHelpers/include",
],
module_map = "Sources/FBLPromisesTestHelpers/include/module.modulemap",
deps = [
":FBLPromises",
],
)
ios_unit_test(
name = "Tests",
deps = [
":FBLPromisesInteroperabilityTests",
":FBLPromisesPerformanceTests",
":FBLPromisesTests",
":PromisesInteroperabilityTests",
":PromisesPerformanceTests",
":PromisesTests",
],
)
swift_library(
name = "PromisesTests",
testonly = 1,
srcs = glob([
"Tests/PromisesTests/*.swift",
]),
copts = SWIFT_COPTS,
deps = [
":PromisesTestHelpers",
],
)
swift_library(
name = "PromisesInteroperabilityTests",
testonly = 1,
srcs = glob([
"Tests/PromisesInteroperabilityTests/*.swift",
]),
copts = SWIFT_COPTS,
deps = [
":FBLPromisesTestHelpers",
":PromisesTestHelpers",
],
)
swift_library(
name = "PromisesPerformanceTests",
testonly = 1,
srcs = glob([
"Tests/PromisesPerformanceTests/*.swift",
]),
copts = SWIFT_COPTS,
swift_version = 4,
deps = [
":FBLPromisesTestHelpers",
":PromisesTestHelpers",
],
)
objc_library(
name = "FBLPromisesTests",
testonly = 1,
srcs = glob([
"Tests/FBLPromisesTests/*.m",
]),
copts = OBJC_COPTS,
deps = [
":FBLPromisesTestHelpers",
],
)
objc_library(
name = "FBLPromisesInteroperabilityTests",
testonly = 1,
srcs = glob([
"Tests/FBLPromisesInteroperabilityTests/*.m",
]),
copts = OBJC_COPTS,
includes = [
"../Promises",
],
deps = [
":FBLPromisesTestHelpers",
":PromisesTestHelpers",
],
)
objc_library(
name = "FBLPromisesPerformanceTests",
testonly = 1,
srcs = glob([
"Tests/FBLPromisesPerformanceTests/*.m",
]),
copts = OBJC_COPTS,
deps = [
":FBLPromisesTestHelpers",
],
)
+54
View File
@@ -0,0 +1,54 @@
# How to contribute #
We'd love to accept your patches and contributions to this project. There are
a just a few small guidelines you need to follow.
## Contributor License Agreement ##
Contributions to any Google project must be accompanied by a Contributor
License Agreement. This is not a copyright **assignment**, it simply gives
Google permission to use and redistribute your contributions as part of the
project.
* If you are an individual writing original source code and you're sure you
own the intellectual property, then you'll need to sign an [individual
CLA][].
* If you work for a company that wants to allow you to contribute your work,
then you'll need to sign a [corporate CLA][].
You generally only need to submit a CLA once, so if you've already submitted
one (even if it was for a different project), you probably don't need to do it
again.
[individual CLA]: https://developers.google.com/open-source/cla/individual
[corporate CLA]: https://developers.google.com/open-source/cla/corporate
## Submitting a patch ##
1. It's generally best to start by opening a new issue describing the bug or
feature you're intending to fix. Even if you think it's relatively minor,
it's helpful to know what people are working on. Mention in the initial
issue that you are planning to work on that bug or feature so that it can
be assigned to you.
1. Follow the normal process of [forking][] the project, and setup a new
branch to work in. It's important that each group of changes be done in
separate branches in order to ensure that a pull request only includes the
commits related to that bug or feature.
1. Any significant changes should almost always be accompanied by tests. The
project already has good test coverage, so look at some of the existing
tests if you're unsure how to go about it.
1. Do your best to have [well-formed commit messages][] for each change.
This provides consistency throughout the project, and ensures that commit
messages are able to be formatted properly by various git tools.
1. Finally, push the commits to your fork and submit a [pull request][].
[forking]: https://help.github.com/articles/fork-a-repo
[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[pull request]: https://help.github.com/articles/creating-a-pull-request
+1
View File
@@ -0,0 +1 @@
Sources/FBLPromises/include/FBLPromises.h
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+118
View File
@@ -0,0 +1,118 @@
// swift-tools-version:4.0
// swiftlint:disable line_length
// swiftlint:disable trailing_comma
// To generate and open project in Xcode run:
// swift package -Xswiftc -ISources/FBLPromises/include generate-xcodeproj && open Promises.xcworkspace
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import PackageDescription
let package = Package(
name: "Promises",
products: [
.library(
name: "FBLPromises",
targets: [
"FBLPromises",
]
),
.library(
name: "FBLPromisesTestHelpers",
targets: [
"FBLPromisesTestHelpers",
]
),
.library(
name: "Promises",
targets: [
"Promises",
]
),
.library(
name: "PromisesTestHelpers",
targets: [
"PromisesTestHelpers",
]
),
],
targets: [
.target(
name: "FBLPromises"
),
.target(
name: "FBLPromisesTestHelpers",
dependencies: [
"FBLPromises",
]
),
.testTarget(
name: "FBLPromisesTests",
dependencies: [
"FBLPromisesTestHelpers",
]
),
// Swift Package Manager doesn't support importing Swift in ObjC just yet.
// To work around uncomment the rule below, generate Xcode project and set
// CLANG_ENABLE_MODULES = YES for FBLPromisesInteroperabilityTests target
// to @import PromisesTestHelpers; instead of #import "PromisesTestHelpers-Swift.h".
// .testTarget(
// name: "FBLPromisesInteroperabilityTests",
// dependencies: [
// "FBLPromisesTestHelpers",
// "PromisesTestHelpers",
// ]
// ),
.testTarget(
name: "FBLPromisesPerformanceTests",
dependencies: [
"FBLPromisesTestHelpers",
]
),
.target(
name: "Promises",
dependencies: [
"FBLPromises",
]
),
.target(
name: "PromisesTestHelpers",
dependencies: [
"Promises",
]
),
.testTarget(
name: "PromisesTests",
dependencies: [
"PromisesTestHelpers",
]
),
.testTarget(
name: "PromisesInteroperabilityTests",
dependencies: [
"FBLPromisesTestHelpers",
"PromisesTestHelpers",
]
),
.testTarget(
name: "PromisesPerformanceTests",
dependencies: [
"FBLPromisesTestHelpers",
"PromisesTestHelpers",
]
),
]
)
+50
View File
@@ -0,0 +1,50 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import PlaygroundSupport
import Promises
PlaygroundPage.current.needsIndefiniteExecution = true
enum PlaygroundError: Error {
case invalidNumber
}
func reverse(string: String) -> Promise<String> {
return Promise {
Thread.sleep(forTimeInterval: 0.1)
return String(string.reversed())
}
}
func number(from string: String) -> Promise<Int> {
return Promise {
Thread.sleep(forTimeInterval: 0.1)
guard let number = Int(string) else { throw PlaygroundError.invalidNumber }
return number
}
}
func square(number: Int) -> Int {
return number * number
}
reverse(string: "01").then(number(from:)).then(square(number:)).then {
print($0) // 100
}
number(from: "hello").catch {
print($0) // invalidNumber
}
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos'>
<timeline fileName='timeline.xctimeline'/>
</playground>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Promises.xcodeproj">
</FileRef>
<FileRef
location = "group:Promises.playground">
</FileRef>
</Workspace>
+44
View File
@@ -0,0 +1,44 @@
# Promises
[![Apache
License](https://img.shields.io/badge/license-Apache%202-lightgrey.svg?style=flat)](LICENSE)
Promises is a modern framework that provides a synchronization construct for
Objective-C and Swift that helps simplify writing asynchronous code. The simple
and intuitive API will help make your code cleaner, safer, and more readable.
* [Introduction](g3doc/introduction.md)
* [The problem with async
code](g3doc/introduction.md#the-problem-with-async-code)
* [Promises to the rescue](g3doc/introduction.md#promises-to-the-rescue)
* [What is a promise?](g3doc/introduction.md#what-is-a-promise)
* [Framework](g3doc/framework.md)
* [Features](g3doc/framework.md#features)
* [Benchmark](g3doc/framework.md#benchmark)
* [Getting started](g3doc/integration.md)
* [Add dependency](g3doc/integration.md#add-dependency)
* [Import](g3doc/integration.md#import)
* [Adopt](g3doc/integration.md#adopt)
* [Basics](g3doc/basics.md)
* [Creating promises](g3doc/basics.md#creating-promises)
* [Observing fulfillment](g3doc/basics.md#observing-fulfillment)
* [Observing rejection](g3doc/basics.md#observing-rejection)
* [Extensions](g3doc/extensions.md)
* [All](g3doc/extensions.md#all)
* [Always](g3doc/extensions.md#always)
* [Any](g3doc/extensions.md#any)
* [Recover](g3doc/extensions.md#recover)
* [Resolve](g3doc/extensions.md#resolve)
* [Timeout](g3doc/extensions.md#timeout)
* [Validate](g3doc/extensions.md#validate)
* [When](g3doc/extensions.md#when)
* [Advanced topics](g3doc/advanced.md)
* [Ownership and retain
cycles](g3doc/advanced.md#ownership-and-retain-cycles)
* [Testing](g3doc/advanced.md#testing)
* [Objective-C <-> Swift
interoperability](g3doc/advanced.md#objective-c-wift-interoperability)
* [Dot-syntax in Objective-C](g3doc/advanced.md#dot-syntax-in-objective-c)
* [Anti-patterns](g3doc/anti-patterns.md)
* [Broken chain](g3doc/anti-patterns.md#broken-chain)
* [Nested promises](g3doc/anti-patterns.md#nested-promises)
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+All.h"
@implementation FBLPromise (DotSyntax_AllAdditions)
+ (FBLPromise<NSArray *> * (^)(NSArray *))all {
return ^(NSArray<FBLPromise *> *promises) {
return [self all:promises];
};
}
+ (FBLPromise<NSArray *> * (^)(dispatch_queue_t, NSArray *))allOn {
return ^(dispatch_queue_t queue, NSArray<FBLPromise *> *promises) {
return [self onQueue:queue all:promises];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Always.h"
@implementation FBLPromise (DotSyntax_AlwaysAdditions)
- (FBLPromise* (^)(void (^)(void)))always {
return ^(void (^work)(void)) {
return [self always:work];
};
}
- (FBLPromise* (^)(dispatch_queue_t, void (^)(void)))alwaysOn {
return ^(dispatch_queue_t queue, void (^work)(void)) {
return [self onQueue:queue always:work];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Any.h"
@implementation FBLPromise (DotSyntax_AnyAdditions)
+ (FBLPromise * (^)(NSArray *))any {
return ^(NSArray *promises) {
return [self any:promises];
};
}
+ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn {
return ^(dispatch_queue_t queue, NSArray *promises) {
return [self onQueue:queue any:promises];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Async.h"
@implementation FBLPromise (DotSyntax_AsyncAdditions)
+ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async {
return ^(FBLPromiseAsyncWorkBlock work) {
return [self async:work];
};
}
+ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn {
return ^(dispatch_queue_t queue, FBLPromiseAsyncWorkBlock work) {
return [self onQueue:queue async:work];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Catch.h"
@implementation FBLPromise (DotSyntax_CatchAdditions)
- (FBLPromise* (^)(FBLPromiseCatchBlock))catch {
return ^(FBLPromiseCatchBlock catch) {
return [self catch:catch];
};
}
- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchBlock))catchOn {
return ^(dispatch_queue_t queue, FBLPromiseCatchBlock catch) {
return [self onQueue:queue catch:catch];
};
}
@end
@@ -0,0 +1,27 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Do.h"
@implementation FBLPromise (DotSyntax_DoAdditions)
+ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn {
return ^(dispatch_queue_t queue, FBLPromiseDoWorkBlock work) {
return [self onQueue:queue do:work];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Recover.h"
@implementation FBLPromise (DotSyntax_RecoverAdditions)
- (FBLPromise * (^)(id __nullable (^)(NSError *)))recover {
return ^(FBLPromise * (^recovery)(NSError *)) {
return [self recover:recovery];
};
}
- (FBLPromise * (^)(dispatch_queue_t, id __nullable (^)(NSError *)))recoverOn {
return ^(dispatch_queue_t queue, id __nullable (^recovery)(NSError *)) {
return [self onQueue:queue recover:recovery];
};
}
@end
@@ -0,0 +1,91 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Resolve.h"
@implementation FBLPromise (DotSyntax_ResolveAdditions)
+ (FBLPromise * (^)(void (^)(FBLPromiseCompletion)))resolveWhen {
return ^(void (^work)(FBLPromiseCompletion)) {
return [self resolveWhenCompleted:work];
};
}
+ (FBLPromise * (^)(void (^)(FBLPromiseObjectCompletion)))resolveWithObjectWhen {
return ^(void (^work)(FBLPromiseObjectCompletion)) {
return [self resolveWithObjectWhenCompleted:work];
};
}
+ (FBLPromise * (^)(void (^)(FBLPromiseErrorCompletion)))resolveWithErrorWhen {
return ^(void (^work)(FBLPromiseErrorCompletion)) {
return [self resolveWithErrorWhenCompleted:work];
};
}
+ (FBLPromise * (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))resolveWithObjectOrErrorWhen {
return ^(void (^work)(FBLPromiseObjectOrErrorCompletion)) {
return [self resolveWithObjectOrErrorWhenCompleted:work];
};
}
+ (FBLPromise<NSArray *> * (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion)))
resolveWith2ObjectsOrErrorWhen {
return ^(void (^work)(FBLPromise2ObjectsOrErrorCompletion)) {
return [self resolveWith2ObjectsOrErrorWhenCompleted:work];
};
}
+ (FBLPromise<NSNumber *> * (^)(void (^)(FBLPromiseBoolCompletion)))resolveWithBoolWhen {
return ^(void (^work)(FBLPromiseBoolCompletion)) {
return [self resolveWithBoolWhenCompleted:work];
};
}
+ (FBLPromise<NSNumber *> * (^)(void (^)(FBLPromiseBoolOrErrorCompletion)))
resolveWithBoolOrErrorWhen {
return ^(void (^work)(FBLPromiseBoolOrErrorCompletion)) {
return [self resolveWithBoolOrErrorWhenCompleted:work];
};
}
+ (FBLPromise<NSNumber *> * (^)(void (^)(FBLPromiseIntegerCompletion)))resolveWithIntegerWhen {
return ^(void (^work)(FBLPromiseIntegerCompletion)) {
return [self resolveWithIntegerWhenCompleted:work];
};
}
+ (FBLPromise<NSNumber *> * (^)(void (^)(FBLPromiseIntegerOrErrorCompletion)))
resolveWithIntegerOrErrorWhen {
return ^(void (^work)(FBLPromiseIntegerOrErrorCompletion)) {
return [self resolveWithIntegerOrErrorWhenCompleted:work];
};
}
+ (FBLPromise<NSNumber *> * (^)(void (^)(FBLPromiseDoubleCompletion)))resolveWithDoubleWhen {
return ^(void (^work)(FBLPromiseDoubleCompletion)) {
return [self resolveWithDoubleWhenCompleted:work];
};
}
+ (FBLPromise<NSNumber *> * (^)(void (^)(FBLPromiseDoubleOrErrorCompletion)))
resolveWithDoubleOrErrorWhen {
return ^(void (^work)(FBLPromiseDoubleOrErrorCompletion)) {
return [self resolveWithDoubleOrErrorWhenCompleted:work];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Then.h"
@implementation FBLPromise (DotSyntax_ThenAdditions)
- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then {
return ^(FBLPromiseThenWorkBlock work) {
return [self then:work];
};
}
- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn {
return ^(dispatch_queue_t queue, FBLPromiseThenWorkBlock work) {
return [self onQueue:queue then:work];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Timeout.h"
@implementation FBLPromise (DotSyntax_TimeoutAdditions)
- (FBLPromise* (^)(NSTimeInterval))timeout {
return ^(NSTimeInterval interval) {
return [self timeout:interval];
};
}
- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn {
return ^(dispatch_queue_t queue, NSTimeInterval interval) {
return [self onQueue:queue timeout:interval];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+Validate.h"
@implementation FBLPromise (DotSyntax_ValidateAdditions)
- (FBLPromise* (^)(BOOL (^)(id __nullable)))validate {
return ^(BOOL (^predicate)(id __nullable)) {
return [self validate:predicate];
};
}
- (FBLPromise* (^)(dispatch_queue_t, BOOL (^)(id __nullable)))validateOn {
return ^(dispatch_queue_t queue, BOOL (^predicate)(id __nullable)) {
return [self onQueue:queue validate:predicate];
};
}
@end
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+When.h"
@implementation FBLPromise (DotSyntax_WhenAdditions)
+ (FBLPromise<NSArray *> * (^)(NSArray *))when {
return ^(NSArray *promises) {
return [self when:promises];
};
}
+ (FBLPromise<NSArray *> * (^)(dispatch_queue_t, NSArray *))whenOn {
return ^(dispatch_queue_t queue, NSArray *promises) {
return [self onQueue:queue when:promises];
};
}
@end
@@ -0,0 +1,27 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
@implementation FBLPromise (DotSyntaxAdditions)
+ (FBLPromise* (^)(id __nullable))resolve {
return ^(id resolution) {
return [self resolvedWith:resolution];
};
}
@end
+69
View File
@@ -0,0 +1,69 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+All.h"
#import "FBLPromise+Async.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (AllAdditions)
+ (FBLPromise<NSArray *> *)all:(NSArray *)promises {
return [self onQueue:dispatch_get_main_queue() all:promises];
}
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue all:(NSArray *)allPromises {
NSParameterAssert(allPromises);
if (allPromises.count == 0) {
return [[[self class] alloc] initWithResolution:@[]];
}
NSMutableArray *promises = [allPromises mutableCopy];
return [FBLPromise
onQueue:queue
async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
for (NSUInteger i = 0; i < promises.count; ++i) {
id promise = promises[i];
if ([promise isKindOfClass:self]) {
continue;
} else if ([promise isKindOfClass:[NSError class]]) {
reject(promise);
return;
} else {
[promises replaceObjectAtIndex:i
withObject:[[[self class] alloc] initWithResolution:promise]];
}
}
for (FBLPromise *promise in promises) {
[promise observeOnQueue:queue
fulfill:^(id __unused _) {
// Wait until all are fulfilled.
for (FBLPromise *promise in promises) {
if (!promise.isFulfilled) {
return;
}
}
// If called multiple times, only the first one affects the result.
fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]);
}
reject:^(NSError *error) {
reject(error);
}];
}
}];
}
@end
+41
View File
@@ -0,0 +1,41 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Always.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (AlwaysAdditions)
- (FBLPromise *)always:(void (^)(void))work {
return [self onQueue:dispatch_get_main_queue() always:work];
}
- (FBLPromise *)onQueue:(dispatch_queue_t)queue always:(void (^)(void))work {
NSParameterAssert(work);
return [self chainOnQueue:queue
chainedFulfill:^id(id value) {
work();
return value;
}
chainedReject:^id(NSError *error) {
work();
return error;
}];
}
@end
+48
View File
@@ -0,0 +1,48 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Any.h"
#import "FBLPromise+Async.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (AnyAdditions)
+ (instancetype)any:(NSArray *)promises {
return [self onQueue:dispatch_get_main_queue() any:promises];
}
+ (instancetype)onQueue:(dispatch_queue_t)queue any:(NSArray *)anyPromises {
NSAssert(anyPromises.count > 0, @"No promises to observe");
NSArray *promises = [anyPromises copy];
return [FBLPromise onQueue:queue
async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
for (id promise in promises) {
if (![promise isKindOfClass:self]) {
fulfill(promise);
return;
}
}
// Subscribe all, but only the first one to resolve will change
// the resulting promise's state.
for (FBLPromise *promise in promises) {
[promise observeOnQueue:queue fulfill:fulfill reject:reject];
}
}];
}
@end
+47
View File
@@ -0,0 +1,47 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Async.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (AsyncAdditions)
+ (instancetype)async:(FBLPromiseAsyncWorkBlock)work {
return [self onQueue:dispatch_get_main_queue() async:work];
}
+ (instancetype)onQueue:(dispatch_queue_t)queue async:(FBLPromiseAsyncWorkBlock)work {
NSParameterAssert(work);
FBLPromise *promise = [[[self class] alloc] initPending];
dispatch_group_async([self class].dispatchGroup, queue, ^{
@try {
work(
^(id __nullable value) {
[promise fulfill:value];
},
^(NSError *error) {
[promise reject:error];
});
} @catch (id exception) {
[promise reject:exception];
}
});
return promise;
}
@end
+38
View File
@@ -0,0 +1,38 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Catch.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (CatchAdditions)
- (FBLPromise *)catch:(FBLPromiseCatchBlock)reject {
return [self onQueue:dispatch_get_main_queue() catch:reject];
}
- (FBLPromise *)onQueue:(dispatch_queue_t)queue catch:(FBLPromiseCatchBlock)reject {
NSParameterAssert(reject);
return [self chainOnQueue:queue
chainedFulfill:nil
chainedReject:^id(NSError *error) {
reject(error);
return error;
}];
}
@end
+41
View File
@@ -0,0 +1,41 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Do.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (DoAdditions)
+ (instancetype)do:(FBLPromiseDoWorkBlock)work {
return [self onQueue:dispatch_get_main_queue() do:work];
}
+ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work {
NSParameterAssert(work);
FBLPromise *promise = [[[self class] alloc] initPending];
dispatch_group_async([self class].dispatchGroup, queue, ^{
@try {
[promise fulfill:work()];
} @catch (id exception) {
[promise reject:exception];
}
});
return promise;
}
@end
+37
View File
@@ -0,0 +1,37 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Recover.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (RecoverAdditions)
- (FBLPromise *)recover:(nullable id (^)(NSError *))recovery {
return [self onQueue:dispatch_get_main_queue() recover:recovery];
}
- (FBLPromise *)onQueue:(dispatch_queue_t)queue recover:(nullable id (^)(NSError *))recovery {
NSParameterAssert(recovery);
return [self chainOnQueue:queue
chainedFulfill:nil
chainedReject:^id(NSError *error) {
return recovery(error);
}];
}
@end
+179
View File
@@ -0,0 +1,179 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Resolve.h"
#import "FBLPromise+Async.h"
@implementation FBLPromise (ResolveAdditions)
+ (instancetype)resolveWhenCompleted:(void (^)(FBLPromiseCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
work(^{
fulfill(nil);
});
}];
}
+ (instancetype)resolveWithObjectWhenCompleted:(void (^)(FBLPromiseObjectCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
work(^(id __nullable value) {
fulfill(value);
});
}];
}
+ (instancetype)resolveWithErrorWhenCompleted:(void (^)(FBLPromiseErrorCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
work(^(NSError *__nullable error) {
if (error) {
reject(error);
} else {
fulfill(nil);
}
});
}];
}
+ (instancetype)resolveWithObjectOrErrorWhenCompleted:
(void (^)(FBLPromiseObjectOrErrorCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
work(^(id __nullable value, NSError *__nullable error) {
if (error) {
reject(error);
} else {
fulfill(value);
}
});
}];
}
+ (instancetype)resolveWithErrorOrObjectWhenCompleted:
(void (^)(FBLPromiseErrorOrObjectCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
work(^(NSError *__nullable error, id __nullable value) {
if (error) {
reject(error);
} else {
fulfill(value);
}
});
}];
}
+ (FBLPromise<NSArray *> *)resolveWith2ObjectsOrErrorWhenCompleted:
(void (^)(FBLPromise2ObjectsOrErrorCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
work(^(id __nullable value1, id __nullable value2, NSError *__nullable error) {
if (error) {
reject(error);
} else {
fulfill(@[ value1, value2 ]);
}
});
}];
}
+ (FBLPromise<NSNumber *> *)resolveWithBoolWhenCompleted:(void (^)(FBLPromiseBoolCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
work(^(BOOL value) {
fulfill(@(value));
});
}];
}
+ (FBLPromise<NSNumber *> *)resolveWithBoolOrErrorWhenCompleted:
(void (^)(FBLPromiseBoolOrErrorCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
work(^(BOOL value, NSError *__nullable error) {
if (error) {
reject(error);
} else {
fulfill(@(value));
}
});
}];
}
+ (FBLPromise<NSNumber *> *)resolveWithIntegerWhenCompleted:
(void (^)(FBLPromiseIntegerCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
work(^(NSInteger value) {
fulfill(@(value));
});
}];
}
+ (FBLPromise<NSNumber *> *)resolveWithIntegerOrErrorWhenCompleted:
(void (^)(FBLPromiseIntegerOrErrorCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
work(^(NSInteger value, NSError *__nullable error) {
if (error) {
reject(error);
} else {
fulfill(@(value));
}
});
}];
}
+ (FBLPromise<NSNumber *> *)resolveWithDoubleWhenCompleted:
(void (^)(FBLPromiseDoubleCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
work(^(double value) {
fulfill(@(value));
});
}];
}
+ (FBLPromise<NSNumber *> *)resolveWithDoubleOrErrorWhenCompleted:
(void (^)(FBLPromiseDoubleOrErrorCompletion))work {
NSParameterAssert(work);
return [self async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
work(^(double value, NSError *__nullable error) {
if (error) {
reject(error);
} else {
fulfill(@(value));
}
});
}];
}
@end
+56
View File
@@ -0,0 +1,56 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Testing.h"
BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) {
BOOL isTimedOut = NO;
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
static NSTimeInterval const minimalTimeout = 0.01;
static int64_t const minimalTimeToWait = (int64_t)(minimalTimeout * NSEC_PER_SEC);
dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, minimalTimeToWait);
dispatch_group_t dispatchGroup = FBLPromise.dispatchGroup;
NSRunLoop *runLoop = NSRunLoop.currentRunLoop;
while (dispatch_group_wait(dispatchGroup, waitTime)) {
isTimedOut = timeoutDate.timeIntervalSinceNow < 0.0;
if (isTimedOut) {
break;
}
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:minimalTimeout]];
}
return !isTimedOut;
}
@implementation FBLPromise (TestingAdditions)
// These properties are implemented in the FBLPromise class itself.
@dynamic isPending;
@dynamic isFulfilled;
@dynamic isRejected;
@dynamic pendingObjects;
@dynamic value;
@dynamic error;
+ (dispatch_group_t)dispatchGroup {
static dispatch_group_t gDispatchGroup;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
gDispatchGroup = dispatch_group_create();
});
return gDispatchGroup;
}
@end
+33
View File
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Then.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (ThenAdditions)
- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work {
return [self onQueue:dispatch_get_main_queue() then:work];
}
- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work {
NSParameterAssert(work);
return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil];
}
@end
+43
View File
@@ -0,0 +1,43 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Timeout.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (TimeoutAdditions)
- (FBLPromise *)timeout:(NSTimeInterval)interval {
return [self onQueue:dispatch_get_main_queue() timeout:interval];
}
- (FBLPromise *)onQueue:(dispatch_queue_t)queue timeout:(NSTimeInterval)interval {
FBLPromise *promise = [[[self class] alloc] initPending];
dispatch_group_async([self class].dispatchGroup, queue, ^{
[promise fulfill:self];
});
int64_t const timeToWait = (int64_t)(interval * NSEC_PER_SEC);
FBLPromise __weak *weakPromise = promise;
dispatch_after(dispatch_time(0, timeToWait), queue, ^{
NSError *timedOutError = [NSError errorWithDomain:FBLPromiseErrorDomain
code:FBLPromiseErrorCodeTimedOut
userInfo:nil];
[weakPromise reject:timedOutError];
});
return promise;
}
@end
+38
View File
@@ -0,0 +1,38 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Validate.h"
#import "FBLPromisePrivate.h"
@implementation FBLPromise (ValidateAdditions)
- (FBLPromise *)validate:(BOOL (^)(id __nullable))predicate {
return [self onQueue:dispatch_get_main_queue() validate:predicate];
}
- (FBLPromise *)onQueue:(dispatch_queue_t)queue validate:(BOOL (^)(id __nullable))predicate {
NSParameterAssert(predicate);
FBLPromiseChainedFulfillBlock chainedFulfill = ^id(id value) {
return predicate(value) ? value : [NSError errorWithDomain:FBLPromiseErrorDomain
code:FBLPromiseErrorCodeValidationFailure
userInfo:nil];
};
return [self chainOnQueue:queue chainedFulfill:chainedFulfill chainedReject:nil];
}
@end
+95
View File
@@ -0,0 +1,95 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+When.h"
#import "FBLPromise+Async.h"
#import "FBLPromisePrivate.h"
static NSArray *FBLPromiseCombineValuesAndErrors(NSArray<FBLPromise *> *promises) {
NSMutableArray *combinedValuesAndErrors = [[NSMutableArray alloc] init];
for (FBLPromise *promise in promises) {
if (promise.isFulfilled) {
[combinedValuesAndErrors addObject:promise.value ?: [NSNull null]];
continue;
}
if (promise.isRejected) {
[combinedValuesAndErrors addObject:promise.error];
continue;
}
assert(!promise.isPending);
};
return combinedValuesAndErrors;
}
@implementation FBLPromise (WhenAdditions)
+ (FBLPromise<NSArray *> *)when:(NSArray *)promises {
return [self onQueue:dispatch_get_main_queue() when:promises];
}
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue when:(NSArray *)whenPromises {
NSParameterAssert(whenPromises);
if (whenPromises.count == 0) {
return [[[self class] alloc] initWithResolution:@[]];
}
NSMutableArray *promises = [whenPromises mutableCopy];
return [FBLPromise
onQueue:queue
async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
for (NSUInteger i = 0; i < promises.count; ++i) {
id promise = promises[i];
if ([promise isKindOfClass:self]) {
continue;
} else {
[promises replaceObjectAtIndex:i
withObject:[[[self class] alloc] initWithResolution:promise]];
}
}
for (FBLPromise *promise in promises) {
[promise observeOnQueue:queue
fulfill:^(id __unused _) {
// Wait until all are resolved.
for (FBLPromise *promise in promises) {
if (promise.isPending) {
return;
}
}
// If called multiple times, only the first one affects the result.
fulfill(FBLPromiseCombineValuesAndErrors(promises));
}
reject:^(NSError *error) {
BOOL atLeastOneIsFulfilled = NO;
for (FBLPromise *promise in promises) {
if (promise.isPending) {
return;
}
if (promise.isFulfilled) {
atLeastOneIsFulfilled = YES;
}
}
if (atLeastOneIsFulfilled) {
fulfill(FBLPromiseCombineValuesAndErrors(promises));
} else {
reject(error);
}
}];
}
}];
}
@end
+288
View File
@@ -0,0 +1,288 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromisePrivate.h"
#import "FBLPromiseErrorPrivate.h"
/** All states a promise can be in. */
typedef NS_ENUM(NSInteger, FBLPromiseState) {
FBLPromiseStatePending = 0,
FBLPromiseStateFulfilled,
FBLPromiseStateRejected,
};
typedef void (^FBLPromiseObserver)(FBLPromiseState state, id __nullable resolution);
@implementation FBLPromise {
/** Current state of the promise. */
FBLPromiseState _state;
/**
Set of arbitrary objects to keep strongly while the promise is pending.
Becomes nil after the promise has been resolved.
*/
NSMutableSet *__nullable _pendingObjects;
/**
Value to fulfill the promise with.
Can be nil if the promise is still pending, was resolved with nil or after it has been rejected.
*/
id __nullable _value;
/**
Error to reject the promise with.
Can be nil if the promise is still pending or after it has been fulfilled.
*/
NSError *__nullable _error;
/** List of observers to notify when the promise gets resolved. */
NSMutableArray<FBLPromiseObserver> *_observers;
}
+ (instancetype)pendingPromise {
return [[self alloc] initPending];
}
+ (instancetype)resolvedWith:(nullable id)resolution {
return [[self alloc] initWithResolution:resolution];
}
- (void)fulfill:(nullable id)value {
if ([value isKindOfClass:[self class]]) {
[(FBLPromise *)value observeOnQueue:dispatch_get_main_queue()
fulfill:^(id __nullable value) {
[self fulfill:value];
}
reject:^(NSError *error) {
[self reject:error];
}];
} else if ([value isKindOfClass:[NSError class]]) {
[self reject:(NSError *)value];
} else if ([value isKindOfClass:[NSException class]]) {
[self reject:FBLNSErrorFromNSException((NSException *)value)];
} else {
@synchronized(self) {
if (_state == FBLPromiseStatePending) {
_state = FBLPromiseStateFulfilled;
_value = value;
_pendingObjects = nil;
for (FBLPromiseObserver observer in _observers) {
observer(_state, _value);
}
_observers = nil;
dispatch_group_leave([self class].dispatchGroup);
}
}
}
}
- (void)reject:(NSError *)error {
if ([error isKindOfClass:[NSException class]]) {
error = FBLNSErrorFromNSException((NSException *)error);
}
NSAssert([error isKindOfClass:[NSError class]], @"Invalid error type.");
if (![error isKindOfClass:[NSError class]]) {
// Give up on invalid error type in Release mode.
@throw error; // NOLINT
}
@synchronized(self) {
if (_state == FBLPromiseStatePending) {
_state = FBLPromiseStateRejected;
_error = error;
_pendingObjects = nil;
for (FBLPromiseObserver observer in _observers) {
observer(_state, _error);
}
_observers = nil;
dispatch_group_leave([self class].dispatchGroup);
}
}
}
#pragma mark - NSObject
- (NSString *)description {
if (self.isFulfilled) {
return [NSString stringWithFormat:@"<%@ %p> Fulfilled: %@", NSStringFromClass([self class]),
self, self.value];
}
if (self.isRejected) {
return [NSString stringWithFormat:@"<%@ %p> Rejected: %@", NSStringFromClass([self class]),
self, self.error];
}
return [NSString stringWithFormat:@"<%@ %p> Pending", NSStringFromClass([self class]), self];
}
#pragma mark - Private
- (instancetype)initPending {
self = [super init];
if (self) {
dispatch_group_enter([self class].dispatchGroup);
}
return self;
}
- (instancetype)initWithResolution:(nullable id)resolution {
self = [super init];
if (self) {
if ([resolution isKindOfClass:[self class]]) {
FBLPromise *anotherPromise = (FBLPromise *)resolution;
if (anotherPromise.isRejected) {
_state = FBLPromiseStateRejected;
_error = anotherPromise.error;
} else {
_state = FBLPromiseStateFulfilled;
_value = anotherPromise.value;
}
} else if ([resolution isKindOfClass:[NSError class]]) {
_state = FBLPromiseStateRejected;
_error = (NSError *)resolution;
} else if ([resolution isKindOfClass:[NSException class]]) {
_state = FBLPromiseStateRejected;
_error = FBLNSErrorFromNSException((NSException *)resolution);
} else {
_state = FBLPromiseStateFulfilled;
_value = resolution;
}
}
return self;
}
- (void)dealloc {
if (_state == FBLPromiseStatePending) {
dispatch_group_leave([self class].dispatchGroup);
}
}
- (BOOL)isPending {
@synchronized(self) {
return _state == FBLPromiseStatePending;
}
}
- (BOOL)isFulfilled {
@synchronized(self) {
return _state == FBLPromiseStateFulfilled;
}
}
- (BOOL)isRejected {
@synchronized(self) {
return _state == FBLPromiseStateRejected;
}
}
- (nullable id)value {
@synchronized(self) {
return _value;
}
}
- (NSError *__nullable)error {
@synchronized(self) {
return _error;
}
}
- (NSMutableSet *__nullable)pendingObjects {
@synchronized(self) {
if (_state == FBLPromiseStatePending) {
if (!_pendingObjects) {
_pendingObjects = [[NSMutableSet alloc] init];
}
}
return _pendingObjects;
}
}
- (void)observeOnQueue:(dispatch_queue_t)queue
fulfill:(FBLPromiseOnFulfillBlock)onFulfill
reject:(FBLPromiseOnRejectBlock)onReject {
dispatch_group_t dispatchGroup = [self class].dispatchGroup;
@synchronized(self) {
switch (_state) {
case FBLPromiseStatePending: {
if (!_observers) {
_observers = [[NSMutableArray alloc] init];
}
[_observers addObject:^(FBLPromiseState state, id __nullable resolution) {
dispatch_group_async(dispatchGroup, queue, ^{
switch (state) {
case FBLPromiseStatePending:
break;
case FBLPromiseStateFulfilled:
onFulfill(resolution);
break;
case FBLPromiseStateRejected:
onReject(resolution);
break;
}
});
}];
break;
}
case FBLPromiseStateFulfilled: {
dispatch_group_async(dispatchGroup, queue, ^{
onFulfill(_value);
});
break;
}
case FBLPromiseStateRejected: {
dispatch_group_async(dispatchGroup, queue, ^{
onReject(_error);
});
break;
}
}
}
}
- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
chainedReject:(FBLPromiseChainedRejectBlock)chainedReject {
FBLPromise *promise = [[[self class] alloc] initPending];
FBLPromiseOnFulfillBlock onFulfill;
if (chainedFulfill) {
onFulfill = ^(id __nullable value) {
@try {
[promise fulfill:chainedFulfill(value)];
} @catch (id exception) {
[promise reject:exception];
}
};
} else {
onFulfill = ^(id __nullable value) {
[promise fulfill:value];
};
}
FBLPromiseOnRejectBlock onReject;
if (chainedReject) {
onReject = ^(NSError *error) {
@try {
[promise fulfill:chainedReject(error)];
} @catch (id exception) {
[promise reject:exception];
}
};
} else {
onReject = ^(NSError *error) {
[promise reject:error];
};
}
[self observeOnQueue:queue fulfill:onFulfill reject:onReject];
return promise;
}
@end
+36
View File
@@ -0,0 +1,36 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromiseErrorPrivate.h"
NSString *const FBLPromiseErrorDomain = @"com.google.FBLPromises.Error";
NSString *const FBLPromiseErrorUserInfoExceptionNameKey = @"NSExceptionName";
NSString *const FBLPromiseErrorUserInfoExceptionReasonKey = @"NSExceptionReason";
NSString *const FBLPromiseErrorUserInfoExceptionUserInfoKey = @"NSExceptionUserInfo";
NSString *const FBLPromiseErrorUserInfoExceptionReturnAddressesKey = @"NSExceptionReturnAddresses";
NSString *const FBLPromiseErrorUserInfoExceptionCallStackKey = @"NSExceptionCallStack";
NSError *FBLNSErrorFromNSException(NSException *exception) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[FBLPromiseErrorUserInfoExceptionNameKey] = exception.name;
userInfo[FBLPromiseErrorUserInfoExceptionReasonKey] = exception.reason;
userInfo[FBLPromiseErrorUserInfoExceptionUserInfoKey] = exception.userInfo;
userInfo[FBLPromiseErrorUserInfoExceptionReturnAddressesKey] = exception.callStackReturnAddresses;
userInfo[FBLPromiseErrorUserInfoExceptionCallStackKey] = exception.callStackSymbols;
return [[NSError alloc] initWithDomain:FBLPromiseErrorDomain
code:FBLPromiseErrorCodeException
userInfo:userInfo];
}
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+All.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `all` operators.
Usage: promise.all(@[ ... ])
*/
@interface FBLPromise<Value>(DotSyntax_AllAdditions)
+ (FBLPromise<NSArray *> * (^)(NSArray *))all FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSArray *> * (^)(dispatch_queue_t, NSArray *))allOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Always.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `always` operators.
Usage: promise.always(^{...})
*/
@interface FBLPromise<Value>(DotSyntax_AlwaysAdditions)
- (FBLPromise* (^)(void (^)(void)))always FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
- (FBLPromise* (^)(dispatch_queue_t, void (^)(void)))alwaysOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Any.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `any` operators.
Usage: promise.any(@[ ... ])
*/
@interface FBLPromise<Value>(DotSyntax_AnyAdditions)
+ (FBLPromise * (^)(NSArray *))any FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Async.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `async` operators.
Usage: promise.async(^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { ... })
*/
@interface FBLPromise<Value>(DotSyntax_AsyncAdditions)
+ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Catch.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `catch` operators.
Usage: promise.catch(^(NSError *error) { ... })
*/
@interface FBLPromise<Value>(DotSyntax_CatchAdditions)
- (FBLPromise* (^)(FBLPromiseCatchBlock))catch FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchBlock))catchOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,33 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Do.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `do` operators.
Usage: FBLPromise.doOn(queue, ^(NSError *error) { ... })
*/
@interface FBLPromise<Value>(DotSyntax_DoAdditions)
+ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,35 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Recover.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `recover` operators.
Usage: promise.recover(^id(NSError *error) {...})
*/
@interface FBLPromise<Value>(DotSyntax_RecoverAdditions)
- (FBLPromise * (^)(id __nullable (^)(NSError *)))recover FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
- (FBLPromise * (^)(dispatch_queue_t, id __nullable (^)(NSError *)))recoverOn
FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,53 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Resolve.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `resolve` operators.
Usage: promise.resolveWhen(^(FBLPromiseCompletion handler) {...})
*/
@interface FBLPromise<Value>(DotSyntax_ResolveAdditions)
+ (FBLPromise* (^)(void (^)(FBLPromiseCompletion)))resolveWhen FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise* (^)(void (^)(FBLPromiseObjectCompletion)))resolveWithObjectWhen
FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise* (^)(void (^)(FBLPromiseErrorCompletion)))resolveWithErrorWhen FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise* (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))resolveWithObjectOrErrorWhen
FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSArray*>* (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion)))
resolveWith2ObjectsOrErrorWhen FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSNumber*>* (^)(void (^)(FBLPromiseBoolCompletion)))resolveWithBoolWhen
FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSNumber*>* (^)(void (^)(FBLPromiseBoolOrErrorCompletion)))resolveWithBoolOrErrorWhen
FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSNumber*>* (^)(void (^)(FBLPromiseIntegerCompletion)))resolveWithIntegerWhen
FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSNumber*>* (^)(void (^)(FBLPromiseIntegerOrErrorCompletion)))
resolveWithIntegerOrErrorWhen FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSNumber*>* (^)(void (^)(FBLPromiseDoubleCompletion)))resolveWithDoubleWhen
FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSNumber*>* (^)(void (^)(FBLPromiseDoubleOrErrorCompletion)))
resolveWithDoubleOrErrorWhen FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Then.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `then` operators.
Usage: promise.then(^id(id value) { ... })
*/
@interface FBLPromise<Value>(DotSyntax_ThenAdditions)
- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Timeout.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `timeout` operators.
Usage: promise.timeout(...)
*/
@interface FBLPromise<Value>(DotSyntax_TimeoutAdditions)
- (FBLPromise* (^)(NSTimeInterval))timeout FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,35 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+Validate.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `validate` operators.
Usage: promise.validate(^BOOL(id value) { ... })
*/
@interface FBLPromise<Value>(DotSyntax_ValidateAdditions)
- (FBLPromise* (^)(BOOL (^)(Value __nullable)))validate FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
- (FBLPromise* (^)(dispatch_queue_t, BOOL (^)(Value __nullable)))validateOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax.h"
#import "FBLPromise+When.h"
NS_ASSUME_NONNULL_BEGIN
/**
Convenience dot-syntax wrappers for `FBLPromise` `when` operators.
Usage: promise.when(@[ ... ])
*/
@interface FBLPromise<Value>(DotSyntax_WhenAdditions)
+ (FBLPromise<NSArray *> * (^)(NSArray *))when FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSArray *> * (^)(dispatch_queue_t, NSArray *))whenOn FBL_PROMISES_DOT_SYNTAX
NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,37 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
#ifdef FBL_PROMISES_DOT_SYNTAX_IS_DEPRECATED
#define FBL_PROMISES_DOT_SYNTAX __attribute__((deprecated))
#else
#define FBL_PROMISES_DOT_SYNTAX
#endif
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(DotSyntaxAdditions)
/**
Convenience dot-syntax wrappers for FBLPromise.
Usage: FBLPromise.resolve(value)
*/
+ (FBLPromise* (^)(id __nullable))resolve FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,51 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(AllAdditions)
/**
Wait until all of the given promises are fulfilled.
If one of the given promises is rejected, then the returned promise is rejected with same error.
If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`,
it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly.
Promises resolved with `nil` become `NSNull` instances in the resulting array.
@param promises Promises to wait for.
@return Promise of an array containing the values of input promises in the same order.
*/
+ (FBLPromise<NSArray *> *)all:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
/**
Wait until all of the given promises are fulfilled.
If one of the given promises is rejected, then the returned promise is rejected with same error.
If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`,
it's implicitly considered a pre-fulfilled or pre-rejected FBLPromise correspondingly.
Promises resolved with `nil` become `NSNull` instances in the resulting array.
@param queue A queue to dispatch on.
@param promises Promises to wait for.
@return Promise of an array containing the values of input promises in the same order.
*/
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue
all:(NSArray *)promises NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,38 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(AlwaysAdditions)
/**
@param work A block that always executes, no matter if the receiver is rejected or fulfilled.
@return A new pending promise to be resolved with same resolution as the receiver.
*/
- (FBLPromise *)always:(void (^)(void))work NS_SWIFT_UNAVAILABLE("");
/**
@param queue A queue to dispatch on.
@param work A block that always executes, no matter if the receiver is rejected or fulfilled.
@return A new pending promise to be resolved with same resolution as the receiver.
*/
- (FBLPromise *)onQueue:(dispatch_queue_t)queue always:(void (^)(void))work NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,50 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(AnyAdditions)
/**
Wait until any of the given promises are fulfilled.
If one of the promises is rejected, then the returned promise is rejected with same error.
If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`,
it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly.
@param promises Promises to wait for.
@return A new pending promise to be resolved with the same resolution as the first promise, among
the given ones, which was resolved.
*/
+ (instancetype)any:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
/**
Wait until any of the given promises are fulfilled.
If one of the promises is rejected, then the returned promise is rejected with same error.
If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`,
it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly.
@param queue A queue to dispatch on.
@param promises Promises to wait for.
@return A new pending promise to be resolved with the same resolution as the first promise, among
the given ones, which was resolved.
*/
+ (instancetype)onQueue:(dispatch_queue_t)queue any:(NSArray *)promises NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,49 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(AsyncAdditions)
typedef void (^FBLPromiseFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseAsyncWorkBlock)(FBLPromiseFulfillBlock fulfill,
FBLPromiseRejectBlock reject) NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise and executes `work` block asynchronously on the main queue.
@param work A block to perform any operations needed to resolve the promise.
@return A new pending promise.
*/
+ (instancetype)async:(FBLPromiseAsyncWorkBlock)work NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise and executes `work` block asynchronously on the given queue.
@param queue A queue to invoke the work block on.
@param work A block to perform any operations needed to resolve the promise.
@return A new pending promise.
*/
+ (instancetype)onQueue:(dispatch_queue_t)queue
async:(FBLPromiseAsyncWorkBlock)work NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,47 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(CatchAdditions)
typedef void (^FBLPromiseCatchBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise which eventually gets resolved with same resolution as the receiver.
If receiver is rejected, then `reject` block is executed asynchronously on the main queue.
@param reject A block to handle the error that receiver was rejected with.
@return A new pending promise.
*/
- (FBLPromise *)catch:(FBLPromiseCatchBlock)reject NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise which eventually gets resolved with same resolution as the receiver.
If receiver is rejected, then `reject` block is executed asynchronously on the given queue.
@param queue A queue to invoke the `reject` block on.
@param reject A block to handle the error that receiver was rejected with.
@return A new pending promise.
*/
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
catch:(FBLPromiseCatchBlock)reject NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,44 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(DoAdditions)
typedef id __nullable (^FBLPromiseDoWorkBlock)(void) NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise and executes `work` block asynchronously on the main queue.
@param work A block that returns a value or an error used to resolve the promise.
@return A new pending promise.
*/
+ (instancetype)do:(FBLPromiseDoWorkBlock)work NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise and executes `work` block asynchronously on the given queue.
@param queue A queue to invoke the `work` block on.
@param work A block that returns a value or an error used to resolve the promise.
@return A new pending promise.
*/
+ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(RecoverAdditions)
/**
Provides a new promise to recover in case the receiver gets rejected.
@param recovery A block to handle the error that the receiver was rejected with.
@return A new pending promise to use instead of the rejected one that gets resolved with resolution
returned from `recovery` block.
*/
- (FBLPromise *)recover:(nullable id (^)(NSError *))recovery NS_SWIFT_UNAVAILABLE("");
/**
Provides a new promise to recover in case the receiver gets rejected.
@param queue A queue to dispatch on.
@param recovery A block to handle the error that the receiver was rejected with.
@return A new pending promise to use instead of the rejected one that gets resolved with resolution
returned from `recovery` block.
*/
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
recover:(nullable id (^)(NSError *))recovery NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,127 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
/**
Different types of completion handlers available to be wrapped with promise.
*/
typedef void (^FBLPromiseCompletion)(void) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseObjectCompletion)(id __nullable) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseErrorCompletion)(NSError* __nullable error) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseObjectOrErrorCompletion)(id __nullable, NSError* __nullable)
NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseErrorOrObjectCompletion)(NSError* __nullable, id __nullable)
NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromise2ObjectsOrErrorCompletion)(id __nullable, id __nullable,
NSError* __nullable) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseBoolCompletion)(BOOL) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseBoolOrErrorCompletion)(BOOL, NSError* __nullable) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseIntegerCompletion)(NSInteger) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseIntegerOrErrorCompletion)(NSInteger, NSError* __nullable)
NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseDoubleCompletion)(double) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseDoubleOrErrorCompletion)(double, NSError* __nullable)
NS_SWIFT_UNAVAILABLE("");
/**
Provides an easy way to convert methods that use common callback patterns into promises.
*/
@interface FBLPromise<Value>(ResolveAdditions)
/**
@returns A promise that resolves with `nil` when completion handler is invoked.
*/
+ (instancetype)resolveWhenCompleted:(void (^)(FBLPromiseCompletion))work NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an object provided by completion handler.
*/
+ (instancetype)resolveWithObjectWhenCompleted:(void (^)(FBLPromiseObjectCompletion))work
NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an error provided by completion handler.
If error is `nil`, fulfills with `nil`, otherwise rejects with the error.
*/
+ (instancetype)resolveWithErrorWhenCompleted:(void (^)(FBLPromiseErrorCompletion))work
NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an object provided by completion handler if error is `nil`.
Otherwise, rejects with the error.
*/
+ (instancetype)resolveWithObjectOrErrorWhenCompleted:
(void (^)(FBLPromiseObjectOrErrorCompletion))work NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an error or object provided by completion handler. If error
is not `nil`, rejects with the error.
*/
+ (instancetype)resolveWithErrorOrObjectWhenCompleted:
(void (^)(FBLPromiseErrorOrObjectCompletion))work NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an array of objects provided by completion handler in order
if error is `nil`. Otherwise, rejects with the error.
*/
+ (FBLPromise<NSArray*>*)resolveWith2ObjectsOrErrorWhenCompleted:
(void (^)(FBLPromise2ObjectsOrErrorCompletion))work NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an `NSNumber` wrapping YES/NO.
*/
+ (FBLPromise<NSNumber*>*)resolveWithBoolWhenCompleted:(void (^)(FBLPromiseBoolCompletion))work
NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`.
Otherwise rejects with the error.
*/
+ (FBLPromise<NSNumber*>*)resolveWithBoolOrErrorWhenCompleted:
(void (^)(FBLPromiseBoolOrErrorCompletion))work NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an `NSNumber` wrapping an integer.
*/
+ (FBLPromise<NSNumber*>*)resolveWithIntegerWhenCompleted:
(void (^)(FBLPromiseIntegerCompletion))work NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`.
Otherwise rejects with the error.
*/
+ (FBLPromise<NSNumber*>*)resolveWithIntegerOrErrorWhenCompleted:
(void (^)(FBLPromiseIntegerOrErrorCompletion))work NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an `NSNumber` wrapping a double.
*/
+ (FBLPromise<NSNumber*>*)resolveWithDoubleWhenCompleted:(void (^)(FBLPromiseDoubleCompletion))work
NS_SWIFT_UNAVAILABLE("");
/**
@returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`.
Otherwise rejects with the error.
*/
+ (FBLPromise<NSNumber*>*)resolveWithDoubleOrErrorWhenCompleted:
(void (^)(FBLPromiseDoubleOrErrorCompletion))work NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,63 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
/**
Waits for all scheduled promises blocks.
@param timeout Maximum time to wait.
@return YES if all promises blocks have completed before the timeout and NO otherwise.
*/
FOUNDATION_EXPORT BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) NS_REFINED_FOR_SWIFT;
@interface FBLPromise<Value>(TestingAdditions)
/**
Dispatch group for promises that is typically used to wait for all scheduled blocks.
*/
@property(class, nonatomic, readonly) dispatch_group_t dispatchGroup NS_REFINED_FOR_SWIFT;
/**
Properties to get the current state of the promise.
*/
@property(nonatomic, readonly) BOOL isPending NS_REFINED_FOR_SWIFT;
@property(nonatomic, readonly) BOOL isFulfilled NS_REFINED_FOR_SWIFT;
@property(nonatomic, readonly) BOOL isRejected NS_REFINED_FOR_SWIFT;
/**
Set of arbitrary objects to keep strongly while the promise is pending.
Becomes nil after the promise has been resolved.
*/
@property(nonatomic, readonly, nullable) NSMutableSet *pendingObjects NS_REFINED_FOR_SWIFT;
/**
Value the promise was fulfilled with.
Can be nil if the promise is still pending, was resolved with nil or after it has been rejected.
*/
@property(nonatomic, readonly, nullable) Value value NS_REFINED_FOR_SWIFT;
/**
Error the promise was rejected with.
Can be nil if the promise is still pending or after it has been fulfilled.
*/
@property(nonatomic, readonly, nullable) NSError *error NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,51 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(ThenAdditions)
typedef id __nullable (^FBLPromiseThenWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise which eventually gets resolved with resolution returned from `work`
block: either value, error or another promise. The `work` block is executed asynchronously on the
main queue only when the receiver is fulfilled. If receiver is rejected, the returned promise is
also rejected with the same error.
@param work A block to handle the value that receiver was fulfilled with.
@return A new pending promise to be resolved with resolution returned from the `work` block.
*/
- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise which eventually gets resolved with resolution returned from `work`
block: either value, error or another promise. The `work` block is executed asynchronously on the
main queue only when the receiver is fulfilled. If receiver is rejected, the returned promise is
also rejected with the same error.
@param queue A queue to invoke the `work` block on.
@param work A block to handle the value that receiver was fulfilled with.
@return A new pending promise to be resolved with resolution returned from the `work` block.
*/
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
then:(FBLPromiseThenWorkBlock)work NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(TimeoutAdditions)
/**
Waits for a promise with the specified `timeout`.
@param interval Time to wait in seconds.
@return A new pending promise that gets either resolved with same resolution as the receiver or
rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`.
*/
- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE("");
/**
Waits for a promise with the specified `timeout`.
@param queue A queue to dispatch on.
@param interval Time to wait in seconds.
@return A new pending promise that gets either resolved with same resolution as the receiver or
rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`.
*/
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(ValidateAdditions)
/**
Validates a fulfilled value or rejects the value if it can not be validated.
@param predicate An expression to validate.
@return A new pending promise that gets either resolved with same resolution as the receiver or
rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`.
*/
- (FBLPromise *)validate:(BOOL (^)(Value __nullable))predicate NS_SWIFT_UNAVAILABLE("");
/**
Validates a fulfilled value or rejects the value if it can not be validated.
@param queue A queue to dispatch on.
@param predicate An expression to validate.
@return A new pending promise that gets either resolved with same resolution as the receiver or
rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`.
*/
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
validate:(BOOL (^)(Value __nullable))predicate NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,57 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise.h"
NS_ASSUME_NONNULL_BEGIN
@interface FBLPromise<Value>(WhenAdditions)
/**
Waits until all of the given promises are either fulfilled or rejected.
If all promises are rejected, then the returned promise is rejected with same error
as the last one rejected.
If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of
values or `NSErrors`, matching the original order of fulfilled or rejected promises respectively.
If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`,
it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly.
Promises resolved with `nil` become `NSNull` instances in the resulting array.
@param promises Promises to wait for.
@return Promise of array containing the values or `NSError`s of input promises in the same order.
*/
+ (FBLPromise<NSArray *> *)when:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
/**
Waits until all of the given promises are either fulfilled or rejected.
If all promises are rejected, then the returned promise is rejected with same error
as the last one rejected.
If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of
values or `NSError`s, matching the original order of fulfilled or rejected promises respectively.
If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`,
it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly.
Promises resolved with `nil` become `NSNull` instances in the resulting array.
@param queue A queue to dispatch on.
@param promises Promises to wait for.
@return Promise of array containing the values or `NSError`s of input promises in the same order.
*/
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue
when:(NSArray *)promises NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
+58
View File
@@ -0,0 +1,58 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromiseError.h"
NS_ASSUME_NONNULL_BEGIN
/**
Promises synchronization construct in Objective-C.
*/
@interface FBLPromise<Value> : NSObject
/**
Creates a pending promise.
*/
+ (instancetype)pendingPromise NS_REFINED_FOR_SWIFT;
/**
Creates a resolved promise.
@param resolution An object to resolve the promise with: either a value or an error.
@return A new resolved promise.
*/
+ (instancetype)resolvedWith:(nullable id)resolution NS_REFINED_FOR_SWIFT;
/**
Synchronously fulfills the promise with a value.
@param value An arbitrary value to fulfill the promise with, including `nil`.
*/
- (void)fulfill:(nullable id)value NS_REFINED_FOR_SWIFT;
/**
Synchronously rejects the promise with an error.
@param error An error to reject the promise with.
*/
- (void)reject:(NSError *)error NS_REFINED_FOR_SWIFT;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,40 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
Possible error codes in `FBLPromiseErrorDomain`.
*/
typedef NS_ENUM(NSInteger, FBLPromiseErrorCode) {
/** Objective-C exception was thrown. */
FBLPromiseErrorCodeException = 1,
/** Promise failed to resolve in time. */
FBLPromiseErrorCodeTimedOut = 2,
/** Validation predicate returned false. */
FBLPromiseErrorCodeValidationFailure = 3,
} NS_REFINED_FOR_SWIFT;
extern NSString* const FBLPromiseErrorDomain NS_REFINED_FOR_SWIFT;
extern NSString* const FBLPromiseErrorUserInfoExceptionNameKey NS_REFINED_FOR_SWIFT;
extern NSString* const FBLPromiseErrorUserInfoExceptionReasonKey NS_REFINED_FOR_SWIFT;
extern NSString* const FBLPromiseErrorUserInfoExceptionUserInfoKey NS_REFINED_FOR_SWIFT;
extern NSString* const FBLPromiseErrorUserInfoExceptionReturnAddressesKey NS_REFINED_FOR_SWIFT;
extern NSString* const FBLPromiseErrorUserInfoExceptionCallStackKey NS_REFINED_FOR_SWIFT;
NS_ASSUME_NONNULL_END
@@ -0,0 +1,24 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromiseError.h"
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT NSError *FBLNSErrorFromNSException(NSException *exception)
NS_SWIFT_UNAVAILABLE("");
NS_ASSUME_NONNULL_END
@@ -0,0 +1,67 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Testing.h"
NS_ASSUME_NONNULL_BEGIN
/**
Miscellaneous low-level private interfaces available to extend standard FBLPromise functionality.
*/
@interface FBLPromise<Value>()
typedef void (^__nullable FBLPromiseOnFulfillBlock)(Value __nullable value)
NS_SWIFT_UNAVAILABLE("");
typedef void (^__nullable FBLPromiseOnRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
typedef id __nullable (^__nullable FBLPromiseChainedFulfillBlock)(Value __nullable value)
NS_SWIFT_UNAVAILABLE("");
typedef id __nullable (^__nullable FBLPromiseChainedRejectBlock)(NSError *error)
NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise.
*/
- (instancetype)initPending NS_SWIFT_UNAVAILABLE("");
/**
Creates a resolved promise.
@param resolution An object to resolve the promise with: either a value or an error.
@return A new resolved promise.
*/
- (instancetype)initWithResolution:(nullable id)resolution NS_SWIFT_UNAVAILABLE("");
/**
Invokes `fulfill` and `reject` blocks on `queue` when the receiver gets either fulfilled or
rejected respectively.
*/
- (void)observeOnQueue:(dispatch_queue_t)queue
fulfill:(FBLPromiseOnFulfillBlock)onFulfill
reject:(FBLPromiseOnRejectBlock)onReject NS_SWIFT_UNAVAILABLE("");
/**
Returns a new promise which gets resolved with the return value of `chainedFulfill` or
`chainedReject` blocks respectively. The blocks are invoked when the receiver gets either
fulfilled or rejected. If `nil` is passed to either block arg, the returned promise is resolved
with the same resolution as the receiver.
*/
- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
chainedReject:(FBLPromiseChainedRejectBlock)chainedReject NS_SWIFT_UNAVAILABLE("");
@end
NS_ASSUME_NONNULL_END
+41
View File
@@ -0,0 +1,41 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DotSyntax/FBLPromise+DotSyntax+All.h"
#import "DotSyntax/FBLPromise+DotSyntax+Always.h"
#import "DotSyntax/FBLPromise+DotSyntax+Any.h"
#import "DotSyntax/FBLPromise+DotSyntax+Async.h"
#import "DotSyntax/FBLPromise+DotSyntax+Catch.h"
#import "DotSyntax/FBLPromise+DotSyntax+Do.h"
#import "DotSyntax/FBLPromise+DotSyntax+Recover.h"
#import "DotSyntax/FBLPromise+DotSyntax+Resolve.h"
#import "DotSyntax/FBLPromise+DotSyntax+Then.h"
#import "DotSyntax/FBLPromise+DotSyntax+Timeout.h"
#import "DotSyntax/FBLPromise+DotSyntax+Validate.h"
#import "DotSyntax/FBLPromise+DotSyntax+When.h"
#import "FBLPromise+All.h"
#import "FBLPromise+Always.h"
#import "FBLPromise+Any.h"
#import "FBLPromise+Async.h"
#import "FBLPromise+Catch.h"
#import "FBLPromise+Do.h"
#import "FBLPromise+Recover.h"
#import "FBLPromise+Resolve.h"
#import "FBLPromise+Testing.h"
#import "FBLPromise+Then.h"
#import "FBLPromise+Timeout.h"
#import "FBLPromise+Validate.h"
#import "FBLPromise+When.h"
@@ -0,0 +1,36 @@
module FBLPromises {
umbrella header "FBLPromises.h"
export *
header "FBLPromise+All.h"
header "FBLPromise+Always.h"
header "FBLPromise+Any.h"
header "FBLPromise+Async.h"
header "FBLPromise+Catch.h"
header "FBLPromise+Do.h"
header "FBLPromise+Recover.h"
header "FBLPromise+Resolve.h"
header "FBLPromise+Testing.h"
header "FBLPromise+Then.h"
header "FBLPromise+Timeout.h"
header "FBLPromise+Validate.h"
header "FBLPromise+When.h"
header "DotSyntax/FBLPromise+DotSyntax.h"
header "DotSyntax/FBLPromise+DotSyntax+All.h"
header "DotSyntax/FBLPromise+DotSyntax+Always.h"
header "DotSyntax/FBLPromise+DotSyntax+Any.h"
header "DotSyntax/FBLPromise+DotSyntax+Async.h"
header "DotSyntax/FBLPromise+DotSyntax+Catch.h"
header "DotSyntax/FBLPromise+DotSyntax+Do.h"
header "DotSyntax/FBLPromise+DotSyntax+Recover.h"
header "DotSyntax/FBLPromise+DotSyntax+Resolve.h"
header "DotSyntax/FBLPromise+DotSyntax+Then.h"
header "DotSyntax/FBLPromise+DotSyntax+Timeout.h"
header "DotSyntax/FBLPromise+DotSyntax+Validate.h"
header "DotSyntax/FBLPromise+DotSyntax+When.h"
exclude header "FBLPromiseErrorPrivate.h"
exclude header "FBLPromisePrivate.h"
}
@@ -0,0 +1,78 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromisesTestInteroperability.h"
#import "FBLPromises.h"
#import "FBLPromisesTestHelpers.h"
@implementation FBLPromisesTestInteroperabilityObjC
+ (FBLPromise *)fulfillWithObject:(nullable id)object {
return [self fulfillWithObject:object delay:0.0];
}
+ (FBLPromise *)fulfillWithObject:(nullable id)object delay:(NSTimeInterval)delay {
return [self promiseWithValue:object error:nil delay:delay];
}
+ (FBLPromise *)rejectWithError:(NSError *)error {
return [self rejectWithError:error delay:0.0];
}
+ (FBLPromise *)rejectWithError:(NSError *)error delay:(NSTimeInterval)delay {
return [self promiseWithValue:nil error:error delay:delay];
}
+ (FBLPromise *)rejectWithException:(NSException *)exception {
return [self rejectWithException:exception delay:0.0];
}
+ (FBLPromise *)rejectWithException:(NSException *)exception delay:(NSTimeInterval)delay {
return [self promiseThrowException:exception delay:delay];
}
#pragma mark - Private
/**
Returns a promise which gets resolved after a delay either with a given error,
or with a value, if error is nil.
*/
+ (FBLPromise *)promiseWithValue:(nullable id)value
error:(NSError *__nullable)error
delay:(NSTimeInterval)delay {
return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
FBLDelay(delay, ^{
if (error) {
reject(error);
} else {
fulfill(value);
}
});
}];
}
+ (FBLPromise *)promiseThrowException:(NSException *__nullable)exception
delay:(NSTimeInterval)delay {
return [FBLPromise async:^(FBLPromiseFulfillBlock __unused _, FBLPromiseRejectBlock __unused __) {
// Can't use asynchronous FBLDelay because the exception will be caught by GCD in that case.
[NSThread sleepForTimeInterval:delay];
@throw exception; // NOLINT
}];
}
@end
@@ -0,0 +1,39 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
Executes the given work block on the main queue after time interval.
*/
static inline void FBLDelay(NSTimeInterval interval, void (^work)(void)) {
int64_t const timeToWait = (int64_t)(interval * NSEC_PER_SEC);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeToWait),
dispatch_get_main_queue(), ^{
work();
});
}
/**
Executes the given block multiple times according to the count variable and then returns
the average number of nanoseconds per execution. Isn't listed in any public libdispatch header,
although comes with a man page, so declaring manually here.
*/
FOUNDATION_EXTERN uint64_t dispatch_benchmark(size_t count, void (^block)(void));
NS_ASSUME_NONNULL_END
@@ -0,0 +1,37 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class FBLPromise<id>;
@interface FBLPromisesTestInteroperabilityObjC<Value> : NSObject
+ (FBLPromise<Value> *)fulfillWithObject:(nullable Value)object NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<Value> *)fulfillWithObject:(nullable Value)object
delay:(NSTimeInterval)delay NS_SWIFT_NAME(fulfill(_:delay:));
+ (FBLPromise<Value> *)rejectWithError:(NSError *)error NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<Value> *)rejectWithError:(NSError *)error
delay:(NSTimeInterval)delay NS_SWIFT_NAME(reject(_:delay:));
+ (FBLPromise<Value> *)rejectWithException:(NSException *)exception NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<Value> *)rejectWithException:(NSException *)exception
delay:(NSTimeInterval)delay NS_SWIFT_NAME(reject(_:delay:));
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,4 @@
module FBLPromisesTestHelpers {
header "FBLPromisesTestHelpers.h"
header "FBLPromisesTestInteroperability.h"
}
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Dispatch
/// Waits until all of the promises have been fulfilled.
/// If one of the promises is rejected, then the returned promise is rejected with same error.
/// If any other arbitrary value or `Error` appears in the array instead of `Promise`,
/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - promises: An array of promises to wait for.
/// - returns: Promise of an array containing the values of input promises in the same order.
public func all<Value>(
on queue: DispatchQueue = .main,
_ promises: Promise<Value>...
) -> Promise<[Value]> {
return all(on: queue, promises)
}
/// Waits until all of the promises have been fulfilled.
/// If one of the promises is rejected, then the returned promise is rejected with same error.
/// If any other arbitrary value or `Error` appears in the array instead of `Promise`,
/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - promises: An array of promises to wait for.
/// - returns: Promise of an array containing the values of input promises in the same order.
public func all<Value, Container: Sequence>(
on queue: DispatchQueue = .main,
_ promises: Container
) -> Promise<[Value]> where Container.Iterator.Element == Promise<Value> {
let promise = Promise<[Value]>(
Promise<[Value]>.ObjCPromise<AnyObject>.__onQueue(queue, all: promises.map { $0.objCPromise })
)
// Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved.
promises.forEach {
$0.objCPromise.__pendingObjects?.add(promise)
}
return promise
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Dispatch
public extension Promise {
/// Provides a way to always execute a given chained block.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - work: A block that always executes, no matter if `self` is rejected or fulfilled.
/// - returns: A new pending promise to be resolved with same resolution as `self`.
@discardableResult
public func always(on queue: DispatchQueue = .main, _ work: @escaping () -> Void) -> Promise {
let promise = Promise(objCPromise.__onQueue(queue, always: work))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
}
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Dispatch
/// Wait until any of the given promises are fulfilled.
/// If one of the given promises is rejected, then the returned promise is rejected with same
/// error. If any other arbitrary value or `Error` appears in the array instead of `Promise`,
/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - promises: Promises to wait for.
/// - returns: First promise, among the given ones, which was fulfilled.
public func any<Value>(
on queue: DispatchQueue = .main,
_ promises: Promise<Value>...
) -> Promise<Value> {
return any(on: queue, promises)
}
/// Wait until any of the given promises are fulfilled.
/// If one of the given promises is rejected, then the returned promise is rejected with same
/// error. If any other arbitrary value or `Error` appears in the array instead of `Promise`,
/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - promises: Promises to wait for.
/// - returns: First promise, among the given ones, which was fulfilled.
public func any<Value>(
on queue: DispatchQueue = .main,
_ promises: [Promise<Value>]
) -> Promise<Value> {
let promise = Promise<Value>(
Promise<Value>.ObjCPromise<AnyObject>.__onQueue(queue, any: promises.map { $0.objCPromise })
)
// Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved.
promises.forEach {
$0.objCPromise.__pendingObjects?.add(promise)
}
return promise
}
+44
View File
@@ -0,0 +1,44 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public extension Promise {
public typealias Fulfill = (Value) -> Void
public typealias Reject = (Error) -> Void
public typealias AsyncWork = (@escaping Fulfill, @escaping Reject) throws -> Void
/// Creates a pending promise and executes `work` block asynchronously on the given `queue`.
/// - parameters:
/// - queue: A queue to invoke the `work` block on.
/// - work: A block to perform any operations needed to resolve the promise.
public convenience init(on queue: DispatchQueue = .main, _ work: @escaping AsyncWork) {
let objCPromise = ObjCPromise<AnyObject>.__onQueue(queue) { fulfill, reject in
do {
try work({ value in
if let error = value as? NSError {
reject(error)
} else {
fulfill(Promise<Value>.asAnyObject(value))
}
}, reject)
} catch let error {
reject(error as NSError)
}
}
self.init(objCPromise)
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(self)
}
}
+33
View File
@@ -0,0 +1,33 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public extension Promise {
public typealias Catch = (Error) -> Void
/// Creates a pending promise which eventually gets resolved with same resolution as `self`.
/// If `self` is rejected, then `reject` block is executed asynchronously on the main queue.
/// - parameters:
/// - queue: A queue to invoke the `reject` block on.
/// - reject: A block to handle the error that `self` was rejected with.
/// - returns: A new pending promise.
@discardableResult
public func `catch`(on queue: DispatchQueue = .main, _ reject: @escaping Catch) -> Promise {
let promise = Promise(objCPromise.__onQueue(queue, catch: { reject($0 as NSError) }))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
}
+38
View File
@@ -0,0 +1,38 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public extension Promise {
public typealias Work = () throws -> Value
/// Creates a pending promise to be resolved with the return value of `work` block which is
/// executed asynchronously on the given `queue`.
/// - parameters:
/// - queue: A queue to invoke the `work` block on.
/// - work: A block to perform any operations needed to resolve the promise.
public convenience init(on queue: DispatchQueue = .main, _ work: @escaping Work) {
let objCPromise = ObjCPromise<AnyObject>.__onQueue(queue) {
do {
let resolution = try work()
return resolution as? NSError ?? Promise<Value>.asAnyObject(resolution)
} catch let error {
return error as NSError
}
}
self.init(objCPromise)
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(self)
}
}
+60
View File
@@ -0,0 +1,60 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public extension Promise {
/// Provides a new promise to recover in case `self` gets rejected.
/// - parameters:
/// - queue: A queue to execute `recovery` block on.
/// - recovery: A block to handle the error that `self` was rejected with.
/// - returns: A new pending promise to use instead of the rejected one that gets resolved with
/// the same resolution as the promise returned from `recovery` block.
@discardableResult
public func recover(on queue: DispatchQueue = .main,
_ recovery: @escaping (Error) throws -> Promise) -> Promise {
let promise = Promise(objCPromise.__onQueue(queue, recover: {
do {
return try recovery($0).objCPromise
} catch let error {
return error as NSError
}
}))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
/// Provides a new promise to recover in case `self` gets rejected.
/// - parameters:
/// - queue: A queue to execute `recovery` block on.
/// - recovery: A block to handle the error that `self` was rejected with.
/// - returns: A new pending promise to use instead of the rejected one that gets resolved with
/// the value returned from `recovery` block.
@discardableResult
public func recover(on queue: DispatchQueue = .main,
_ recovery: @escaping (Error) throws -> Value) -> Promise {
let promise = Promise(objCPromise.__onQueue(queue, recover: { error in
do {
return Promise<Value>.asAnyObject(try recovery(error)) as Any
} catch let error {
return error as NSError
}
}))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
}
+151
View File
@@ -0,0 +1,151 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// Provides a convenient way to convert methods that use common callback patterns into `Promise`s.
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with no arguments.
/// - returns: A new pending promise to be resolved with `nil` when completion handler finishes.
public func resolve(_ work: @escaping (@escaping () -> Void) throws -> Void) -> Promise<Any?> {
return Promise<Any?> { fulfill, _ in
try work { fulfill(nil) }
}
}
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with one argument of generic `Value` type.
/// - returns: A new pending promise to be resolved with the value provided by completion handler
/// when it finishes.
public func resolve<Value>(
_ work: @escaping (@escaping (Value) -> Void) throws -> Void
) -> Promise<Value> {
return Promise<Value> { fulfill, _ in
try work { fulfill($0) }
}
}
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with one argument of optional generic `Value` type.
/// - returns: A new pending promise to be resolved with the value or error provided by completion
/// handler when it finishes.
public func resolve<Value>(
_ work: @escaping (@escaping (Value?) -> Void) throws -> Void
) -> Promise<Value?> {
return Promise<Value?> { fulfill, _ in
try work { fulfill($0) }
}
}
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with two arguments: a generic of `Value` type and
/// an optional `Error`.
/// - returns: A new pending promise to be resolved with the value or error provided by completion
/// handler when it finishes.
public func resolve<Value>(
_ work: @escaping (@escaping (Value, Error?) -> Void) throws -> Void
) -> Promise<Value> {
return Promise<Value> { fulfill, reject in
try work { value, error in
if let error = error {
reject(error)
} else {
fulfill(value)
}
}
}
}
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with two arguments: an optional `Error` and a generic of
/// `Value` type.
/// - returns: A new pending promise to be resolved with the error or value provided by completion
/// handler when it finishes.
public func resolve<Value>(
_ work: @escaping (@escaping (Error?, Value) -> Void) throws -> Void
) -> Promise<Value> {
return Promise<Value> { fulfill, reject in
try work { error, value in
if let error = error {
reject(error)
} else {
fulfill(value)
}
}
}
}
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with two arguments: an optional generic of `Value` type
/// and an optional `Error`.
/// - returns: A new pending promise to be resolved with the value or error provided by completion
/// handler when it finishes.
public func resolve<Value>(
_ work: @escaping (@escaping (Value?, Error?) -> Void) throws -> Void
) -> Promise<Value?> {
return Promise<Value?> { fulfill, reject in
try work { value, error in
if let error = error {
reject(error)
} else {
fulfill(value)
}
}
}
}
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with two arguments: an optional `Error` and an optional
/// generic of `Value` type.
/// - returns: A new pending promise to be resolved with the error or value provided by completion
/// handler when it finishes.
public func resolve<Value>(
_ work: @escaping (@escaping (Error?, Value?) -> Void) throws -> Void
) -> Promise<Value?> {
return Promise<Value?> { fulfill, reject in
try work { error, value in
if let error = error {
reject(error)
} else {
fulfill(value)
}
}
}
}
/// Creates a new promise to be resolved when completion handler gets invoked.
/// - parameter work: A block to execute on the main queue to invoke some API that requires
/// a completion handler with three arguments: two optionals of `Any` type
/// and an optional `Error`.
/// - returns: A new pending promise to be resolved with a tuple of optional values or an error
/// provided by completion handler when it finishes.
public func resolve<Value1, Value2>(
_ work: @escaping (@escaping (Value1?, Value2?, Error?) -> Void) throws -> Void
) -> Promise<(Value1?, Value2?)> {
return Promise<(Value1?, Value2?)> { fulfill, reject in
try work { value1, value2, error in
if let error = error {
reject(error)
} else {
fulfill((value1, value2))
}
}
}
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import FBLPromises
extension DispatchGroup {
/// Dispatch group for promises that is typically used to wait for all scheduled blocks.
static var promises: DispatchGroup { return Promise<Any>.ObjCPromise<AnyObject>.__dispatchGroup }
}
/// Waits for all scheduled promise blocks.
/// - parameter timeout: Maximum time to wait.
/// - returns: `true` if all promise blocks have completed before `timeout` and `false` otherwise.
func waitForPromises(timeout: TimeInterval) -> Bool {
return __FBLWaitForPromisesWithTimeout(timeout)
}
+91
View File
@@ -0,0 +1,91 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public extension Promise {
public typealias Then<Result> = (Value) throws -> Result
/// Creates a pending promise which eventually gets resolved with the same resolution as the
/// promise returned from `work` block. The `work` block is executed asynchronously on the given
/// `queue` only when `self` is fulfilled. If `self` is rejected, the returned promise is also
/// rejected with the same error.
/// - parameters:
/// - queue: A queue to invoke the `work` block on.
/// - work: A block to handle the value that `self` was fulfilled with.
/// - returns: A new pending promise to be resolved with the same resolution as the promise
/// returned from the `work` block.
@discardableResult
public func then<Result>(on queue: DispatchQueue = .main,
_ work: @escaping Then<Promise<Result>>) -> Promise<Result> {
let promise = Promise<Result>(objCPromise.__onQueue(queue, then: { value in
guard let value = Promise<Value>.asValue(value) else { preconditionFailure() }
do {
return try work(value).objCPromise
} catch let error {
return error as NSError
}
}))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
/// Creates a pending promise which eventually gets resolved with the value returned from `work`
/// block. The `work` block is executed asynchronously on the given `queue` only when `self` is
/// fulfilled. If `self` is rejected, the returned promise is also rejected with the same error.
/// - parameters:
/// - queue: A queue to invoke the `work` block on.
/// - work: A block to handle the value that `self` was fulfilled with.
/// - returns: A new pending promise to be resolved with the value returned from the `work` block.
@discardableResult
public func then<Result>(on queue: DispatchQueue = .main,
_ work: @escaping Then<Result>) -> Promise<Result> {
let promise = Promise<Result>(objCPromise.__onQueue(queue, then: { value in
guard let value = Promise<Value>.asValue(value) else { preconditionFailure() }
do {
let value = try work(value)
return value as? NSError ?? Promise<Result>.asAnyObject(value)
} catch let error {
return error as NSError
}
}))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
/// Creates a pending promise which eventually gets resolved with the same resolution as `self`.
/// `work` block is executed asynchronously on the given `queue` only when `self` is fulfilled.
/// If `self` is rejected, the returned promise is also rejected with the same error.
/// - parameters:
/// - queue: A queue to invoke the `work` block on.
/// - work: A block to handle the value that `self` was fulfilled with.
/// - returns: A new pending promise to be resolved with the value passed into the `work` block.
@discardableResult
public func then(on queue: DispatchQueue = .main, _ work: @escaping Then<Void>) -> Promise {
let promise = Promise(objCPromise.__onQueue(queue, then: { value in
guard let value = Promise<Value>.asValue(value) else { preconditionFailure() }
do {
try work(value)
return Promise<Value>.asAnyObject(value)
} catch let error {
return error as NSError
}
}))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
}
+32
View File
@@ -0,0 +1,32 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public extension Promise {
/// Waits on a promise for a given interval or rejects the promise if it exceeds the time limit.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - interval: Time to wait in seconds.
/// - returns: A new pending promise that gets either resolved with same resolution as `self` or
/// rejected with `PromiseError.timedOut` error.
@discardableResult
public func timeout(on queue: DispatchQueue = .main, _ interval: TimeInterval) -> Promise {
let promise = Promise(objCPromise.__onQueue(queue, timeout: interval))
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(promise)
return promise
}
}
+33
View File
@@ -0,0 +1,33 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Dispatch
public extension Promise {
/// Validates a fulfilled value or rejects the value if it can not be validated.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - predicate: An expression to validate.
/// - returns: A new pending promise that gets either resolved with same resolution as `self` or
/// rejected with `PromiseError.validationFailure` error.
@discardableResult
public func validate(on queue: DispatchQueue = .main,
_ predicate: @escaping (Value) -> Bool) -> Promise {
return then { (value: Value) -> Value in
guard predicate(value) else { throw PromiseError.validationFailure }
return value
}
}
}
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
/// Waits for all of the given promises to be fulfilled or rejected.
/// If all promises are rejected, then the returned promise is rejected with same error
/// as the last one rejected.
/// If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array
/// of values or `Error`s, matching the original order of fulfilled or rejected promises
/// respectively.
/// If any other arbitrary value or `Error` appears in the array instead of `Promise`,
/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - promises: Promises to wait for.
/// - returns: Promise of array containing the values or `Error`s of input promises in their
/// original order.
public func when<Value>(
on queue: DispatchQueue = .main,
_ promises: Promise<Value>...
) -> Promise<[Value]> {
return when(on: queue, promises)
}
/// Waits for all of the given promises to be fulfilled or rejected.
/// If all promises are rejected, then the returned promise is rejected with same error
/// as the last one rejected.
/// If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array
/// of values or `Error`s, matching the original order of fulfilled or rejected promises
/// respectively.
/// If any other arbitrary value or `Error` appears in the array instead of `Promise`,
/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly.
/// - parameters:
/// - queue: A queue to dispatch on.
/// - promises: Promises to wait for.
/// - returns: Promise of array containing the values or `Error`s of input promises in their
/// original order.
public func when<Value, Container: Sequence>(
on queue: DispatchQueue = .main,
_ promises: Container
) -> Promise<[Value]> where Container.Iterator.Element == Promise<Value> {
let promise = Promise<[Value]>(
Promise<[Value]>.ObjCPromise<AnyObject>.__onQueue(queue, when: promises.map { $0.objCPromise })
)
// Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved.
promises.forEach {
$0.objCPromise.__pendingObjects?.add(promise)
}
return promise
}
+115
View File
@@ -0,0 +1,115 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import FBLPromises
/// Promises synchronization construct in Swift. Leverages ObjC implementation internally.
public final class Promise<Value> {
public typealias ObjCPromise<Value: AnyObject> = FBLPromise<Value>
/// Creates a new promise with an existing ObjC promise.
public init<Value>(_ objCPromise: ObjCPromise<Value>) {
guard let objCPromise = objCPromise as? ObjCPromise<AnyObject> else { preconditionFailure() }
self.objCPromise = objCPromise
}
/// Creates a new pending promise.
public static func pending() -> Promise<Value> {
return Promise<Value>.init(ObjCPromise<AnyObject>.__pending())
}
/// Creates a new promise rejected with the given `error`.
public convenience init(_ error: Error) {
self.init(ObjCPromise<AnyObject>.__resolved(with: error as NSError))
}
/// Creates a new promise resolved with the result of `work` block.
public convenience init(_ work: @autoclosure () throws -> Value) {
do {
let resolution = try work()
switch resolution {
case let error as NSError:
self.init(error)
case let objCPromise as ObjCPromise<AnyObject>:
self.init(objCPromise)
default:
self.init(ObjCPromise<AnyObject>.__resolved(with: Promise<Value>.asAnyObject(resolution)))
}
} catch let error {
self.init(error as NSError)
}
}
/// Resolves `self` with the given `resolution`.
public func fulfill(_ resolution: Value) {
objCPromise.__fulfill(Promise<Value>.asAnyObject(resolution))
}
/// Rejects `self` with the given `error`.
public func reject(_ error: Error) {
objCPromise.__fulfill(error as NSError)
}
/// Converts `self` into ObjC promise.
public func asObjCPromise<Value>() -> ObjCPromise<Value> {
guard let objCPromise = objCPromise as? ObjCPromise<Value> else { preconditionFailure() }
return objCPromise
}
// MARK: Internal
/// Underlying ObjC counterpart.
let objCPromise: ObjCPromise<AnyObject>
var isPending: Bool { return objCPromise.__isPending }
var isFulfilled: Bool { return objCPromise.__isFulfilled }
var isRejected: Bool { return objCPromise.__isRejected }
var value: Value? {
let objCValue = objCPromise.__value
if Promise<AnyObject>.isBridgedNil(objCValue) { return nil }
guard let value = objCValue as? Value else { preconditionFailure() }
return value
}
var error: Error? { return objCPromise.__error }
/// Converts generic `Value` to `AnyObject`.
static func asAnyObject(_ value: Value) -> AnyObject? {
return Promise<Value>.isBridgedNil(value) ? nil : value as AnyObject
}
/// Converts `AnyObject` to generic `Value`.
static func asValue(_ value: AnyObject?) -> Value? {
// Swift nil becomes NSNull during bridging.
return value as? Value ?? NSNull() as AnyObject as? Value
}
// MARK: Private
/// Checks if generic `Value` is bridged ObjC `nil`.
private static func isBridgedNil(_ value: Value?) -> Bool {
// Swift nil becomes NSNull during bridging.
return !(value is NSNull) && value as AnyObject is NSNull
}
}
extension Promise: CustomStringConvertible {
public var description: String {
return isFulfilled ? "Fulfilled: \(String(describing: value ?? nil))" :
isRejected ? "Rejected: \(String(describing: error ?? nil))" : "Pending: \(Value.self)"
}
}
+96
View File
@@ -0,0 +1,96 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import FBLPromises
/// Internal errors that `Promise` can throw.
/// Indirectly conforms to `Swift.Error` through conformance to `Swift.CustomNSError` below.
/// Not placing it under extension `Promise` for convenience to avoid collisions with `Swift.Error`.
public enum PromiseError {
case nsException(NSExceptionName, String?, [AnyHashable: Any]?, [NSNumber], [String])
case timedOut
case validationFailure
}
/// Downcasting from `Swift.Error` and `NSException`.
extension PromiseError {
public init?(_ error: Error) {
let error = error as NSError
if error.domain != __FBLPromiseErrorDomain { return nil }
switch error.code {
case __FBLPromiseErrorCode.exception.rawValue:
let errorUserInfo = error.userInfo
guard let name = errorUserInfo[__FBLPromiseErrorUserInfoExceptionNameKey] as? NSExceptionName,
let returnAddresses: [NSNumber] =
errorUserInfo[__FBLPromiseErrorUserInfoExceptionReturnAddressesKey] as? [NSNumber],
let callStack: [String] =
errorUserInfo[__FBLPromiseErrorUserInfoExceptionCallStackKey] as? [String]
else { return nil }
let reason = errorUserInfo[__FBLPromiseErrorUserInfoExceptionReasonKey] as? String
let userInfo =
errorUserInfo[__FBLPromiseErrorUserInfoExceptionUserInfoKey] as? [AnyHashable: Any]
self = .nsException(name, reason, userInfo, returnAddresses, callStack)
case __FBLPromiseErrorCode.timedOut.rawValue:
self = .timedOut
case __FBLPromiseErrorCode.validationFailure.rawValue:
self = .validationFailure
default:
return nil
}
}
public init?(_ nsException: NSException) {
self = .nsException(nsException.name,
nsException.reason,
nsException.userInfo,
nsException.callStackReturnAddresses,
nsException.callStackSymbols)
}
}
extension PromiseError: CustomNSError {
public static var errorDomain: String {
return __FBLPromiseErrorDomain
}
public var errorCode: Int {
switch self {
case .nsException:
return __FBLPromiseErrorCode.exception.rawValue
case .timedOut:
return __FBLPromiseErrorCode.timedOut.rawValue
case .validationFailure:
return __FBLPromiseErrorCode.validationFailure.rawValue
}
}
public var errorUserInfo: [String: Any] {
if case let .nsException(name, reason, userInfo, returnAddresses, callStack) = self {
return [
__FBLPromiseErrorUserInfoExceptionNameKey: name,
__FBLPromiseErrorUserInfoExceptionReasonKey: reason as Any,
__FBLPromiseErrorUserInfoExceptionUserInfoKey: userInfo as Any,
__FBLPromiseErrorUserInfoExceptionReturnAddressesKey: returnAddresses,
__FBLPromiseErrorUserInfoExceptionCallStackKey: callStack
]
}
return [String: Any]()
}
}
extension PromiseError: Equatable {
public static func == (lhs: PromiseError, rhs: PromiseError) -> Bool {
return (lhs as NSError).isEqual(rhs as NSError)
}
}
@@ -0,0 +1,90 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
/// Namespace for test helpers.
public struct Test {
/// Executes `work` after a time `interval` on the main queue.
public static func delay(_ interval: TimeInterval, work: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
work()
}
}
// Phony errors.
public enum Error: Int, CustomNSError {
case code13 = 13
case code42 = 42
public static var errorDomain: String {
return "com.google.Promises.Test.Error"
}
public var errorCode: Int { return rawValue }
public var errorUserInfo: [String: Any] { return [:] }
}
}
/// Convenience `NSError` accessors for `Error` protocol.
public extension Error {
var domain: String { return (self as NSError).domain }
var code: Int { return (self as NSError).code }
var userInfo: [AnyHashable: Any] { return (self as NSError).userInfo }
}
/// Compare two `Error`.
public func == (lhs: Error?, rhs: Error?) -> Bool {
switch (lhs, rhs) {
case (nil, nil):
return true
case (nil, _?), (_?, nil):
return false
case let (lhs?, rhs?):
return (lhs as NSError).isEqual(rhs as NSError)
}
}
/// Compare two arrays of the same generic type conforming to `Equatable` protocol.
public func ==<T: Equatable>(lhs: [T?], rhs: [T?]) -> Bool {
if lhs.count != rhs.count { return false }
for (l, r) in zip(lhs, rhs) where l != r { return false }
return true
}
/// Compare two arrays of different primitive types.
public func == (lhs: [Any?], rhs: [Any?]) -> Bool {
if lhs.count != rhs.count { return false }
for (l, r) in zip(lhs, rhs) {
switch (l, r) {
case (nil, nil):
break
case (let l as [Any?], let r as [Any?]):
guard l == r else { return false }
case (let l as Int, let r as Int):
guard l == r else { return false }
case (let l as Double, let r as Double):
guard l == r else { return false }
case (let l as String, let r as String):
guard l == r else { return false }
case (let l as Error, let r as Error):
guard l == r else { return false }
default:
return false
}
}
return true
}
@@ -0,0 +1,69 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import Promises
@objc(FBLPromisesTestInteroperabilitySwift)
public class Interoperability: NSObject {
@objc
public static func fulfill(
_ object: Any?, delay: TimeInterval
) -> Promise<Any?>.ObjCPromise<AnyObject> {
return promise(object, error: nil, delay: delay).asObjCPromise()
}
@objc
public static func fulfill(
number: NSNumber?, delay: TimeInterval
) -> Promise<NSNumber?>.ObjCPromise<NSNumber> {
return promise(number, error: nil, delay: delay).asObjCPromise()
}
@objc
public static func reject(
_ error: Error, delay: TimeInterval
) -> Promise<Any?>.ObjCPromise<AnyObject> {
return (promise(nil, error: error, delay: delay) as Promise<Any?>).asObjCPromise()
}
@objc
public static func `throw`(
_ error: Error, delay: TimeInterval
) -> Promise<Any?>.ObjCPromise<AnyObject> {
return (
promise(nil, error: error, shouldThrow: true, delay: delay) as Promise<Any?>
).asObjCPromise()
}
// MARK: Internal
static func promise<T>(
_ value: T, error: Error? = nil, shouldThrow: Bool = false, delay: TimeInterval = 0.0
) -> Promise<T> {
return Promise { fulfill, reject in
if let error = error, shouldThrow {
Thread.sleep(forTimeInterval: delay)
throw error
}
Test.delay(delay) {
if let error = error {
reject(error)
} else {
fulfill(value)
}
}
}
}
}
@@ -0,0 +1,66 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Catch.h"
#import <XCTest/XCTest.h>
#import "FBLPromise+Testing.h"
#import "FBLPromisesTestHelpers.h"
#import "PromisesTestHelpers-Swift.h"
@interface FBLPromiseCatchInteroperabilityTests : XCTestCase
@end
@implementation FBLPromiseCatchInteroperabilityTests
- (void)testPromiseReject {
// Arrange.
NSError *expectedError = [NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil];
// Act.
FBLPromise *promise = [FBLPromisesTestInteroperabilitySwift
reject:[NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil]
delay:0.1];
[promise catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(promise.error, expectedError);
XCTAssertNil(promise.value);
}
- (void)testPromiseThrow {
// Arrange.
NSError *expectedError = [NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil];
// Act.
FBLPromise *promise = [FBLPromisesTestInteroperabilitySwift
throw:[NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil]
delay:0.1];
[promise catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(promise.error, expectedError);
XCTAssertNil(promise.value);
}
@end
@@ -0,0 +1,60 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Then.h"
#import <XCTest/XCTest.h>
#import "FBLPromise+Testing.h"
#import "FBLPromisesTestHelpers.h"
#import "PromisesTestHelpers-Swift.h"
@interface FBLPromiseThenInteroperabilityTests : XCTestCase
@end
@implementation FBLPromiseThenInteroperabilityTests
- (void)testPromiseFulfillNumberNil {
// Act.
FBLPromise<NSNumber *> *promise =
[FBLPromisesTestInteroperabilitySwift fulfillWithNumber:nil delay:0.1];
[promise then:^id(NSNumber *value) {
XCTAssertNil(value);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertNil(promise.value);
XCTAssertNil(promise.error);
}
- (void)testPromiseFulfillNumberNonNil {
// Act.
FBLPromise<NSNumber *> *promise =
[FBLPromisesTestInteroperabilitySwift fulfillWithNumber:@42 delay:0.1];
[promise then:^id(NSNumber *value) {
XCTAssertEqualObjects(value, @42);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(promise.value, @42);
XCTAssertNil(promise.error);
}
@end
@@ -0,0 +1,300 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Then.h"
#import <XCTest/XCTest.h>
#import "FBLPromisesTestHelpers.h"
static size_t const FBLPromisePerformanceTestIterationCount = 10000;
NS_INLINE void FBLLogAverageTime(uint64_t time) {
NSLog(@"Average time: %.10lf", (double)time / NSEC_PER_SEC);
}
NS_INLINE void FBLLogTotalTime(NSTimeInterval time) {
NSLog(@"Total time: %.10lf", time);
}
@interface FBLPromiseThenPerformanceTests : XCTestCase
@end
@implementation FBLPromiseThenPerformanceTests
#pragma mark GCD
/**
Measures the average time needed to get into a dispatch_async block.
*/
- (void)testDispatchAsyncOnSerialQueue {
// Arrange.
XCTestExpectation *expectation = [self expectationWithDescription:@""];
expectation.expectedFulfillmentCount = FBLPromisePerformanceTestIterationCount;
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// Act.
dispatch_async(dispatch_get_main_queue(), ^{
uint64_t time = dispatch_benchmark(FBLPromisePerformanceTestIterationCount, ^{
dispatch_async(queue, ^{
dispatch_semaphore_signal(semaphore);
[expectation fulfill];
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
FBLLogAverageTime(time);
});
// Assert.
[self waitForExpectationsWithTimeout:10 handler:nil];
}
/**
Measures the average time needed to get into a doubly nested dispatch_async block.
*/
- (void)testDoubleDispatchAsyncOnSerialQueue {
// Arrange.
XCTestExpectation *expectation = [self expectationWithDescription:@""];
expectation.expectedFulfillmentCount = FBLPromisePerformanceTestIterationCount;
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// Act.
dispatch_async(dispatch_get_main_queue(), ^{
uint64_t time = dispatch_benchmark(FBLPromisePerformanceTestIterationCount, ^{
dispatch_async(queue, ^{
dispatch_async(queue, ^{
dispatch_semaphore_signal(semaphore);
[expectation fulfill];
});
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
FBLLogAverageTime(time);
});
// Assert.
[self waitForExpectationsWithTimeout:10 handler:nil];
}
/**
Measures the average time needed to get into a triply nested dispatch_async block.
*/
- (void)testTripleDispatchAsyncOnSerialQueue {
// Arrange.
XCTestExpectation *expectation = [self expectationWithDescription:@""];
expectation.expectedFulfillmentCount = FBLPromisePerformanceTestIterationCount;
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// Act.
dispatch_async(dispatch_get_main_queue(), ^{
uint64_t time = dispatch_benchmark(FBLPromisePerformanceTestIterationCount, ^{
dispatch_async(queue, ^{
dispatch_async(queue, ^{
dispatch_async(queue, ^{
dispatch_semaphore_signal(semaphore);
[expectation fulfill];
});
});
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
FBLLogAverageTime(time);
});
// Assert.
[self waitForExpectationsWithTimeout:10 handler:nil];
}
/**
Measures the total time needed to perform a lot of dispatch_async blocks on a concurrent queue.
*/
- (void)testDispatchAsyncOnConcurrentQueue {
// Arrange.
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT,
QOS_CLASS_USER_INITIATED, 0));
dispatch_group_t group = dispatch_group_create();
NSMutableArray<dispatch_block_t> *blocks =
[NSMutableArray arrayWithCapacity:FBLPromisePerformanceTestIterationCount];
for (NSUInteger i = 0; i < FBLPromisePerformanceTestIterationCount; ++i) {
dispatch_group_enter(group);
void (^block)() = ^{
dispatch_group_leave(group);
};
[blocks addObject:block];
}
NSDate *startDate = [NSDate date];
// Act.
for (NSUInteger i = 0; i < FBLPromisePerformanceTestIterationCount; ++i) {
dispatch_async(queue, blocks[i]);
}
// Assert.
XCTAssert(dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)) == 0,
@"Asynchronous wait failed: Exceeded timeout of 1 second.");
NSDate *endDate = [NSDate date];
FBLLogTotalTime([endDate timeIntervalSinceDate:startDate]);
}
#pragma mark FBLPromises
/**
Measures the average time needed to create a resolved FBLPromise and get into a `then` block
chained to it.
*/
- (void)testThenOnSerialQueue {
// Arrange.
XCTestExpectation *expectation = [self expectationWithDescription:@""];
expectation.expectedFulfillmentCount = FBLPromisePerformanceTestIterationCount;
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// Act.
dispatch_async(dispatch_get_main_queue(), ^{
uint64_t time = dispatch_benchmark(FBLPromisePerformanceTestIterationCount, ^{
[[FBLPromise resolvedWith:@YES] onQueue:queue
then:^id(id result) {
dispatch_semaphore_signal(semaphore);
[expectation fulfill];
return result;
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
FBLLogAverageTime(time);
});
// Assert.
[self waitForExpectationsWithTimeout:10 handler:nil];
}
/**
Measures the average time needed to create a resolved FBLPromise, chain two `then` blocks on it
and get into the last `then` block.
*/
- (void)testDoubleThenOnSerialQueue {
// Arrange.
XCTestExpectation *expectation = [self expectationWithDescription:@""];
expectation.expectedFulfillmentCount = FBLPromisePerformanceTestIterationCount;
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// Act.
dispatch_async(dispatch_get_main_queue(), ^{
uint64_t time = dispatch_benchmark(FBLPromisePerformanceTestIterationCount, ^{
[[[FBLPromise resolvedWith:@YES] onQueue:queue
then:^id(id result) {
return result;
}] onQueue:queue
then:^id(id result) {
dispatch_semaphore_signal(semaphore);
[expectation fulfill];
return result;
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
FBLLogAverageTime(time);
});
// Assert.
[self waitForExpectationsWithTimeout:10 handler:nil];
}
/**
Measures the average time needed to create a resolved FBLPromise, chain three `then` blocks on it
and get into the last `then` block.
*/
- (void)testTripleThenOnSerialQueue {
// Arrange.
XCTestExpectation *expectation = [self expectationWithDescription:@""];
expectation.expectedFulfillmentCount = FBLPromisePerformanceTestIterationCount;
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// Act.
dispatch_async(dispatch_get_main_queue(), ^{
uint64_t time = dispatch_benchmark(FBLPromisePerformanceTestIterationCount, ^{
[[[[FBLPromise resolvedWith:@YES] onQueue:queue
then:^id(id result) {
return result;
}] onQueue:queue
then:^id(id result) {
return result;
}] onQueue:queue
then:^id(id result) {
dispatch_semaphore_signal(semaphore);
[expectation fulfill];
return result;
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
FBLLogAverageTime(time);
});
// Assert.
[self waitForExpectationsWithTimeout:10 handler:nil];
}
/**
Measures the total time needed to resolve a lot of pending FBLPromise with chained `then` blocks
on them on a concurrent queue and wait for each of them to get into chained block.
*/
- (void)testThenOnConcurrentQueue {
// Arrange.
dispatch_queue_t queue = dispatch_queue_create(
__FUNCTION__, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT,
QOS_CLASS_USER_INITIATED, 0));
dispatch_group_t group = dispatch_group_create();
NSMutableArray<FBLPromise *> *promises =
[NSMutableArray arrayWithCapacity:FBLPromisePerformanceTestIterationCount];
for (NSUInteger i = 0; i < FBLPromisePerformanceTestIterationCount; ++i) {
dispatch_group_enter(group);
FBLPromise *promise = [FBLPromise pendingPromise];
[promise onQueue:queue
then:^id(id result) {
dispatch_group_leave(group);
return result;
}];
[promises addObject:promise];
}
NSDate *startDate = [NSDate date];
// Act.
[promises makeObjectsPerformSelector:@selector(fulfill:) withObject:@YES];
// Assert.
XCTAssert(dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)) == 0,
@"Asynchronous wait failed: Exceeded timeout of 1 second.");
NSDate *endDate = [NSDate date];
FBLLogTotalTime([endDate timeIntervalSinceDate:startDate]);
}
@end
@@ -0,0 +1,232 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+All.h"
#import <XCTest/XCTest.h>
#import "FBLPromise+Async.h"
#import "FBLPromise+Catch.h"
#import "FBLPromise+Testing.h"
#import "FBLPromise+Then.h"
#import "FBLPromisesTestHelpers.h"
@interface FBLPromiseAllTests : XCTestCase
@end
@implementation FBLPromiseAllTests
- (void)testPromiseAll {
// Arrange.
NSArray *expectedValues = @[ @42, @"hello world", @[ @42 ], [NSNull null] ];
FBLPromise<NSNumber *> *promise1 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@42);
});
}];
FBLPromise<NSString *> *promise2 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(1, ^{
fulfill(@"hello world");
});
}];
FBLPromise<NSArray<NSNumber *> *> *promise3 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(2, ^{
fulfill(@[ @42 ]);
});
}];
FBLPromise *promise4 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(3, ^{
fulfill(nil);
});
}];
// Act.
FBLPromise<NSArray *> *combinedPromise =
[[FBLPromise all:@[ promise1, promise2, promise3, promise4 ]] then:^id(NSArray *value) {
XCTAssertEqualObjects(value, expectedValues);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(combinedPromise.value, expectedValues);
XCTAssertNil(combinedPromise.error);
}
- (void)testPromiseAllEmpty {
// Act.
FBLPromise<NSArray *> *promise = [[FBLPromise all:@[]] then:^id(NSArray *value) {
XCTAssertEqualObjects(value, @[]);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(promise.value, @[]);
XCTAssertNil(promise.error);
}
- (void)testPromiseAllRejectFirst {
// Arrange.
FBLPromise<NSNumber *> *promise1 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(1, ^{
fulfill(@42);
});
}];
FBLPromise<NSString *> *promise2 =
[FBLPromise async:^(FBLPromiseFulfillBlock __unused _, FBLPromiseRejectBlock reject) {
FBLDelay(0.1, ^{
reject([NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil]);
});
}];
// Act.
FBLPromise<NSArray *> *combinedPromise =
[[[FBLPromise all:@[ promise1, promise2 ]] then:^id(id __unused _) {
XCTFail();
return nil;
}] catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqual(combinedPromise.error.code, 42);
XCTAssertNil(combinedPromise.value);
}
- (void)testPromiseAllRejectLast {
// Arrange.
FBLPromise<NSNumber *> *promise1 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@42);
});
}];
FBLPromise<NSString *> *promise2 =
[FBLPromise async:^(FBLPromiseFulfillBlock __unused _, FBLPromiseRejectBlock reject) {
FBLDelay(1, ^{
reject([NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil]);
});
}];
// Act.
FBLPromise<NSArray *> *combinedPromise =
[[[FBLPromise all:@[ promise1, promise2 ]] then:^id(id __unused _) {
XCTFail();
return nil;
}] catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqual(combinedPromise.error.code, 42);
XCTAssertNil(combinedPromise.value);
}
- (void)testPromiseAllWithValues {
// Arrange.
NSArray *expectedValues = @[ @42, @"hello world", @[ @42 ], [NSNull null] ];
FBLPromise<NSArray<NSNumber *> *> *promise1 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@[ @42 ]);
});
}];
FBLPromise *promise2 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(1, ^{
fulfill(nil);
});
}];
// Act.
FBLPromise<NSArray *> *combinedPromise =
[[FBLPromise all:@[ @42, @"hello world", promise1, promise2 ]] then:^id(NSArray *value) {
XCTAssertEqualObjects(value, expectedValues);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(combinedPromise.value, expectedValues);
XCTAssertNil(combinedPromise.error);
}
- (void)testPromiseAllWithError {
// Arrange.
NSError *error = [NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil];
FBLPromise<NSArray<NSNumber *> *> *promise =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@[ @42 ]);
});
}];
// Act.
FBLPromise<NSArray *> *combinedPromise =
[[[FBLPromise all:@[ @42, error, promise ]] then:^id(id __unused _) {
XCTFail();
return nil;
}] catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqual(combinedPromise.error.code, 42);
XCTAssertNil(combinedPromise.value);
}
/**
Promise created with `all` should not deallocate until it gets resolved.
*/
- (void)testPromiseAllNoDeallocUntilResolved {
// Arrange.
FBLPromise *promise = [FBLPromise pendingPromise];
FBLPromise __weak *weakExtendedPromise1;
FBLPromise __weak *weakExtendedPromise2;
// Act.
@autoreleasepool {
XCTAssertNil(weakExtendedPromise1);
XCTAssertNil(weakExtendedPromise2);
FBLPromise *extendedPromise1 = [FBLPromise all:@[ promise ]];
FBLPromise *extendedPromise2 = [FBLPromise all:@[ promise ]];
weakExtendedPromise1 = extendedPromise1;
weakExtendedPromise2 = extendedPromise2;
XCTAssertNotNil(weakExtendedPromise1);
XCTAssertNotNil(weakExtendedPromise2);
}
// Assert.
XCTAssertNotNil(weakExtendedPromise1);
XCTAssertNotNil(weakExtendedPromise2);
[promise fulfill:@42];
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertNil(weakExtendedPromise1);
XCTAssertNil(weakExtendedPromise2);
}
@end
@@ -0,0 +1,119 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Always.h"
#import <XCTest/XCTest.h>
#import "FBLPromise+Async.h"
#import "FBLPromise+Catch.h"
#import "FBLPromise+Testing.h"
#import "FBLPromise+Then.h"
#import "FBLPromisesTestHelpers.h"
@interface FBLPromiseAlwaysTests : XCTestCase
@end
@implementation FBLPromiseAlwaysTests
- (void)testPromiseAlwaysOnFulfilled {
// Arrange.
NSUInteger __block count = 0;
NSUInteger const expectedCount = 3;
// Act.
FBLPromise<NSNumber *> *promise =
[[[[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@42);
});
}] always:^{
++count;
}] then:^id(NSNumber *value) {
XCTAssertEqualObjects(value, @42);
++count;
return value;
}] always:^{
++count;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqual(count, expectedCount);
XCTAssertEqualObjects(promise.value, @42);
XCTAssertNil(promise.error);
}
- (void)testPromiseAlwaysOnRejected {
// Arrange.
NSUInteger __block count = 0;
NSUInteger const expectedCount = 3;
// Act.
FBLPromise<NSNumber *> *promise =
[[[[FBLPromise async:^(FBLPromiseFulfillBlock __unused _, FBLPromiseRejectBlock reject) {
FBLDelay(0.1, ^{
reject([NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil]);
});
}] always:^{
++count;
}] catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
++count;
}] always:^{
++count;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqual(count, expectedCount);
XCTAssertEqual(promise.error.code, 42);
XCTAssertNil(promise.value);
}
/**
Promise created with `always` should not deallocate until it gets resolved.
*/
- (void)testPromiseAlwaysNoDeallocUntilResolved {
// Arrange.
FBLPromise *promise = [FBLPromise pendingPromise];
FBLPromise __weak *weakExtendedPromise1;
FBLPromise __weak *weakExtendedPromise2;
// Act.
@autoreleasepool {
XCTAssertNil(weakExtendedPromise1);
XCTAssertNil(weakExtendedPromise2);
FBLPromise *extendedPromise1 = [promise always:^{}];
FBLPromise *extendedPromise2 = [promise always:^{}];
weakExtendedPromise1 = extendedPromise1;
weakExtendedPromise2 = extendedPromise2;
XCTAssertNotNil(weakExtendedPromise1);
XCTAssertNotNil(weakExtendedPromise2);
}
// Assert.
XCTAssertNotNil(weakExtendedPromise1);
XCTAssertNotNil(weakExtendedPromise2);
[promise fulfill:@42];
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertNil(weakExtendedPromise1);
XCTAssertNil(weakExtendedPromise2);
}
@end
@@ -0,0 +1,229 @@
/**
Copyright 2018 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "FBLPromise+Any.h"
#import <XCTest/XCTest.h>
#import "FBLPromise+Async.h"
#import "FBLPromise+Catch.h"
#import "FBLPromise+Testing.h"
#import "FBLPromise+Then.h"
#import "FBLPromisesTestHelpers.h"
@interface FBLPromiseAnyTests : XCTestCase
@end
@implementation FBLPromiseAnyTests
- (void)testPromiseAny {
// Arrange.
FBLPromise<NSNumber *> *promise1 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@42);
});
}];
FBLPromise<NSString *> *promise2 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(1, ^{
fulfill(@"hello world");
});
}];
FBLPromise<NSArray<NSNumber *> *> *promise3 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(2, ^{
fulfill(@[ @42 ]);
});
}];
FBLPromise *promise4 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(3, ^{
fulfill(nil);
});
}];
// Act.
FBLPromise *fastestPromise =
[[FBLPromise any:@[ promise1, promise2, promise3, promise4 ]] then:^id(NSNumber *value) {
XCTAssertEqualObjects(value, @42);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(fastestPromise.value, @42);
XCTAssertNil(fastestPromise.error);
}
- (void)testPromiseAnyRejectFirst {
// Arrange.
FBLPromise<NSNumber *> *promise1 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(1, ^{
fulfill(@42);
});
}];
FBLPromise<NSString *> *promise2 =
[FBLPromise async:^(FBLPromiseFulfillBlock __unused _, FBLPromiseRejectBlock reject) {
FBLDelay(0.1, ^{
reject([NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil]);
});
}];
// Act.
FBLPromise *fastestPromise = [[[FBLPromise any:@[ promise1, promise2 ]] then:^id(id __unused _) {
XCTFail();
return nil;
}] catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqual(fastestPromise.error.code, 42);
XCTAssertNil(fastestPromise.value);
}
- (void)testPromiseAnyRejectLast {
// Arrange.
FBLPromise<NSNumber *> *promise1 =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@42);
});
}];
FBLPromise<NSString *> *promise2 =
[FBLPromise async:^(FBLPromiseFulfillBlock __unused _, FBLPromiseRejectBlock reject) {
FBLDelay(1, ^{
reject([NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil]);
});
}];
// Act.
FBLPromise *fastestPromise = [[FBLPromise any:@[ promise1, promise2 ]] then:^id(NSNumber *value) {
XCTAssertEqualObjects(value, @42);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(fastestPromise.value, @42);
XCTAssertNil(fastestPromise.error);
}
- (void)testPromiseAnyWithValues {
// Arrange.
FBLPromise<NSArray<NSNumber *> *> *promise =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@[ @42 ]);
});
}];
// Act.
FBLPromise *fastestPromise =
[[FBLPromise any:@[ @42, @"hello world", promise ]] then:^id(NSNumber *value) {
XCTAssertEqualObjects(value, @42);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(fastestPromise.value, @42);
XCTAssertNil(fastestPromise.error);
}
- (void)testPromiseAnyWithErrorFirst {
// Arrange.
NSError *error = [NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil];
FBLPromise<NSArray<NSNumber *> *> *promise =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@[ @42 ]);
});
}];
// Act.
FBLPromise *fastestPromise = [[[FBLPromise any:@[ promise, error, @42 ]] then:^id(id __unused _) {
XCTFail();
return nil;
}] catch:^(NSError *error) {
XCTAssertEqual(error.code, 42);
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqual(fastestPromise.error.code, 42);
XCTAssertNil(fastestPromise.value);
}
- (void)testPromiseAnyWithErrorLast {
// Arrange.
NSError *error = [NSError errorWithDomain:FBLPromiseErrorDomain code:42 userInfo:nil];
FBLPromise<NSArray<NSNumber *> *> *promise =
[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
FBLDelay(0.1, ^{
fulfill(@[ @42 ]);
});
}];
// Act.
FBLPromise *fastestPromise =
[[FBLPromise any:@[ promise, @42, error ]] then:^id(NSNumber *value) {
XCTAssertEqualObjects(value, @42);
return value;
}];
// Assert.
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertEqualObjects(fastestPromise.value, @42);
XCTAssertNil(fastestPromise.error);
}
/**
Promise created with `any` should not deallocate until it gets resolved.
*/
- (void)testPromiseAnyNoDeallocUntilResolved {
// Arrange.
FBLPromise *promise = [FBLPromise pendingPromise];
FBLPromise __weak *weakExtendedPromise1;
FBLPromise __weak *weakExtendedPromise2;
// Act.
@autoreleasepool {
XCTAssertNil(weakExtendedPromise1);
XCTAssertNil(weakExtendedPromise2);
FBLPromise *extendedPromise1 = [FBLPromise any:@[ promise ]];
FBLPromise *extendedPromise2 = [FBLPromise any:@[ promise ]];
weakExtendedPromise1 = extendedPromise1;
weakExtendedPromise2 = extendedPromise2;
XCTAssertNotNil(weakExtendedPromise1);
XCTAssertNotNil(weakExtendedPromise2);
}
// Assert.
XCTAssertNotNil(weakExtendedPromise1);
XCTAssertNotNil(weakExtendedPromise2);
[promise fulfill:@42];
XCTAssert(FBLWaitForPromisesWithTimeout(10));
XCTAssertNil(weakExtendedPromise1);
XCTAssertNil(weakExtendedPromise2);
}
@end
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff. Show more