Delete promises
The eng review decision was a no-go.
TBR=gab@chromium.org
Bug: 906125
Change-Id: I23a7a88129451ca691b9ed43050ed7f624a2a14f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1916479
Reviewed-by: Alex Clarke <alexclarke@chromium.org>
Reviewed-by: François Doray <fdoray@chromium.org>
Reviewed-by: Gabriel Charette <gab@chromium.org>
Commit-Queue: Alex Clarke <alexclarke@chromium.org>
Auto-Submit: Alex Clarke <alexclarke@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#718108}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 112c5128dc6bc95cd7bfadbe5ebba15a226ece4b
diff --git a/BUILD.gn b/BUILD.gn
index 0f8d303..9f583f3 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -584,27 +584,6 @@
"task/post_job.h",
"task/post_task.cc",
"task/post_task.h",
- "task/promise/abstract_promise.cc",
- "task/promise/abstract_promise.h",
- "task/promise/all_container_executor.h",
- "task/promise/all_tuple_executor.h",
- "task/promise/dependent_list.cc",
- "task/promise/dependent_list.h",
- "task/promise/finally_executor.cc",
- "task/promise/finally_executor.h",
- "task/promise/helpers.cc",
- "task/promise/helpers.h",
- "task/promise/no_op_promise_executor.cc",
- "task/promise/post_task_executor.h",
- "task/promise/promise.h",
- "task/promise/promise.h",
- "task/promise/promise_executor.cc",
- "task/promise/promise_executor.h",
- "task/promise/promise_result.h",
- "task/promise/promise_value.cc",
- "task/promise/promise_value.h",
- "task/promise/then_and_catch_executor.cc",
- "task/promise/then_and_catch_executor.h",
"task/scoped_set_task_priority_for_current_thread.cc",
"task/scoped_set_task_priority_for_current_thread.h",
"task/sequence_manager/associated_thread_id.cc",
@@ -2678,12 +2657,6 @@
"task/lazy_task_runner_unittest.cc",
"task/post_job_unittest.cc",
"task/post_task_unittest.cc",
- "task/promise/abstract_promise_unittest.cc",
- "task/promise/dependent_list_unittest.cc",
- "task/promise/helpers_unittest.cc",
- "task/promise/post_task_executor_unittest.cc",
- "task/promise/promise_unittest.cc",
- "task/promise/promise_value_unittest.cc",
"task/scoped_set_task_priority_for_current_thread_unittest.cc",
"task/sequence_manager/atomic_flag_set_unittest.cc",
"task/sequence_manager/lazily_deallocated_deque_unittest.cc",
@@ -3160,7 +3133,6 @@
"observer_list_unittest.nc",
"optional_unittest.nc",
"strings/string16_unittest.nc",
- "task/promise/promise_unittest.nc",
"task/task_traits_extension_unittest.nc",
"task/task_traits_unittest.nc",
"thread_annotations_unittest.nc",
diff --git a/task/promise/abstract_promise.cc b/task/promise/abstract_promise.cc
deleted file mode 100644
index 315cfd3..0000000
--- a/task/promise/abstract_promise.cc
+++ /dev/null
@@ -1,740 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/abstract_promise.h"
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/sequenced_task_runner.h"
-#include "base/task/promise/dependent_list.h"
-#include "base/task/promise/post_task_executor.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-
-namespace base {
-namespace internal {
-
-#if DCHECK_IS_ON()
-namespace {
-
-// static
-RepeatingClosure& GetPromiseApiErrorCallback() {
- static NoDestructor<RepeatingClosure> on_api_error_callback;
- return *on_api_error_callback;
-}
-
-} // namespace
-
-// static
-void AbstractPromise::SetApiErrorObserverForTesting(
- RepeatingClosure on_api_error_callback) {
- CheckedAutoLock lock(GetCheckedLock());
- GetPromiseApiErrorCallback() = std::move(on_api_error_callback);
-}
-
-// Like DCHECK except observable via
-// AbstractPromise::SetApiErrorObserverForTesting. Exists to avoid DEATH_TESTs
-// which are flaky with promises.
-#define PROMISE_API_DCHECK(condition) \
- if (!(condition) && GetPromiseApiErrorCallback()) { \
- GetPromiseApiErrorCallback().Run(); \
- return; \
- } \
- DCHECK(condition)
-
-#endif // DCHECK_IS_ON()
-
-AbstractPromise::~AbstractPromise() {
-#if DCHECK_IS_ON()
- {
- CheckedAutoLock lock(GetCheckedLock());
-
- PROMISE_API_DCHECK(!must_catch_ancestor_that_could_reject_ ||
- passed_catch_responsibility_)
- << "Promise chain ending at " << from_here_.ToString()
- << " didn't have a catch for potentially rejecting promise here "
- << must_catch_ancestor_that_could_reject_->from_here().ToString();
-
- PROMISE_API_DCHECK(!this_must_catch_ || passed_catch_responsibility_)
- << "Potentially rejecting promise at " << from_here_.ToString()
- << " doesn't have a catch.";
- }
-#endif
-
- // If we're not settled we might be retaining some promises which need to be
- // released to prevent memory leaks. If we are settled this does nothing.
- OnCanceled();
-}
-
-void AbstractPromise::EmplaceResolvedVoid() {
- emplace(Resolved<void>());
-}
-
-bool AbstractPromise::IsCanceled() const {
- if (dependents_.IsCanceled())
- return true;
-
- const PromiseExecutor* executor = GetExecutor();
- return executor && executor->IsCancelled();
-}
-
-void AbstractPromise::AddAsDependentForAllPrerequisites() {
- if (!prerequisites_)
- return;
-
- // Note a curried promise will eventually get to all its children and pass
- // them catch responsibility through AddAsDependentForAllPrerequisites,
- // although that'll be done lazily (only once they resolve/reject, so there
- // is a possibility the DCHECKs might be racy.
-
- for (DependentList::Node& node : *prerequisites_->prerequisite_list()) {
- node.dependent() = this;
-
- // If |node.prerequisite()| was canceled then early out because
- // |prerequisites_->prerequisite_list| will have been cleared.
- DCHECK(node.prerequisite());
- if (!node.prerequisite()->InsertDependentOnAnyThread(&node))
- break;
- }
-}
-
-bool AbstractPromise::InsertDependentOnAnyThread(DependentList::Node* node) {
- scoped_refptr<AbstractPromise>& dependent = node->dependent();
-
- // Used to ensure no reference to the dependent is kept in case the Promise is
- // already settled.
- scoped_refptr<AbstractPromise> dependent_to_release;
-
-#if DCHECK_IS_ON()
- {
- CheckedAutoLock lock(GetCheckedLock());
- DCHECK(node->dependent()) << from_here_.ToString();
- node->dependent()->MaybeInheritChecks(this);
- }
-#endif
-
- // If |dependents_| has been consumed (i.e. this promise has been resolved
- // or rejected) then |node| may be ready to run now.
- switch (dependents_.Insert(node)) {
- case DependentList::InsertResult::SUCCESS:
- break;
-
- case DependentList::InsertResult::FAIL_PROMISE_RESOLVED: {
- AbstractPromise* curried_promise = GetCurriedPromise();
- if (curried_promise) {
- // Try and reinsert |node| in the curried ancestor.
- node->SetPrerequisite(curried_promise);
- return curried_promise->InsertDependentOnAnyThread(node);
- } else {
- dependent_to_release = std::move(dependent);
- node->RetainSettledPrerequisite();
- dependent_to_release->OnPrerequisiteResolved(this);
- }
- break;
- }
-
- case DependentList::InsertResult::FAIL_PROMISE_REJECTED: {
- AbstractPromise* curried_promise = GetCurriedPromise();
- if (curried_promise) {
- // Try and reinsert |node| in the curried ancestor.
- node->SetPrerequisite(curried_promise);
- return curried_promise->InsertDependentOnAnyThread(node);
- } else {
- dependent_to_release = std::move(dependent);
- node->RetainSettledPrerequisite();
- dependent_to_release->OnPrerequisiteRejected(this);
- }
- break;
- }
-
- case DependentList::InsertResult::FAIL_PROMISE_CANCELED:
- dependent_to_release = std::move(dependent);
- return dependent_to_release->OnPrerequisiteCancelled(this);
- }
-
- return true;
-}
-
-void AbstractPromise::IgnoreUncaughtCatchForTesting() {
-#if DCHECK_IS_ON()
- CheckedAutoLock lock(GetCheckedLock());
- passed_catch_responsibility_ = true;
-#endif
-}
-
-#if DCHECK_IS_ON()
-
-// static
-CheckedLock& AbstractPromise::GetCheckedLock() {
- static base::NoDestructor<CheckedLock> instance;
- return *instance;
-}
-
-void AbstractPromise::DoubleMoveDetector::CheckForDoubleMoveErrors(
- const base::Location& new_dependent_location,
- PromiseExecutor::ArgumentPassingType new_dependent_executor_type) {
- switch (new_dependent_executor_type) {
- case PromiseExecutor::ArgumentPassingType::kNoCallback:
- return;
-
- case PromiseExecutor::ArgumentPassingType::kNormal:
- PROMISE_API_DCHECK(!dependent_move_only_promise_)
- << "Can't mix move only and non-move only " << callback_type_
- << "callback arguments for the same " << callback_type_
- << " prerequisite. See " << new_dependent_location.ToString()
- << " and " << dependent_move_only_promise_->ToString()
- << " with common ancestor " << from_here_.ToString();
- dependent_normal_promise_ =
- std::make_unique<Location>(new_dependent_location);
- return;
-
- case PromiseExecutor::ArgumentPassingType::kMove:
- PROMISE_API_DCHECK(!dependent_move_only_promise_ ||
- *dependent_move_only_promise_ ==
- new_dependent_location)
- << "Can't have multiple move only " << callback_type_
- << " callbacks for same " << callback_type_ << " prerequisite. See "
- << new_dependent_location.ToString() << " and "
- << dependent_move_only_promise_->ToString() << " with common "
- << callback_type_ << " prerequisite " << from_here_.ToString();
- PROMISE_API_DCHECK(!dependent_normal_promise_)
- << "Can't mix move only and non-move only " << callback_type_
- << " callback arguments for the same " << callback_type_
- << " prerequisite. See " << new_dependent_location.ToString()
- << " and " << dependent_normal_promise_->ToString() << " with common "
- << callback_type_ << " prerequisite " << from_here_.ToString();
- dependent_move_only_promise_ =
- std::make_unique<Location>(new_dependent_location);
- return;
- }
-}
-
-void AbstractPromise::MaybeInheritChecks(AbstractPromise* prerequisite) {
- if (!ancestor_that_could_resolve_) {
- // Inherit |prerequisite|'s resolve ancestor if it doesn't have a resolve
- // callback.
- if (prerequisite->resolve_argument_passing_type_ ==
- PromiseExecutor::ArgumentPassingType::kNoCallback) {
- ancestor_that_could_resolve_ = prerequisite->ancestor_that_could_resolve_;
- }
-
- // If |prerequisite| didn't have a resolve callback (but it's reject
- // callback could resolve) or if
- // |prerequisite->ancestor_that_could_resolve_| is null then assign
- // |prerequisite->this_resolve_|.
- if (!ancestor_that_could_resolve_ && prerequisite->executor_can_resolve_)
- ancestor_that_could_resolve_ = prerequisite->this_resolve_;
- }
-
- if (!ancestor_that_could_reject_) {
- // Inherit |prerequisite|'s reject ancestor if it doesn't have a Catch.
- if (prerequisite->reject_argument_passing_type_ ==
- PromiseExecutor::ArgumentPassingType::kNoCallback) {
- ancestor_that_could_reject_ = prerequisite->ancestor_that_could_reject_;
- }
-
- // If |prerequisite| didn't have a reject callback (but it's resolve
- // callback could reject) or if
- // |prerequisite->ancestor_that_could_resolve_| is null then assign
- // |prerequisite->this_reject_|.
- if (!ancestor_that_could_reject_ && prerequisite->executor_can_reject_)
- ancestor_that_could_reject_ = prerequisite->this_reject_;
- }
-
- if (!must_catch_ancestor_that_could_reject_) {
- // Inherit |prerequisite|'s must catch ancestor if it doesn't have a Catch.
- if (prerequisite->reject_argument_passing_type_ ==
- PromiseExecutor::ArgumentPassingType::kNoCallback) {
- must_catch_ancestor_that_could_reject_ =
- prerequisite->must_catch_ancestor_that_could_reject_;
- }
-
- // If |prerequisite| didn't have a reject callback (but it's resolve
- // callback could reject) or if
- // |prerequisite->must_catch_ancestor_that_could_reject_| is null then
- // assign |prerequisite->this_must_catch_|.
- if (!must_catch_ancestor_that_could_reject_ &&
- prerequisite->executor_can_reject_) {
- must_catch_ancestor_that_could_reject_ = prerequisite->this_must_catch_;
- }
- }
-
- if (ancestor_that_could_resolve_) {
- ancestor_that_could_resolve_->CheckForDoubleMoveErrors(
- from_here_, resolve_argument_passing_type_);
- }
-
- if (ancestor_that_could_reject_) {
- ancestor_that_could_reject_->CheckForDoubleMoveErrors(
- from_here_, reject_argument_passing_type_);
- }
-
- prerequisite->passed_catch_responsibility_ = true;
-}
-
-AbstractPromise::LocationRef::LocationRef(const Location& from_here)
- : from_here_(from_here) {}
-
-AbstractPromise::LocationRef::~LocationRef() = default;
-
-AbstractPromise::DoubleMoveDetector::DoubleMoveDetector(
- const Location& from_here,
- const char* callback_type)
- : from_here_(from_here), callback_type_(callback_type) {}
-
-AbstractPromise::DoubleMoveDetector::~DoubleMoveDetector() = default;
-
-#endif
-
-AbstractPromise* AbstractPromise::GetCurriedPromise() {
- if (!value_.ContainsCurriedPromise())
- return nullptr;
- return value_.Get<scoped_refptr<AbstractPromise>>()->get();
-}
-
-const PromiseExecutor* AbstractPromise::GetExecutor() const {
- if (!value_.ContainsPromiseExecutor())
- return nullptr;
- return value_.Get<PromiseExecutor>();
-}
-
-PromiseExecutor::PrerequisitePolicy AbstractPromise::GetPrerequisitePolicy() {
- PromiseExecutor* executor = GetExecutor();
- if (!executor) {
- // If there's no executor it's because the promise has already run. We
- // can't run again however. The only circumstance in which we expect
- // GetPrerequisitePolicy() to be called after execution is when it was
- // resolved with a promise or we're already settled.
- DCHECK(IsSettled());
- return PromiseExecutor::PrerequisitePolicy::kNever;
- }
- return executor->GetPrerequisitePolicy();
-}
-
-AbstractPromise* AbstractPromise::GetFirstSettledPrerequisite() const {
- DCHECK(prerequisites_);
- return prerequisites_->GetFirstSettledPrerequisite();
-}
-
-void AbstractPromise::Execute() {
- const PromiseExecutor* executor = GetExecutor();
- DCHECK(executor || dependents_.IsCanceled()) << from_here_.ToString();
-
- if (!executor || executor->IsCancelled()) {
- OnCanceled();
- return;
- }
-
-#if DCHECK_IS_ON()
- // Clear |must_catch_ancestor_that_could_reject_| if we can catch it.
- if (reject_argument_passing_type_ !=
- PromiseExecutor::ArgumentPassingType::kNoCallback) {
- CheckedAutoLock lock(GetCheckedLock());
- must_catch_ancestor_that_could_reject_ = nullptr;
- }
-#endif
-
- DCHECK(!IsResolvedWithPromise());
-
- // To reduce template bloat the Executor machinery deals with AbstractPromise
- // raw pointers. This is fine as long as we ensure the reference count doesn't
- // go to zero when we run the promise callback (which could do anything
- // including releasing what might otherwise be the last reference to the
- // AbstractPromise).
- scoped_refptr<AbstractPromise> protect(this);
-
- // This is likely to delete the executor.
- GetExecutor()->Execute(this);
-
- if (value_.ContainsRejected()) {
- OnRejected();
- } else if (value_.ContainsResolved() || value_.ContainsCurriedPromise()) {
- OnResolved();
- }
-}
-
-void AbstractPromise::ReplaceCurriedPrerequisite(
- AbstractPromise* curried_prerequisite,
- AbstractPromise* replacement) {
- DCHECK(curried_prerequisite->IsResolved() ||
- curried_prerequisite->IsRejected());
- DCHECK(curried_prerequisite->IsResolvedWithPromise());
- DCHECK(replacement);
- for (DependentList::Node& node : *prerequisites_->prerequisite_list()) {
- if (node.prerequisite() == curried_prerequisite) {
- node.Reset(replacement, this);
- replacement->InsertDependentOnAnyThread(&node);
- return;
- }
- }
- NOTREACHED();
-}
-
-void AbstractPromise::OnPrerequisiteResolved(
- AbstractPromise* resolved_prerequisite) {
- DCHECK(resolved_prerequisite->IsResolved());
-
- switch (GetPrerequisitePolicy()) {
- case PromiseExecutor::PrerequisitePolicy::kAll:
- if (prerequisites_->DecrementPrerequisiteCountAndCheckIfZero())
- DispatchPromise();
- break;
-
- case PromiseExecutor::PrerequisitePolicy::kAny:
- // PrerequisitePolicy::kAny should resolve immediately.
- if (prerequisites_->MarkPrerequisiteAsSettling(resolved_prerequisite))
- DispatchPromise();
- break;
-
- case PromiseExecutor::PrerequisitePolicy::kNever:
- break;
- }
-}
-
-void AbstractPromise::OnPrerequisiteRejected(
- AbstractPromise* rejected_prerequisite) {
- DCHECK(rejected_prerequisite->IsRejected());
-
- // Promises::All (or Race if we add that) can have multiple prerequisites and
- // it will reject as soon as any prerequisite rejects. Multiple prerequisites
- // can reject, but we wish to record only the first one. Also we can only
- // invoke executors once.
- if (prerequisites_->MarkPrerequisiteAsSettling(rejected_prerequisite)) {
- DispatchPromise();
- }
-}
-
-bool AbstractPromise::OnPrerequisiteCancelled(
- AbstractPromise* canceled_prerequisite) {
- switch (GetPrerequisitePolicy()) {
- case PromiseExecutor::PrerequisitePolicy::kAll:
- // PrerequisitePolicy::kAll should cancel immediately.
- OnCanceled();
- return false;
-
- case PromiseExecutor::PrerequisitePolicy::kAny:
- // PrerequisitePolicy::kAny should only cancel if all if it's
- // pre-requisites have been canceled.
- if (prerequisites_->DecrementPrerequisiteCountAndCheckIfZero()) {
- OnCanceled();
- return false;
- } else {
- prerequisites_->RemoveCanceledPrerequisite(canceled_prerequisite);
- }
- return true;
-
- case PromiseExecutor::PrerequisitePolicy::kNever:
- // If we where resolved with a promise then we can't have had
- // PrerequisitePolicy::kAny or PrerequisitePolicy::kNever before the
- // executor was replaced with the curried promise, so pass on
- // cancellation.
- if (IsResolvedWithPromise())
- OnCanceled();
- return false;
- }
-}
-
-void AbstractPromise::OnResolveDispatchReadyDependents() {
- class Visitor : public DependentList::Visitor {
- public:
- explicit Visitor(AbstractPromise* resolved_prerequisite)
- : resolved_prerequisite_(resolved_prerequisite) {}
-
- private:
- void Visit(scoped_refptr<AbstractPromise> dependent) override {
- dependent->OnPrerequisiteResolved(resolved_prerequisite_);
- }
- AbstractPromise* const resolved_prerequisite_;
- };
-
- Visitor visitor(this);
- dependents_.ResolveAndConsumeAllDependents(&visitor);
-}
-
-void AbstractPromise::OnRejectDispatchReadyDependents() {
- class Visitor : public DependentList::Visitor {
- public:
- explicit Visitor(AbstractPromise* rejected_prerequisite)
- : rejected_prerequisite_(rejected_prerequisite) {}
-
- private:
- void Visit(scoped_refptr<AbstractPromise> dependent) override {
- dependent->OnPrerequisiteRejected(rejected_prerequisite_);
- }
- AbstractPromise* const rejected_prerequisite_;
- };
-
- Visitor visitor(this);
- dependents_.RejectAndConsumeAllDependents(&visitor);
-}
-
-void AbstractPromise::OnResolveMakeDependantsUseCurriedPrerequisite(
- AbstractPromise* non_curried_root) {
- class Visitor : public DependentList::Visitor {
- public:
- explicit Visitor(AbstractPromise* resolved_prerequisite,
- AbstractPromise* non_curried_root)
- : resolved_prerequisite_(resolved_prerequisite),
- non_curried_root_(non_curried_root) {}
-
- private:
- void Visit(scoped_refptr<AbstractPromise> dependent) override {
- dependent->ReplaceCurriedPrerequisite(resolved_prerequisite_,
- non_curried_root_);
- }
- AbstractPromise* const resolved_prerequisite_;
- AbstractPromise* const non_curried_root_;
- };
-
- Visitor visitor(this, non_curried_root);
- dependents_.ResolveAndConsumeAllDependents(&visitor);
-}
-
-void AbstractPromise::OnRejectMakeDependantsUseCurriedPrerequisite(
- AbstractPromise* non_curried_root) {
- class Visitor : public DependentList::Visitor {
- public:
- explicit Visitor(AbstractPromise* rejected_prerequisite,
- AbstractPromise* non_curried_root)
- : rejected_prerequisite_(rejected_prerequisite),
- non_curried_root_(non_curried_root) {}
-
- private:
- void Visit(scoped_refptr<AbstractPromise> dependent) override {
- dependent->ReplaceCurriedPrerequisite(rejected_prerequisite_,
- non_curried_root_);
- }
- AbstractPromise* const rejected_prerequisite_;
- AbstractPromise* const non_curried_root_;
- };
-
- Visitor visitor(this, non_curried_root);
- dependents_.RejectAndConsumeAllDependents(&visitor);
-}
-
-void AbstractPromise::DispatchPromise() {
- if (task_runner_) {
- task_runner_->PostPromiseInternal(WrappedPromise(this), TimeDelta());
- } else {
- Execute();
- }
-}
-
-void AbstractPromise::OnCanceled() {
- class Visitor : public DependentList::Visitor {
- public:
- explicit Visitor(AbstractPromise* canceled_prerequisite)
- : canceled_prerequisite_(canceled_prerequisite) {}
-
- private:
- void Visit(scoped_refptr<AbstractPromise> dependent) override {
- dependent->OnPrerequisiteCancelled(canceled_prerequisite_);
- }
-
- AbstractPromise* const canceled_prerequisite_;
- };
-
- Visitor visitor(this);
- if (!dependents_.CancelAndConsumeAllDependents(&visitor))
- return;
-
- // The executor could be keeping a promise alive, but it's never going to run
- // so clear it.
- value_.reset();
-
-#if DCHECK_IS_ON()
- {
- CheckedAutoLock lock(GetCheckedLock());
- passed_catch_responsibility_ = true;
- }
-#endif
-
- if (prerequisites_)
- prerequisites_->Clear();
-}
-
-AbstractPromise* AbstractPromise::FindCurriedAncestor() {
- AbstractPromise* promise = this;
- while (promise->IsSettled()) {
- if (promise->IsCanceled())
- return nullptr;
-
- if (!promise->value_.ContainsCurriedPromise())
- break;
-
- promise = promise->value_.Get<scoped_refptr<AbstractPromise>>()->get();
- }
- return promise;
-}
-
-void AbstractPromise::OnResolved() {
-#if DCHECK_IS_ON()
- PROMISE_API_DCHECK(executor_can_resolve_ || IsResolvedWithPromise())
- << from_here_.ToString();
-#endif
- if (AbstractPromise* curried_promise = GetCurriedPromise()) {
-#if DCHECK_IS_ON()
- {
- CheckedAutoLock lock(GetCheckedLock());
- MaybeInheritChecks(curried_promise);
- }
-#endif
-
- curried_promise = curried_promise->FindCurriedAncestor();
- if (!curried_promise) {
- OnCanceled();
- return;
- }
-
- OnResolveMakeDependantsUseCurriedPrerequisite(curried_promise);
- } else {
- OnResolveDispatchReadyDependents();
- }
-
- if (prerequisites_)
- prerequisites_->Clear();
-}
-
-void AbstractPromise::OnRejected() {
-#if DCHECK_IS_ON()
- PROMISE_API_DCHECK(executor_can_reject_) << from_here_.ToString();
-#endif
-
- if (AbstractPromise* curried_promise = GetCurriedPromise()) {
-#if DCHECK_IS_ON()
- {
- CheckedAutoLock lock(GetCheckedLock());
- MaybeInheritChecks(curried_promise);
- }
-#endif
-
- curried_promise = curried_promise->FindCurriedAncestor();
-
- // It shouldn't be possible for OnRejected to be called with a canceled
- // curried promise because AbstractPromise::Execute regards a curried as a
- // resolved promise.
- DCHECK(curried_promise);
- OnRejectMakeDependantsUseCurriedPrerequisite(curried_promise);
- } else {
- OnRejectDispatchReadyDependents();
- }
-
- if (prerequisites_)
- prerequisites_->Clear();
-}
-
-AbstractPromise::AdjacencyList::AdjacencyList() = default;
-
-AbstractPromise::AdjacencyList::AdjacencyList(AbstractPromise* prerequisite)
- : prerequisite_list_(1), action_prerequisite_count_(1) {
- prerequisite_list_[0].SetPrerequisite(prerequisite);
-}
-
-AbstractPromise::AdjacencyList::AdjacencyList(
- std::vector<DependentList::Node> nodes)
- : prerequisite_list_(std::move(nodes)),
- action_prerequisite_count_(prerequisite_list_.size()) {}
-
-AbstractPromise::AdjacencyList::~AdjacencyList() = default;
-
-bool AbstractPromise::AdjacencyList::
- DecrementPrerequisiteCountAndCheckIfZero() {
- return action_prerequisite_count_.fetch_sub(1, std::memory_order_acq_rel) ==
- 1;
-}
-
-// For PrerequisitePolicy::kAll this is called for the first rejected
-// prerequisite. For PrerequisitePolicy:kAny this is called for the first
-// resolving or rejecting prerequisite.
-bool AbstractPromise::AdjacencyList::MarkPrerequisiteAsSettling(
- AbstractPromise* settled_prerequisite) {
- DCHECK(settled_prerequisite->IsSettled());
- uintptr_t expected = 0;
- return first_settled_prerequisite_.compare_exchange_strong(
- expected, reinterpret_cast<uintptr_t>(settled_prerequisite),
- std::memory_order_acq_rel);
-}
-
-void AbstractPromise::AdjacencyList::RemoveCanceledPrerequisite(
- AbstractPromise* canceled_prerequisite) {
- DCHECK(canceled_prerequisite->IsCanceled());
- for (DependentList::Node& node : prerequisite_list_) {
- if (node.prerequisite() == canceled_prerequisite) {
- node.ClearPrerequisite();
- return;
- }
- }
- NOTREACHED() << "Couldn't find canceled_prerequisite "
- << canceled_prerequisite->from_here().ToString();
-}
-
-void AbstractPromise::AdjacencyList::Clear() {
- // If there's only one prerequisite we can just clear |prerequisite_list_|
- // which deals with potential refcounting cycles due to curried promises.
- if (prerequisite_list_.size() == 1) {
- prerequisite_list_.clear();
- } else {
- // If there's multiple prerequisites we can't do that because the
- // DependentList::Nodes may still be in use by some of them.
- // Instead we release our prerequisite references and rely on refcounting to
- // release the owning AbstractPromise.
- for (DependentList::Node& node : prerequisite_list_) {
- node.ClearPrerequisite();
- }
- }
-}
-
-BasePromise::BasePromise() = default;
-
-BasePromise::BasePromise(
- scoped_refptr<internal::AbstractPromise> abstract_promise)
- : abstract_promise_(std::move(abstract_promise)) {}
-
-BasePromise::BasePromise(const BasePromise& other) = default;
-BasePromise::BasePromise(BasePromise&& other) = default;
-
-BasePromise& BasePromise::operator=(const BasePromise& other) = default;
-BasePromise& BasePromise::operator=(BasePromise&& other) = default;
-
-BasePromise::~BasePromise() = default;
-
-} // namespace internal
-
-WrappedPromise::WrappedPromise() = default;
-
-WrappedPromise::WrappedPromise(scoped_refptr<internal::AbstractPromise> promise)
- : promise_(std::move(promise)) {}
-
-WrappedPromise::WrappedPromise(internal::PassedPromise&& passed_promise)
- : promise_(passed_promise.Release(), subtle::kAdoptRefTag) {
- DCHECK(promise_);
-}
-
-WrappedPromise::WrappedPromise(const Location& from_here, OnceClosure task)
- : WrappedPromise(internal::AbstractPromise::CreateNoPrerequisitePromise(
- from_here,
- RejectPolicy::kMustCatchRejection,
- internal::DependentList::ConstructUnresolved(),
- internal::PromiseExecutor::Data(
- base::in_place_type_t<internal::PostTaskExecutor<void>>(),
- std::move(task)))) {}
-
-WrappedPromise::WrappedPromise(const WrappedPromise& other) = default;
-WrappedPromise::WrappedPromise(WrappedPromise&& other) = default;
-
-WrappedPromise& WrappedPromise::operator=(const WrappedPromise& other) =
- default;
-WrappedPromise& WrappedPromise::operator=(WrappedPromise&& other) = default;
-
-WrappedPromise::~WrappedPromise() = default;
-
-void WrappedPromise::Execute() {
- DCHECK(promise_);
- promise_->Execute();
-}
-
-void WrappedPromise::Clear() {
- promise_ = nullptr;
-}
-
-} // namespace base
diff --git a/task/promise/abstract_promise.h b/task/promise/abstract_promise.h
deleted file mode 100644
index c16132c..0000000
--- a/task/promise/abstract_promise.h
+++ /dev/null
@@ -1,892 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_ABSTRACT_PROMISE_H_
-#define BASE_TASK_PROMISE_ABSTRACT_PROMISE_H_
-
-#include <utility>
-
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/no_destructor.h"
-#include "base/task/common/checked_lock.h"
-#include "base/task/promise/dependent_list.h"
-#include "base/task/promise/promise_executor.h"
-#include "base/task/promise/promise_value.h"
-#include "base/thread_annotations.h"
-
-namespace base {
-class TaskRunner;
-
-template <typename ResolveType, typename RejectType>
-class ManualPromiseResolver;
-
-template <typename ResolveType, typename RejectType>
-class Promise;
-
-// AbstractPromise Memory Management.
-//
-// Consider a chain of promises: P1, P2 & P3
-//
-// Before resolve:
-// * P1 needs an external reference (such as a Promise<> handle or it has been
-// posted) to keep it alive
-// * P2 is kept alive by P1
-// * P3 is kept alive by P2
-//
-// ------------
-// Key: | P1 | P1 doesn't have an
-// ═ Denotes a reference is held | | AdjacencyList
-// ─ Denotes a raw pointer | Dependants |
-// -----|------
-// | ^
-// ╔════════════╗ | |
-// ↓ ║ ↓ |
-// ------------ ---║--------|--
-// | P2 | | dependent_ | |
-// | |==| | | P2's AdjacencyList
-// | Dependants | | prerequisite_ |
-// -----|------ ---------------
-// | ^
-// ╔════════════╗ | |
-// ↓ ║ ↓ |
-// ------------ ---║--------|--
-// | P3 | | dependent_ | |
-// | |==| | | P3's AdjacencyList
-// | Dependants | | prerequisite_ |
-// ---|-------- ---------------
-// |
-// ↓
-// null
-//
-//
-// After P1's executor runs, P2's |prerequisite_| link is upgraded by
-// OnResolveDispatchReadyDependents (which incirectly calls
-// RetainSettledPrerequisite) from a raw pointer to a reference. This is done to
-// ensure P1's |value_| is available when P2's executor runs.
-//
-// ------------
-// | P1 | P1 doesn't have an
-// | | AdjacencyList
-// | Dependants |
-// -----|------
-// | ^
-// ╔════════════╗ | ║
-// ↓ ║ ↓ ║
-// ------------ ---║--------║--
-// | P2 | | dependent_ ║ |
-// | |==| ║ | P2's AdjacencyList
-// | Dependants | | prerequisite_ |
-// -----|------ ---------------
-// | ^
-// ╔════════════╗ | |
-// ↓ ║ ↓ |
-// ------------ ---║--------|--
-// | P3 | | dependent_ | |
-// | |==| | | P3's AdjacencyList
-// | Dependants | | prerequisite_ |
-// ---|-------- ---------------
-// |
-// ↓
-// null
-//
-//
-// After P2's executor runs, it's AdjacencyList is cleared. Unless there's
-// external references, at this stage P1 will be deleted. P3's |prerequisite_|
-// is from a raw pointer to a reference to ensure P2's |value_| is available
-// when P3's executor runs.
-//
-// ------------
-// | P1 | P1 doesn't have an
-// | | AdjacencyList
-// | Dependants |
-// -----|------
-// |
-// null | null
-// ^ ↓ ^
-// ------------ ---|--------|--
-// | P2 | | dependent_ | |
-// | |==| | | P2's AdjacencyList
-// | Dependants | | prerequisite_ |
-// -----|------ ---------------
-// | ^
-// ╔════════════╗ | ║
-// ↓ ║ ↓ ║
-// ------------ ---║--------║--
-// | P3 | | dependent_ ║ |
-// | |==| ║ | P3's AdjacencyList
-// | Dependants | | prerequisite_ |
-// ---|-------- ---------------
-// |
-// ↓
-// null
-//
-// =============================================================================
-// Consider a promise P1 that is resolved with an unresolved promise P2, and P3
-// which depends on P1.
-//
-// 1) Initially P1 doesn't have an AdjacencyList and must be kept alive by an
-// external reference. P1 keeps P3 alive.
-//
-// 2) P1's executor resolves with P2 and P3 is modified to have P2 as a
-// dependent instead of P1. P1 has a reference to P2, but it needs an
-// external reference to keep alive.
-//
-// 3) When P2's executor runs, P3's executor is scheduled and P3's
-// |prerequisite_| link to P2 is upgraded to a reference. So P3 keeps P2
-// alive.
-//
-// 4) When P3's executor runs, its AdjacencyList is cleared. At this stage
-// unless there are external referecnes P2 and P3 will be deleted.
-//
-//
-// 1. --------------
-// | P1 value_ |
-// | | P1 doesn't have an AdjacencyList
-// | Dependants |
-// ---|----------
-// | ^
-// ↓ ║
-// ------------ ------------║---
-// | P3 | | dependent_ ║ |
-// | |==| ║ | P3's AdjacencyList
-// | Dependants | | prerequisite_ |
-// ---|-------- ---------------
-// |
-// ↓
-// null
-//
-// 2. ------------
-// | P2 |
-// ╔══════>| | P2 doesn't have an
-// ║ | Dependants | AdjacencyList
-// ║ -----|------
-// ║ | ^
-// ------║------- | |
-// | P1 value_ | | |
-// | | | |
-// | Dependants | | |
-// -------------- | |
-// ╔═════════╗ ┌────────────┘ |
-// ↓ ║ ↓ ┌──────────┘
-// ------------ ---║--------|---
-// | P3 | | dependent_ | |
-// | |==| | | P3's AdjacencyList
-// | Dependants | | prerequisite_ |
-// ---|-------- ---------------
-// |
-// ↓
-// null
-// 3. ------------
-// | P2 |
-// | | P2 doesn't have an
-// | Dependants | AdjacencyList
-// -----|------
-// | ^
-// | ║
-// | ║
-// | ║
-// | ║
-// | ║
-// ╔═════════╗ ┌────────────┘ ║
-// ↓ ║ ↓ ╔══════════╝
-// ------------ ---║--------║---
-// | P3 | | dependent_ ║ |
-// | |==| ║ | P3's AdjacencyList
-// | Dependants | | prerequisite_ |
-// ---|-------- ---------------
-// |
-// ↓
-// null
-//
-//
-// 4. ------------
-// | P2 |
-// | | P2 doesn't have an
-// | Dependants | AdjacencyList
-// ------------
-//
-//
-//
-//
-//
-//
-//
-//
-// ------------
-// | P3 | P3 doesn't have an AdjacencyList anymore.
-// | |
-// | Dependants |
-// ---|--------
-// |
-// ↓
-// null
-//
-// =============================================================================
-// Consider an all promise Pall with dependents P1, P2 & P3:
-//
-// Before resolve P1, P2 & P3 keep Pall alive. If say P2 rejects then Pall
-// keeps P2 alive, however all the dependents in Pall's AdjacencyList are
-// cleared. When there are no external references to P1, P2 & P3 then Pall
-// will get deleted too if it has no external references.
-//
-// Pall's AdjacencyList
-// ------------ ----------------
-// | P1 | | |
-// | | <─────────── prerequisite_ |
-// | Dependants────────────>| dependent_══════════════════╗
-// ------------ | | ↓
-// |----------------| ---------
-// ------------ | | | |
-// | P2 | <─────────── prerequisite_ | | Pall |
-// | | | dependent_════════════>| |
-// | Dependants────────────>| | | |
-// ------------ | | ---------
-// |----------------| ^
-// ------------ | | ║
-// | P3 | <─────────── prerequisite_ | ║
-// | | | dependent_══════════════════╝
-// | Dependants────────────>| |
-// ------------ ----------------
-//
-//
-// In general a promise's AdjacencyList's only retains prerequisites after the
-// promise has resolved. It is necessary to retain the prerequisites because a
-// ThenOn or CatchOn can be added after the promise has resolved.
-
-// A promise for either |ResolveType| if successful or |RejectType| on error.
-template <typename ResolveType, typename RejectType>
-class Promise;
-
-// This enum is used to configure AbstractPromise's uncaught reject detection.
-// Usually not catching a reject reason is a coding error, but at times that can
-// become onerous. When that happens kCatchNotRequired should be used.
-enum class RejectPolicy {
- kMustCatchRejection,
- kCatchNotRequired,
-};
-
-class WrappedPromise;
-
-namespace internal {
-
-template <typename T, typename... Args>
-class PromiseCallbackHelper;
-
-class AbstractPromise;
-class AbstractPromiseTest;
-class BasePromise;
-
-// A binary size optimization to reduce the overhead of passing a scoped_refptr
-// to Promise<> returned by PostTask. There are many thousands of PostTasks so
-// even a single extra instruction (such as the scoped_refptr move constructor
-// clearing the pointer) adds up. This is why we're not constructing a Promise<>
-// with a scoped_refptr.
-//
-// The constructor calls AddRef, it's up to the owner of this object to either
-// call Clear (which calls Release) or AbstractPromise in order to pass
-// ownership onto a WrappedPromise.
-class BASE_EXPORT PassedPromise {
- public:
- explicit inline PassedPromise(const scoped_refptr<AbstractPromise>& promise);
-
- PassedPromise() : promise_(nullptr) {}
-
- PassedPromise(const PassedPromise&) = delete;
- PassedPromise& operator=(const PassedPromise&) = delete;
-
-#if DCHECK_IS_ON()
- PassedPromise(PassedPromise&& other) noexcept : promise_(other.promise_) {
- DCHECK(promise_);
- other.promise_ = nullptr;
- }
-
- PassedPromise& operator=(PassedPromise&& other) noexcept {
- DCHECK(!promise_);
- promise_ = other.promise_;
- DCHECK(promise_);
- other.promise_ = nullptr;
- return *this;
- }
-
- ~PassedPromise() {
- DCHECK(!promise_) << "The PassedPromise must be Cleared or passed onto a "
- "Wrapped Promise";
- }
-#else
- PassedPromise(PassedPromise&&) noexcept = default;
- PassedPromise& operator=(PassedPromise&&) noexcept = default;
-#endif
-
- AbstractPromise* Release() {
- AbstractPromise* promise = promise_;
-#if DCHECK_IS_ON()
- promise_ = nullptr;
-#endif
- return promise;
- }
-
- AbstractPromise* get() const { return promise_; }
-
- private:
- AbstractPromise* promise_;
-};
-
-// Internal promise representation, maintains a graph of dependencies and posts
-// promises as they become ready. In debug builds various sanity checks are
-// performed to catch common errors such as double move or forgetting to catch a
-// potential reject (NB this last check can be turned off with
-// RejectPolicy::kCatchNotRequired).
-class BASE_EXPORT AbstractPromise
- : public RefCountedThreadSafe<AbstractPromise> {
- public:
- class AdjacencyList;
-
- template <typename ConstructType>
- static scoped_refptr<AbstractPromise> Create(
- const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- std::unique_ptr<AdjacencyList> prerequisites,
- RejectPolicy reject_policy,
- ConstructType tag,
- PromiseExecutor::Data&& executor_data) noexcept {
- scoped_refptr<AbstractPromise> promise = subtle::AdoptRefIfNeeded(
- new AbstractPromise(task_runner, from_here, std::move(prerequisites),
- reject_policy, tag, std::move(executor_data)),
- AbstractPromise::kRefCountPreference);
- // It's important this is called after |promise| has been initialized
- // because otherwise it could trigger a scoped_refptr destructor on another
- // thread before this thread has had a chance to increment the refcount.
- promise->AddAsDependentForAllPrerequisites();
- return promise;
- }
-
- template <typename ConstructType>
- static scoped_refptr<AbstractPromise> CreateNoPrerequisitePromise(
- const Location& from_here,
- RejectPolicy reject_policy,
- ConstructType tag,
- PromiseExecutor::Data&& executor_data) noexcept {
- return subtle::AdoptRefIfNeeded(
- new internal::AbstractPromise(nullptr, from_here, nullptr,
- reject_policy, tag,
- std::move(executor_data)),
- AbstractPromise::kRefCountPreference);
- }
-
- AbstractPromise(const AbstractPromise&) = delete;
- AbstractPromise& operator=(const AbstractPromise&) = delete;
-
- const Location& from_here() const { return from_here_; }
-
- bool IsSettled() const { return dependents_.IsSettled(); }
- bool IsCanceled() const;
-
- // It's an error (result will be racy) to call these if unsettled.
- bool IsRejected() const { return dependents_.IsRejected(); }
- bool IsResolved() const { return dependents_.IsResolved(); }
-
- bool IsRejectedForTesting() const {
- return dependents_.IsRejectedForTesting();
- }
-
- bool IsResolvedForTesting() const {
- return dependents_.IsResolvedForTesting();
- }
-
- bool IsResolvedWithPromise() const { return value_.ContainsCurriedPromise(); }
-
- const PromiseValue& value() const {
- DCHECK(!IsResolvedWithPromise());
- return value_;
- }
-
- class ValueHandle {
- public:
- PromiseValue& value() { return value_; }
-
-#if DCHECK_IS_ON()
- ~ValueHandle() { value_.reset(); }
-#endif
-
- private:
- friend class AbstractPromise;
-
- explicit ValueHandle(PromiseValue& value) : value_(value) {}
-
- PromiseValue& value_;
- };
-
- // Used for promise results that require move semantics. E.g. a promise chain
- // involving a std::unique_ptr<>.
- ValueHandle TakeValue() { return ValueHandle(value_); }
-
- // Returns nullptr if there isn't a curried promise.
- const AbstractPromise* GetCurriedPromise() const;
-
- // Sets the |value_| to |t|. The caller should call OnResolved() or
- // OnRejected() afterwards.
- template <typename T>
- void emplace(T&& t) {
- DCHECK(GetExecutor() != nullptr) << "Only valid to emplace once";
- value_ = std::forward<T>(t);
- static_assert(!std::is_same<std::decay_t<T>, AbstractPromise*>::value,
- "Use scoped_refptr<AbstractPromise> instead");
- }
-
- template <typename T, typename... Args>
- void emplace(in_place_type_t<T> tag, Args&&... args) {
- DCHECK(GetExecutor() != nullptr) << "Only valid to emplace once";
- value_.emplace(tag, std::forward<Args>(args)...);
- static_assert(!std::is_same<std::decay_t<T>, AbstractPromise*>::value,
- "Use scoped_refptr<AbstractPromise> instead");
- }
-
- // An out-of line emplace(Resolved<void>()); Useful for reducing binary
- // bloat in executor templates.
- void EmplaceResolvedVoid();
-
- // This is separate from AbstractPromise to reduce the memory footprint of
- // regular PostTask without promise chains.
- class BASE_EXPORT AdjacencyList {
- public:
- AdjacencyList();
- ~AdjacencyList();
-
- explicit AdjacencyList(AbstractPromise* prerequisite);
- explicit AdjacencyList(std::vector<DependentList::Node> prerequisite_list);
-
- bool DecrementPrerequisiteCountAndCheckIfZero();
-
- // Called for each prerequisites that resolves or rejects for
- // PrerequisitePolicy::kAny and each prerequisite that rejects for
- // PrerequisitePolicy::kAll. This saves |settled_prerequisite| and returns
- // true iff called for the first time.
- bool MarkPrerequisiteAsSettling(AbstractPromise* settled_prerequisite);
-
- // Invoked when this promise is notified that |canceled_prerequisite| is
- // cancelled. Clears the reference to |canceled_prerequisite| in this
- // AdjacencyList to ensure the it is not accessed later when Clear() is
- // called.
- void RemoveCanceledPrerequisite(AbstractPromise* canceled_prerequisite);
-
- std::vector<DependentList::Node>* prerequisite_list() {
- return &prerequisite_list_;
- }
-
- AbstractPromise* GetFirstSettledPrerequisite() const {
- return reinterpret_cast<AbstractPromise*>(
- first_settled_prerequisite_.load(std::memory_order_acquire));
- }
-
- void Clear();
-
- private:
- std::vector<DependentList::Node> prerequisite_list_;
-
- // PrerequisitePolicy::kAny waits for at most 1 resolve or N cancellations.
- // PrerequisitePolicy::kAll waits for N resolves or at most 1 cancellation.
- // PrerequisitePolicy::kNever doesn't use this.
- std::atomic_int action_prerequisite_count_;
-
- // For PrerequisitePolicy::kAll the address of the first rejected
- // prerequisite if any.
- // For PrerequisitePolicy::kAll the address of the first rejected or
- // resolved rerequsite if any.
- std::atomic<uintptr_t> first_settled_prerequisite_{0};
- };
-
- const std::vector<DependentList::Node>* prerequisite_list() const {
- if (!prerequisites_)
- return nullptr;
- return prerequisites_->prerequisite_list();
- }
-
- // Returns the first and only prerequisite AbstractPromise. It's an error to
- // call this if the number of prerequisites isn't exactly one.
- AbstractPromise* GetOnlyPrerequisite() const {
- DCHECK(prerequisites_);
- const std::vector<DependentList::Node>* prerequisite_list =
- prerequisites_->prerequisite_list();
- DCHECK_EQ(prerequisite_list->size(), 1u);
- return (*prerequisite_list)[0].prerequisite();
- }
-
- // For PrerequisitePolicy::kAll returns the first rejected prerequisite if
- // any. For PrerequisitePolicy::kAny returns the first rejected or resolved
- // rerequsite if any.
- AbstractPromise* GetFirstSettledPrerequisite() const;
-
- // Calls |RunExecutor()| or posts a task to do so if |from_here_| is not
- // nullopt.
- void Execute();
-
- void IgnoreUncaughtCatchForTesting();
-
- // Signals that this promise was cancelled. If executor hasn't run yet, this
- // will prevent it from running and cancels any dependent promises unless they
- // have PrerequisitePolicy::kAny, in which case they will only be canceled if
- // all of their prerequisites are canceled. If OnCanceled() or OnResolved() or
- // OnRejected() has already run, this does nothing.
- void OnCanceled();
-
- private:
- friend base::RefCountedThreadSafe<AbstractPromise>;
-
- friend class AbstractPromiseTest;
-
- template <typename ResolveType, typename RejectType>
- friend class base::ManualPromiseResolver;
-
- template <typename T, typename... Args>
- friend class PromiseCallbackHelper;
-
- template <typename ConstructType>
- AbstractPromise(const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- std::unique_ptr<AdjacencyList> prerequisites,
- RejectPolicy reject_policy,
- ConstructType tag,
- PromiseExecutor::Data&& executor_data) noexcept
- : task_runner_(task_runner),
- from_here_(std::move(from_here)),
- value_(in_place_type_t<PromiseExecutor>(), std::move(executor_data)),
-#if DCHECK_IS_ON()
- reject_policy_(reject_policy),
- resolve_argument_passing_type_(
- GetExecutor()->ResolveArgumentPassingType()),
- reject_argument_passing_type_(
- GetExecutor()->RejectArgumentPassingType()),
- executor_can_resolve_(GetExecutor()->CanResolve()),
- executor_can_reject_(GetExecutor()->CanReject()),
-#endif
- dependents_(tag),
- prerequisites_(std::move(prerequisites)) {
-#if DCHECK_IS_ON()
- {
- CheckedAutoLock lock(GetCheckedLock());
- if (executor_can_resolve_) {
- this_resolve_ =
- MakeRefCounted<DoubleMoveDetector>(from_here_, "resolve");
- }
-
- if (executor_can_reject_) {
- this_reject_ = MakeRefCounted<DoubleMoveDetector>(from_here_, "reject");
-
- if (reject_policy_ == RejectPolicy::kMustCatchRejection) {
- this_must_catch_ = MakeRefCounted<LocationRef>(from_here_);
- }
- }
- }
-#endif
- }
-
- NOINLINE ~AbstractPromise();
-
- // Follows the chain of CurriedPromises attempting to find the non-curried
- // root. This isn't always possible because some nodes may not have settled
- // yet, in which case the non-settled ancestor is returned. A node may also
- // have been canceled, in which case null is returned.
- AbstractPromise* FindCurriedAncestor();
-
- // Signals that |value_| now contains a resolve value. Dependent promises may
- // scheduled for execution.
- void OnResolved();
-
- // Signals that |value_| now contains a reject value. Dependent promises may
- // scheduled for execution.
- void OnRejected();
-
- // Returns the curried promise if there is one or null otherwise.
- AbstractPromise* GetCurriedPromise();
-
- // Returns the associated PromiseExecutor if there is one.
- const PromiseExecutor* GetExecutor() const;
-
- PromiseExecutor* GetExecutor() {
- return const_cast<PromiseExecutor*>(
- const_cast<const AbstractPromise*>(this)->GetExecutor());
- }
-
- // With the exception of curried promises, this may only be called before the
- // executor has run.
- PromiseExecutor::PrerequisitePolicy GetPrerequisitePolicy();
-
- void AddAsDependentForAllPrerequisites();
-
- // If the promise hasn't executed then |node| is added to the list. If it has
- // and it was resolved or rejected then the corresponding promise is scheduled
- // for execution if necessary. If this promise was canceled this is a NOP.
- // Returns false if this operation failed because this promise became canceled
- // as a result of adding a dependency on a canceled |node|.
- bool InsertDependentOnAnyThread(DependentList::Node* node);
-
- // Checks if the promise is now ready to be executed and if so posts it on the
- // given task runner.
- void OnPrerequisiteResolved(AbstractPromise* resolved_prerequisite);
-
- // Schedules the promise for execution.
- void OnPrerequisiteRejected(AbstractPromise* rejected_prerequisite);
-
- // Returns true if we are still potentially eligible to run despite the
- // cancellation.
- bool OnPrerequisiteCancelled(AbstractPromise* canceled_prerequisite);
-
- // This promise was resolved, post any dependent promises that are now ready
- // as a result.
- void OnResolveDispatchReadyDependents();
-
- // This promise was rejected, post any dependent promises that are now ready
- // as a result.
- void OnRejectDispatchReadyDependents();
-
- // This promise was resolved with a curried promise, make any dependent
- // promises depend on |non_curried_root| instead.
- void OnResolveMakeDependantsUseCurriedPrerequisite(
- AbstractPromise* non_curried_root);
-
- // This promise was rejected with a curried promise, make any dependent
- // promises depend on |non_curried_root| instead.
- void OnRejectMakeDependantsUseCurriedPrerequisite(
- AbstractPromise* non_curried_root);
-
- void DispatchPromise();
-
- // Reverses |list| so dependents can be dispatched in the order they where
- // added. Assumes no other thread is accessing |list|.
- static DependentList::Node* NonThreadSafeReverseList(
- DependentList::Node* list);
-
- void ReplaceCurriedPrerequisite(AbstractPromise* curried_prerequisite,
- AbstractPromise* replacement);
-
- scoped_refptr<TaskRunner> task_runner_;
-
- const Location from_here_;
-
- // To save memory |value_| contains Executor (which is stored inline) before
- // it has run and afterwards it contains one of:
- // * Resolved<T>
- // * Rejected<T>
- // * scoped_refptr<AbstractPromise> (for curried promises - i.e. a promise
- // which is resolved with a promise).
- //
- // The state transitions which occur during Execute() (which is once only) are
- // like so:
- //
- // ┌────────── Executor ─────────┐
- // | | │
- // | | │
- // ↓ | ↓
- // Resolved<T> | Rejected<T>
- // ↓
- // scoped_refptr<AbstractPromise>
- //
- PromiseValue value_;
-
-#if DCHECK_IS_ON()
- // |on_api_error_callback| is called when an API usage error is spotted.
- static void SetApiErrorObserverForTesting(
- RepeatingClosure on_api_error_callback);
-
- void MaybeInheritChecks(AbstractPromise* source)
- EXCLUSIVE_LOCKS_REQUIRED(GetCheckedLock());
-
- // Controls how we deal with unhandled rejection.
- const RejectPolicy reject_policy_;
-
- // Cached because we need to access these values after the Executor they came
- // from has gone away.
- const PromiseExecutor::ArgumentPassingType resolve_argument_passing_type_;
- const PromiseExecutor::ArgumentPassingType reject_argument_passing_type_;
- const bool executor_can_resolve_;
- const bool executor_can_reject_;
-
- // Whether responsibility for catching rejected promise has been passed on to
- // this promise's dependents.
- bool passed_catch_responsibility_ GUARDED_BY(GetCheckedLock()) = false;
-
- static CheckedLock& GetCheckedLock();
-
- // Used to avoid refcounting cycles.
- class BASE_EXPORT LocationRef : public RefCountedThreadSafe<LocationRef> {
- public:
- explicit LocationRef(const Location& from_here);
-
- const Location& from_here() const { return from_here_; }
-
- private:
- Location from_here_;
-
- friend class RefCountedThreadSafe<LocationRef>;
- ~LocationRef();
- };
-
- // For catching missing catches.
- scoped_refptr<LocationRef> must_catch_ancestor_that_could_reject_
- GUARDED_BY(GetCheckedLock());
-
- // Used to supply all child nodes with a single LocationRef.
- scoped_refptr<LocationRef> this_must_catch_ GUARDED_BY(GetCheckedLock());
-
- class BASE_EXPORT DoubleMoveDetector
- : public RefCountedThreadSafe<DoubleMoveDetector> {
- public:
- DoubleMoveDetector(const Location& from_here, const char* callback_type);
-
- void CheckForDoubleMoveErrors(
- const base::Location& new_dependent_location,
- PromiseExecutor::ArgumentPassingType new_dependent_executor_type);
-
- private:
- const Location from_here_;
- const char* callback_type_;
- std::unique_ptr<Location> dependent_move_only_promise_;
- std::unique_ptr<Location> dependent_normal_promise_;
-
- friend class RefCountedThreadSafe<DoubleMoveDetector>;
- ~DoubleMoveDetector();
- };
-
- // Used to supply all child nodes with a single DoubleMoveDetector.
- scoped_refptr<DoubleMoveDetector> this_resolve_ GUARDED_BY(GetCheckedLock());
-
- // Used to supply all child nodes with a single DoubleMoveDetector.
- scoped_refptr<DoubleMoveDetector> this_reject_ GUARDED_BY(GetCheckedLock());
-
- // Validates that the value of this promise, or the value of the closest
- // ancestor that can resolve if this promise can't resolve, is not
- // double-moved.
- scoped_refptr<DoubleMoveDetector> ancestor_that_could_resolve_
- GUARDED_BY(GetCheckedLock());
-
- // Validates that the value of this promise, or the value of the closest
- // ancestor that can reject if this promise can't reject, is not
- // double-moved.
- scoped_refptr<DoubleMoveDetector> ancestor_that_could_reject_
- GUARDED_BY(GetCheckedLock());
-#endif
-
- // List of promises which are dependent on this one.
- DependentList dependents_;
-
- // Details of any promises this promise is dependent on. If there are none
- // |prerequisites_| will be null. This is a space optimization for the common
- // case of a non-chained PostTask.
- std::unique_ptr<AdjacencyList> prerequisites_;
-};
-
-PassedPromise::PassedPromise(const scoped_refptr<AbstractPromise>& promise)
- : promise_(promise.get()) {
- promise_->AddRef();
-}
-
-// Non-templatized base class of the Promise<> template. This is a binary size
-// optimization, letting us use an out of line destructor in the template
-// instead of the more complex scoped_refptr<> destructor.
-class BASE_EXPORT BasePromise {
- public:
- BasePromise();
-
- BasePromise(const BasePromise& other);
- BasePromise(BasePromise&& other) noexcept;
-
- BasePromise& operator=(const BasePromise& other);
- BasePromise& operator=(BasePromise&& other) noexcept;
-
- // We want an out of line destructor to reduce binary size.
- ~BasePromise();
-
- // Returns true if the promise is not null.
- operator bool() const { return abstract_promise_.get(); }
-
- protected:
- struct InlineConstructor {};
-
- explicit BasePromise(
- scoped_refptr<internal::AbstractPromise> abstract_promise);
-
- // We want this to be inlined to reduce binary size for the Promise<>
- // constructor. Its a template to bypass ChromiumStyle plugin which otherwise
- // insists this is out of line.
- template <typename T>
- explicit BasePromise(internal::PassedPromise&& passed_promise,
- T InlineConstructor)
- : abstract_promise_(passed_promise.Release(), subtle::kAdoptRefTag) {}
-
- scoped_refptr<internal::AbstractPromise> abstract_promise_;
-};
-
-} // namespace internal
-
-// Wrapper around scoped_refptr<base::internal::AbstractPromise> which is
-// intended for use by TaskRunner implementations.
-class BASE_EXPORT WrappedPromise {
- public:
- WrappedPromise();
-
- explicit WrappedPromise(scoped_refptr<internal::AbstractPromise> promise);
-
- WrappedPromise(const WrappedPromise& other);
- WrappedPromise(WrappedPromise&& other) noexcept;
-
- WrappedPromise& operator=(const WrappedPromise& other);
- WrappedPromise& operator=(WrappedPromise&& other) noexcept;
-
- explicit WrappedPromise(internal::PassedPromise&& passed_promise);
-
- // Constructs a promise to run |task|.
- WrappedPromise(const Location& from_here, OnceClosure task);
-
- // If the WrappedPromise hasn't been executed, cleared or taken by
- // TakeForTesting, it will be canceled to prevent memory leaks of dependent
- // tasks that will never run.
- ~WrappedPromise();
-
- // Returns true if the promise is not null.
- operator bool() const { return promise_.get(); }
-
- bool IsCanceled() const {
- DCHECK(promise_);
- return promise_->IsCanceled();
- }
-
- void OnCanceled() {
- DCHECK(promise_);
- promise_->OnCanceled();
- }
-
- // Can only be called once, clears |promise_| after execution.
- void Execute();
-
- // Clears |promise_|.
- void Clear();
-
- const Location& from_here() const {
- DCHECK(promise_);
- return promise_->from_here();
- }
-
- scoped_refptr<internal::AbstractPromise>& GetForTesting() { return promise_; }
-
- scoped_refptr<internal::AbstractPromise> TakeForTesting() {
- return std::move(promise_);
- }
-
- private:
- template <typename ResolveType, typename RejectType>
- friend class Promise;
-
- template <typename T, typename... Args>
- friend class internal::PromiseCallbackHelper;
-
- friend class Promises;
-
- scoped_refptr<internal::AbstractPromise> promise_;
-};
-
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_ABSTRACT_PROMISE_H_
diff --git a/task/promise/abstract_promise_unittest.cc b/task/promise/abstract_promise_unittest.cc
deleted file mode 100644
index 5cbe449..0000000
--- a/task/promise/abstract_promise_unittest.cc
+++ /dev/null
@@ -1,2447 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/abstract_promise.h"
-
-#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
-#include "base/test/do_nothing_promise.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Errors from PROMISE_API_DCHECK are only observable in builds where DCHECKS
-// are on.
-#if DCHECK_IS_ON()
-#define PROMISE_API_DCHECK_TEST(test_name) test_name
-#else
-#define PROMISE_API_DCHECK_TEST(test_name) DISABLED_##test_name
-#endif
-
-#define EXPECT_PROMISE_DCHECK_FAIL(code_that_should_fail) \
- { \
- bool api_error_reported = false; \
- SetApiErrorObserver( \
- BindLambdaForTesting([&] { api_error_reported = true; })); \
- code_that_should_fail; \
- EXPECT_TRUE(api_error_reported); \
- SetApiErrorObserver(RepeatingClosure()); \
- }
-
-using testing::ElementsAre;
-
-using ArgumentPassingType =
- base::internal::PromiseExecutor::ArgumentPassingType;
-
-using PrerequisitePolicy = base::internal::PromiseExecutor::PrerequisitePolicy;
-
-namespace base {
-namespace internal {
-namespace {
-
-size_t CountTasksRunUntilIdle(
- const scoped_refptr<TestSimpleTaskRunner>& task_runner) {
- size_t count = 0;
- while (task_runner->HasPendingTask()) {
- count += task_runner->NumPendingTasks();
- task_runner->RunPendingTasks();
- }
- return count;
-}
-
-} // namespace
-
-template <PrerequisitePolicy PREREQUISITE_POLICY>
-class TestExecutor {
- public:
- TestExecutor(
-#if DCHECK_IS_ON()
- ArgumentPassingType resolve_executor_type,
- ArgumentPassingType reject_executor_type,
- bool can_resolve,
- bool can_reject,
-#endif
- base::OnceCallback<void(AbstractPromise*)> callback)
- : callback_(std::move(callback))
-#if DCHECK_IS_ON()
- ,
- resolve_argument_passing_type_(resolve_executor_type),
- reject_argument_passing_type_(reject_executor_type),
- resolve_flags_(can_resolve + (can_reject << 1))
-#endif
- {
- }
-
-#if DCHECK_IS_ON()
- ArgumentPassingType ResolveArgumentPassingType() const {
- return resolve_argument_passing_type_;
- }
-
- ArgumentPassingType RejectArgumentPassingType() const {
- return reject_argument_passing_type_;
- }
-
- bool CanResolve() const { return resolve_flags_ & 1; }
-
- bool CanReject() const { return resolve_flags_ & 2; }
-#endif
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- PREREQUISITE_POLICY;
-
- bool IsCancelled() const { return false; }
-
- void Execute(AbstractPromise* p) { std::move(callback_).Run(p); }
-
- private:
- base::OnceCallback<void(AbstractPromise*)> callback_;
-#if DCHECK_IS_ON()
- const ArgumentPassingType resolve_argument_passing_type_;
- const ArgumentPassingType reject_argument_passing_type_;
- // On 32 bit platform we need to pack to fit in the space requirement of 3x
- // void*.
- uint8_t resolve_flags_;
-#endif
-};
-
-class AbstractPromiseTest : public testing::Test {
- public:
- void SetApiErrorObserver(RepeatingClosure on_api_error_callback) {
-#if DCHECK_IS_ON()
- AbstractPromise::SetApiErrorObserverForTesting(
- std::move(on_api_error_callback));
-#endif
- }
-
- enum class CallbackResultType : uint8_t {
- kNoCallback,
- kCanResolve,
- kCanReject,
- kCanResolveOrReject,
- };
-
- struct PromiseSettings {
- PromiseSettings(
- Location from_here,
- std::unique_ptr<AbstractPromise::AdjacencyList> prerequisites)
- : from_here(from_here), prerequisites(std::move(prerequisites)) {}
-
- Location from_here;
-
- std::unique_ptr<AbstractPromise::AdjacencyList> prerequisites;
-
- PrerequisitePolicy prerequisite_policy =
- PromiseExecutor::PrerequisitePolicy::kAll;
-
- bool executor_can_resolve = true;
-
- bool executor_can_reject = false;
-
- ArgumentPassingType resolve_executor_type = ArgumentPassingType::kNormal;
-
- ArgumentPassingType reject_executor_type = ArgumentPassingType::kNoCallback;
-
- RejectPolicy reject_policy = RejectPolicy::kMustCatchRejection;
-
- base::OnceCallback<void(AbstractPromise*)> callback;
-
- scoped_refptr<TaskRunner> task_runner = ThreadTaskRunnerHandle::Get();
- };
-
- class PromiseSettingsBuilder {
- public:
- PromiseSettingsBuilder(
- Location from_here,
- std::unique_ptr<AbstractPromise::AdjacencyList> prerequisites)
- : settings(from_here, std::move(prerequisites)) {}
-
- PromiseSettingsBuilder& With(PrerequisitePolicy prerequisite_policy) {
- settings.prerequisite_policy = prerequisite_policy;
- return *this;
- }
-
- PromiseSettingsBuilder& With(const scoped_refptr<TaskRunner>& task_runner) {
- settings.task_runner = task_runner;
- return *this;
- }
-
- PromiseSettingsBuilder& With(RejectPolicy reject_policy) {
- settings.reject_policy = reject_policy;
- return *this;
- }
-
- PromiseSettingsBuilder& With(
- base::OnceCallback<void(AbstractPromise*)> callback) {
- settings.callback = std::move(callback);
- return *this;
- }
-
- PromiseSettingsBuilder& With(CallbackResultType callback_result_type) {
- switch (callback_result_type) {
- case CallbackResultType::kNoCallback:
- settings.executor_can_resolve = false;
- settings.executor_can_reject = false;
- break;
- case CallbackResultType::kCanResolve:
- settings.executor_can_resolve = true;
- settings.executor_can_reject = false;
- break;
- case CallbackResultType::kCanReject:
- settings.executor_can_resolve = false;
- settings.executor_can_reject = true;
- break;
- case CallbackResultType::kCanResolveOrReject:
- settings.executor_can_resolve = true;
- settings.executor_can_reject = true;
- break;
- };
- return *this;
- }
-
- PromiseSettingsBuilder& WithResolve(
- ArgumentPassingType resolve_executor_type) {
- settings.resolve_executor_type = resolve_executor_type;
- return *this;
- }
-
- PromiseSettingsBuilder& WithReject(
- ArgumentPassingType reject_executor_type) {
- settings.reject_executor_type = reject_executor_type;
- return *this;
- }
-
- operator scoped_refptr<AbstractPromise>() {
- switch (settings.prerequisite_policy) {
- case PrerequisitePolicy::kAll:
- return MakeAbstractPromise<PrerequisitePolicy::kAll>();
-
- case PrerequisitePolicy::kAny:
- return MakeAbstractPromise<PrerequisitePolicy::kAny>();
-
- case PrerequisitePolicy::kNever:
- return MakeAbstractPromise<PrerequisitePolicy::kNever>();
- }
- }
-
- private:
- template <PrerequisitePolicy POLICY>
- scoped_refptr<AbstractPromise> MakeAbstractPromise() {
- PromiseExecutor::Data executor_data(
- in_place_type_t<TestExecutor<POLICY>>(),
-#if DCHECK_IS_ON()
- settings.resolve_executor_type, settings.reject_executor_type,
- settings.executor_can_resolve, settings.executor_can_reject,
-#endif
- std::move(settings.callback));
-
- return WrappedPromise(AbstractPromise::Create(
- settings.task_runner, settings.from_here,
- std::move(settings.prerequisites),
- settings.reject_policy,
- DependentList::ConstructUnresolved(),
- std::move(executor_data)))
- .TakeForTesting();
- }
-
- PromiseSettings settings;
- };
-
- PromiseSettingsBuilder ThenPromise(Location from_here,
- scoped_refptr<AbstractPromise> parent) {
- PromiseSettingsBuilder builder(
- from_here,
- parent ? std::make_unique<AbstractPromise::AdjacencyList>(parent.get())
- : std::make_unique<AbstractPromise::AdjacencyList>());
- builder.With(BindOnce([](AbstractPromise* p) {
- AbstractPromise* prerequisite = p->GetOnlyPrerequisite();
- if (prerequisite->IsResolved()) {
- p->emplace(Resolved<void>());
- } else if (prerequisite->IsRejected()) {
- // Consistent with BaseThenAndCatchExecutor::ProcessNullExecutor.
- p->emplace(scoped_refptr<AbstractPromise>(prerequisite));
- } else {
- NOTREACHED();
- }
- }));
- return builder;
- }
-
- PromiseSettingsBuilder CatchPromise(Location from_here,
- scoped_refptr<AbstractPromise> parent) {
- PromiseSettingsBuilder builder(
- from_here,
- parent ? std::make_unique<AbstractPromise::AdjacencyList>(parent.get())
- : std::make_unique<AbstractPromise::AdjacencyList>());
- builder.With(CallbackResultType::kNoCallback)
- .With(CallbackResultType::kCanResolve)
- .WithResolve(ArgumentPassingType::kNoCallback)
- .WithReject(ArgumentPassingType::kNormal)
- .With(BindOnce([](AbstractPromise* p) {
- AbstractPromise* prerequisite = p->GetOnlyPrerequisite();
- if (prerequisite->IsResolved()) {
- // Consistent with BaseThenAndCatchExecutor::ProcessNullExecutor.
- p->emplace(scoped_refptr<AbstractPromise>(prerequisite));
- } else if (prerequisite->IsRejected()) {
- p->emplace(Resolved<void>());
- } else {
- NOTREACHED();
- }
- }));
- return builder;
- }
-
- PromiseSettingsBuilder AllPromise(
- Location from_here,
- std::vector<DependentList::Node> prerequisite_list) {
- PromiseSettingsBuilder builder(
- from_here, std::make_unique<AbstractPromise::AdjacencyList>(
- std::move(prerequisite_list)));
- builder.With(PrerequisitePolicy::kAll)
- .With(BindOnce([](AbstractPromise* p) {
- AbstractPromise* first_settled = p->GetFirstSettledPrerequisite();
- if (first_settled && first_settled->IsRejected()) {
- p->emplace(Rejected<void>());
- return;
- }
-
- p->emplace(Resolved<void>());
- }));
- return builder;
- }
-
- PromiseSettingsBuilder AnyPromise(
- Location from_here,
- std::vector<internal::DependentList::Node> prerequisite_list) {
- PromiseSettingsBuilder builder(
- from_here, std::make_unique<AbstractPromise::AdjacencyList>(
- std::move(prerequisite_list)));
- builder.With(PrerequisitePolicy::kAny)
- .With(BindOnce([](AbstractPromise* p) {
- AbstractPromise* first_settled = p->GetFirstSettledPrerequisite();
- if (first_settled && first_settled->IsRejected()) {
- p->emplace(Rejected<void>());
- return;
- }
-
- p->emplace(Resolved<void>());
- }));
- return builder;
- }
-
- // Convenience wrappers for calling private methods.
- static void OnCanceled(scoped_refptr<AbstractPromise> promise) {
- promise->OnCanceled();
- }
-
- static void OnResolved(scoped_refptr<AbstractPromise> promise) {
- promise->OnResolved();
- }
-
- static void OnRejected(scoped_refptr<AbstractPromise> promise) {
- promise->OnRejected();
- }
-
- static AbstractPromise* GetCurriedPromise(AbstractPromise* promise) {
- return promise->GetCurriedPromise();
- }
-
- test::TaskEnvironment task_environment_;
-};
-
-TEST_F(AbstractPromiseTest, UnfulfilledPromise) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- EXPECT_FALSE(promise->IsResolvedForTesting());
- EXPECT_FALSE(promise->IsRejectedForTesting());
- EXPECT_FALSE(promise->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, OnResolve) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- EXPECT_FALSE(promise->IsResolvedForTesting());
- OnResolved(promise);
- EXPECT_TRUE(promise->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, OnReject) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
- EXPECT_FALSE(promise->IsRejectedForTesting());
- OnRejected(promise);
- EXPECT_TRUE(promise->IsRejectedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, ExecuteOnResolve) {
- scoped_refptr<AbstractPromise> promise =
- ThenPromise(FROM_HERE, nullptr).With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }));
-
- EXPECT_FALSE(promise->IsResolvedForTesting());
- promise->Execute();
- EXPECT_TRUE(promise->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, ExecuteOnReject) {
- scoped_refptr<AbstractPromise> promise =
- ThenPromise(FROM_HERE, nullptr)
- .With(RejectPolicy::kCatchNotRequired)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- EXPECT_FALSE(promise->IsRejectedForTesting());
- promise->Execute();
- EXPECT_TRUE(promise->IsRejectedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, ExecutionChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p3);
- scoped_refptr<AbstractPromise> p5 = ThenPromise(FROM_HERE, p4);
-
- OnResolved(p1);
-
- EXPECT_FALSE(p2->IsResolvedForTesting());
- EXPECT_FALSE(p3->IsResolvedForTesting());
- EXPECT_FALSE(p4->IsResolvedForTesting());
- EXPECT_FALSE(p5->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p1->IsResolvedForTesting());
- EXPECT_TRUE(p3->IsResolvedForTesting());
- EXPECT_TRUE(p4->IsResolvedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MoveExecutionChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1).WithResolve(ArgumentPassingType::kMove);
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p2).WithResolve(ArgumentPassingType::kMove);
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3).WithResolve(ArgumentPassingType::kMove);
-
- scoped_refptr<AbstractPromise> p5 =
- ThenPromise(FROM_HERE, p4).WithResolve(ArgumentPassingType::kMove);
-
- OnResolved(p1);
-
- EXPECT_FALSE(p2->IsResolvedForTesting());
- EXPECT_FALSE(p3->IsResolvedForTesting());
- EXPECT_FALSE(p4->IsResolvedForTesting());
- EXPECT_FALSE(p5->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p1->IsResolvedForTesting());
- EXPECT_TRUE(p3->IsResolvedForTesting());
- EXPECT_TRUE(p4->IsResolvedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MoveResolveCatchExecutionChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1)
- .With(CallbackResultType::kCanReject)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, p2)
- .With(CallbackResultType::kCanResolve)
- .WithReject(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }));
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3)
- .With(CallbackResultType::kCanReject)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p5 =
- CatchPromise(FROM_HERE, p4)
- .With(CallbackResultType::kCanResolve)
- .WithReject(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }));
-
- OnResolved(p1);
-
- EXPECT_FALSE(p2->IsRejectedForTesting());
- EXPECT_FALSE(p3->IsResolvedForTesting());
- EXPECT_FALSE(p4->IsRejectedForTesting());
- EXPECT_FALSE(p5->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p2->IsRejectedForTesting());
- EXPECT_TRUE(p3->IsResolvedForTesting());
- EXPECT_TRUE(p4->IsRejectedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MoveResolveCatchExecutionChainType2) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1)
- .With(CallbackResultType::kCanReject)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, p2)
- .With(CallbackResultType::kCanReject)
- .WithReject(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p4 =
- CatchPromise(FROM_HERE, p3)
- .With(CallbackResultType::kCanResolve)
- .WithReject(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }));
-
- scoped_refptr<AbstractPromise> p5 =
- ThenPromise(FROM_HERE, p4)
- .With(CallbackResultType::kCanResolve)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }));
-
- scoped_refptr<AbstractPromise> p6 =
- ThenPromise(FROM_HERE, p5)
- .With(CallbackResultType::kCanReject)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p7 =
- CatchPromise(FROM_HERE, p6)
- .With(CallbackResultType::kCanReject)
- .WithReject(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p8 =
- CatchPromise(FROM_HERE, p7)
- .With(CallbackResultType::kCanResolve)
- .WithReject(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }));
-
- scoped_refptr<AbstractPromise> p9 =
- ThenPromise(FROM_HERE, p8)
- .With(CallbackResultType::kCanResolve)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }));
- OnResolved(p1);
-
- EXPECT_FALSE(p2->IsRejectedForTesting());
- EXPECT_FALSE(p3->IsRejectedForTesting());
- EXPECT_FALSE(p4->IsResolvedForTesting());
- EXPECT_FALSE(p5->IsResolvedForTesting());
- EXPECT_FALSE(p6->IsRejectedForTesting());
- EXPECT_FALSE(p7->IsRejectedForTesting());
- EXPECT_FALSE(p8->IsResolvedForTesting());
- EXPECT_FALSE(p9->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p2->IsRejectedForTesting());
- EXPECT_TRUE(p3->IsRejectedForTesting());
- EXPECT_TRUE(p4->IsResolvedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
- EXPECT_TRUE(p6->IsRejectedForTesting());
- EXPECT_TRUE(p7->IsRejectedForTesting());
- EXPECT_TRUE(p8->IsResolvedForTesting());
- EXPECT_TRUE(p9->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MixedMoveAndNormalExecutionChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1).WithResolve(ArgumentPassingType::kMove);
-
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3).WithResolve(ArgumentPassingType::kMove);
-
- scoped_refptr<AbstractPromise> p5 = ThenPromise(FROM_HERE, p4);
-
- OnResolved(p1);
-
- EXPECT_FALSE(p2->IsResolvedForTesting());
- EXPECT_FALSE(p3->IsResolvedForTesting());
- EXPECT_FALSE(p4->IsResolvedForTesting());
- EXPECT_FALSE(p5->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p1->IsResolvedForTesting());
- EXPECT_TRUE(p3->IsResolvedForTesting());
- EXPECT_TRUE(p4->IsResolvedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MoveAtEndOfChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p2).WithResolve(ArgumentPassingType::kMove);
-}
-
-TEST_F(AbstractPromiseTest, BranchedExecutionChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p5 = ThenPromise(FROM_HERE, p4);
-
- OnResolved(p1);
-
- EXPECT_FALSE(p2->IsResolvedForTesting());
- EXPECT_FALSE(p3->IsResolvedForTesting());
- EXPECT_FALSE(p4->IsResolvedForTesting());
- EXPECT_FALSE(p5->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p2->IsResolvedForTesting());
- EXPECT_TRUE(p3->IsResolvedForTesting());
- EXPECT_TRUE(p4->IsResolvedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, PrerequisiteAlreadyResolved) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- OnResolved(p1);
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
-
- EXPECT_FALSE(p2->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p2->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, PrerequisiteAlreadyRejected) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- OnRejected(p1);
- ;
-
- scoped_refptr<AbstractPromise> p2 =
- CatchPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- EXPECT_TRUE(
- p->GetFirstSettledPrerequisite()->IsRejectedForTesting());
- EXPECT_EQ(p->GetFirstSettledPrerequisite(), p1);
- p->emplace(Resolved<void>());
- }));
-
- EXPECT_FALSE(p2->IsResolvedForTesting());
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p2->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MultipleResolvedPrerequisitePolicyALL) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> all_promise =
- AllPromise(FROM_HERE, std::move(prerequisite_list));
-
- OnResolved(p1);
- OnResolved(p2);
- OnResolved(p3);
- RunLoop().RunUntilIdle();
-
- EXPECT_FALSE(all_promise->IsResolvedForTesting());
- OnResolved(p4);
-
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(all_promise->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest,
- MultithreadedMultipleResolvedPrerequisitePolicyALL) {
- constexpr int num_threads = 4;
- constexpr int num_promises = 1000;
-
- std::unique_ptr<Thread> thread[num_threads];
- for (int i = 0; i < num_threads; i++) {
- thread[i] = std::make_unique<Thread>("Test thread");
- thread[i]->Start();
- }
-
- scoped_refptr<AbstractPromise> promise[num_promises];
- std::vector<internal::DependentList::Node> prerequisite_list(num_promises);
- for (int i = 0; i < num_promises; i++) {
- promise[i] = DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- prerequisite_list[i].SetPrerequisite(promise[i].get());
- }
-
- scoped_refptr<AbstractPromise> all_promise =
- AllPromise(FROM_HERE, std::move(prerequisite_list));
-
- RunLoop run_loop;
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, all_promise)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_loop.Quit();
- p->emplace(Resolved<void>());
- }));
-
- for (int i = 0; i < num_promises; i++) {
- thread[i % num_threads]->task_runner()->PostTask(
- FROM_HERE, BindOnce(
- [](scoped_refptr<AbstractPromise> all_promise,
- scoped_refptr<AbstractPromise> promise) {
- EXPECT_FALSE(all_promise->IsResolvedForTesting());
- AbstractPromiseTest::OnResolved(promise);
- },
- all_promise, promise[i]));
- }
-
- run_loop.Run();
-
- for (int i = 0; i < num_promises; i++) {
- EXPECT_TRUE(promise[i]->IsResolvedForTesting());
- }
-
- EXPECT_TRUE(all_promise->IsResolvedForTesting());
-
- for (int i = 0; i < num_threads; i++) {
- thread[i]->Stop();
- }
-}
-
-TEST_F(AbstractPromiseTest, SingleRejectPrerequisitePolicyALL) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> all_promise =
- AllPromise(FROM_HERE, std::move(prerequisite_list))
- .With(CallbackResultType::kCanResolveOrReject)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- EXPECT_TRUE(
- p->GetFirstSettledPrerequisite()->IsRejectedForTesting());
- EXPECT_EQ(p->GetFirstSettledPrerequisite(), p3);
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p5 = CatchPromise(FROM_HERE, all_promise);
-
- OnRejected(p3);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(all_promise->IsRejectedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MultipleRejectPrerequisitePolicyALL) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> all_promise =
- AllPromise(FROM_HERE, std::move(prerequisite_list))
- .With(CallbackResultType::kCanResolveOrReject)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- AbstractPromise* settled = p->GetFirstSettledPrerequisite();
- if (settled && settled->IsRejected()) {
- EXPECT_EQ(settled, p2);
- p->emplace(Rejected<void>());
- } else {
- FAIL() << "A prerequisite was rejected";
- }
- }));
-
- scoped_refptr<AbstractPromise> p5 =
- CatchPromise(FROM_HERE, all_promise)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- EXPECT_FALSE(p->IsSettled()); // Should only happen once.
- EXPECT_TRUE(
- p->GetFirstSettledPrerequisite()->IsRejectedForTesting());
- EXPECT_EQ(p->GetFirstSettledPrerequisite(), all_promise);
- p->emplace(Resolved<void>());
- }));
-
- OnRejected(p2);
- OnRejected(p1);
- OnRejected(p3);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(all_promise->IsRejectedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, SingleResolvedPrerequisitePolicyANY) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> any_promise =
- AnyPromise(FROM_HERE, std::move(prerequisite_list));
-
- OnResolved(p2);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(any_promise->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, MultipleResolvedPrerequisitePolicyANY) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> any_promise =
- AnyPromise(FROM_HERE, std::move(prerequisite_list));
-
- OnResolved(p1);
- OnResolved(p2);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(any_promise->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, SingleRejectPrerequisitePolicyANY) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> any_promise =
- AnyPromise(FROM_HERE, std::move(prerequisite_list))
- .With(CallbackResultType::kCanResolveOrReject);
-
- scoped_refptr<AbstractPromise> p5 = CatchPromise(FROM_HERE, any_promise);
-
- OnRejected(p3);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(any_promise->IsRejectedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, SingleResolvePrerequisitePolicyANY) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> any_promise =
- AnyPromise(FROM_HERE, std::move(prerequisite_list));
-
- scoped_refptr<AbstractPromise> p5 = CatchPromise(FROM_HERE, any_promise);
-
- OnResolved(p3);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(any_promise->IsResolvedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, IsCanceled) {
- scoped_refptr<AbstractPromise> promise = ThenPromise(FROM_HERE, nullptr);
- EXPECT_FALSE(promise->IsCanceled());
- OnCanceled(promise);
- EXPECT_TRUE(promise->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, OnCanceledPreventsExecution) {
- scoped_refptr<AbstractPromise> promise =
- ThenPromise(FROM_HERE, nullptr).With(BindOnce([](AbstractPromise* p) {
- FAIL() << "Should not be called";
- }));
- OnCanceled(promise);
- promise->Execute();
-}
-
-TEST_F(AbstractPromiseTest, CancelationStopsExecutionChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1).With(BindOnce([](AbstractPromise* p) {
- OnCanceled(p);
- OnCanceled(p); // NOP shouldn't crash.
- }));
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p3);
-
- OnResolved(p1);
-
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p3->IsCanceled());
- EXPECT_TRUE(p4->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, CancelationStopsBranchedExecutionChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1).With(BindOnce([](AbstractPromise* p) {
- // This cancellation should get propagated down the chain which is
- // registered below.
- OnCanceled(p);
- }));
-
- // Branch one
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p3);
-
- // Branch two
- scoped_refptr<AbstractPromise> p5 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> promise6 = ThenPromise(FROM_HERE, p5);
-
- OnResolved(p1);
-
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p3->IsCanceled());
- EXPECT_TRUE(p4->IsCanceled());
- EXPECT_TRUE(p5->IsCanceled());
- EXPECT_TRUE(promise6->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, CancelChainCanReject) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = CatchPromise(FROM_HERE, p2);
-
- OnCanceled(p0);
- RunLoop().RunUntilIdle();
-}
-
-TEST_F(AbstractPromiseTest, CancelationPrerequisitePolicyALL) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(3);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
-
- scoped_refptr<AbstractPromise> all_promise =
- AllPromise(FROM_HERE, std::move(prerequisite_list));
-
- OnCanceled(p2);
- EXPECT_TRUE(all_promise->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, CancelationPrerequisitePolicyANY) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(3);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
-
- scoped_refptr<AbstractPromise> any_promise =
- AnyPromise(FROM_HERE, std::move(prerequisite_list));
-
- OnCanceled(p3);
- OnCanceled(p2);
- EXPECT_FALSE(any_promise->IsCanceled());
-
- OnCanceled(p1);
- EXPECT_TRUE(any_promise->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, AlreadyCanceledPrerequisitePolicyALL) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(3);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- OnCanceled(p2);
-
- scoped_refptr<AbstractPromise> all_promise =
- AllPromise(FROM_HERE, std::move(prerequisite_list));
-
- EXPECT_TRUE(all_promise->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, SomeAlreadyCanceledPrerequisitePolicyANY) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(3);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- OnCanceled(p2);
-
- scoped_refptr<AbstractPromise> any_promise =
- AnyPromise(FROM_HERE, std::move(prerequisite_list));
-
- EXPECT_FALSE(any_promise->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, AllAlreadyCanceledPrerequisitePolicyANY) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- std::vector<internal::DependentList::Node> prerequisite_list(3);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- OnCanceled(p1);
- OnCanceled(p2);
- OnCanceled(p3);
-
- scoped_refptr<AbstractPromise> any_promise =
- AnyPromise(FROM_HERE, std::move(prerequisite_list));
-
- EXPECT_TRUE(any_promise->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, CurriedResolvedPromiseAny) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(BindOnce(
- [](scoped_refptr<AbstractPromise> p2, AbstractPromise* p) {
- p->emplace(std::move(p2));
- },
- p2))
- .With(PrerequisitePolicy::kAny);
-
- scoped_refptr<TestSimpleTaskRunner> task_runner =
- MakeRefCounted<TestSimpleTaskRunner>();
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1).With(task_runner);
-
- OnResolved(p0);
- OnResolved(p2);
- RunLoop().RunUntilIdle();
-
- // |p3| should run.
- EXPECT_EQ(1u, CountTasksRunUntilIdle(task_runner));
-}
-
-TEST_F(AbstractPromiseTest, CurriedRejectedPromiseAny) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true);
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(BindOnce(
- [](scoped_refptr<AbstractPromise> p2, AbstractPromise* p) {
- p->emplace(std::move(p2));
- },
- p2))
- .With(PrerequisitePolicy::kAny);
-
- scoped_refptr<TestSimpleTaskRunner> task_runner =
- MakeRefCounted<TestSimpleTaskRunner>();
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, p1).With(task_runner);
-
- OnResolved(p0);
- OnRejected(p2);
- RunLoop().RunUntilIdle();
-
- // |p3| should run.
- EXPECT_EQ(1u, CountTasksRunUntilIdle(task_runner));
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(DetectResolveDoubleMoveHazard)) {
- scoped_refptr<AbstractPromise> p0 = ThenPromise(FROM_HERE, nullptr);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0).WithResolve(ArgumentPassingType::kMove);
-
- EXPECT_PROMISE_DCHECK_FAIL({
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0).WithResolve(ArgumentPassingType::kMove);
- });
-}
-
-TEST_F(
- AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(DetectMixedResolveCallbackMoveAndNonMoveHazard)) {
- scoped_refptr<AbstractPromise> p0 = ThenPromise(FROM_HERE, nullptr);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0).WithResolve(ArgumentPassingType::kMove);
-
- EXPECT_PROMISE_DCHECK_FAIL(
- { scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p0); });
-}
-
-TEST_F(AbstractPromiseTest, MultipleNonMoveCatchCallbacksAreOK) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * T T
- * | |
- * \| |/
- * P1 P2
- * T T
- * | |
- * \| |/
- * E3 E4
- * C C
- */
- scoped_refptr<AbstractPromise> p0 =
- ThenPromise(FROM_HERE, nullptr).With(CallbackResultType::kCanReject);
-
- scoped_refptr<AbstractPromise> p1 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p3 = CatchPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p2);
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(DetectCatchCallbackDoubleMoveHazard)) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * T T
- * | |
- * \| |/
- * P1 P2
- * C C
- *
- * We need to make sure P3 & P4's reject callback don't both use move
- * semantics since they share a common ancestor with no intermediate catches.
- */
- scoped_refptr<AbstractPromise> p0 =
- ThenPromise(FROM_HERE, nullptr).With(CallbackResultType::kCanReject);
-
- scoped_refptr<AbstractPromise> p1 =
- CatchPromise(FROM_HERE, p0).WithReject(ArgumentPassingType::kMove);
-
- EXPECT_PROMISE_DCHECK_FAIL({
- scoped_refptr<AbstractPromise> p2 =
- CatchPromise(FROM_HERE, p0).WithReject(ArgumentPassingType::kMove);
- });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(DetectCatchCallbackDoubleMoveHazardInChain)) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * T T
- * | |
- * \| |/
- * P1 P2
- * T T
- * | |
- * \| |/
- * P3 P4
- * C C
- *
- * We need to make sure P3 & P4's reject callback don't both use move
- * semantics since they share a common ancestor with no intermediate catches.
- */
- scoped_refptr<AbstractPromise> p0 =
- ThenPromise(FROM_HERE, nullptr).With(CallbackResultType::kCanReject);
-
- scoped_refptr<AbstractPromise> p1 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p0);
-
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, p1).WithReject(ArgumentPassingType::kMove);
-
- EXPECT_PROMISE_DCHECK_FAIL({
- scoped_refptr<AbstractPromise> p4 =
- CatchPromise(FROM_HERE, p2).WithReject(ArgumentPassingType::kMove);
- });
-}
-
-TEST_F(
- AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(
- DetectCatchCallbackDoubleMoveHazardInChainIntermediateThensCanReject)) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * T T
- * | |
- * \| |/
- * P1 P2
- * T T
- * | |
- * \| |/
- * P3 P4
- * C C
- *
- * We need to make sure P3 & P4's reject callback don't both use move
- * semantics since they share a common ancestor with no intermediate catches.
- */
- scoped_refptr<AbstractPromise> p0 =
- ThenPromise(FROM_HERE, nullptr).With(CallbackResultType::kCanReject);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0).With(CallbackResultType::kCanReject);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0).With(CallbackResultType::kCanReject);
-
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, p1).WithReject(ArgumentPassingType::kMove);
-
- EXPECT_PROMISE_DCHECK_FAIL({
- scoped_refptr<AbstractPromise> p4 =
- CatchPromise(FROM_HERE, p2).WithReject(ArgumentPassingType::kMove);
- });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(DetectMixedCatchCallbackMoveAndNonMoveHazard)) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * T T
- * | |
- * \| |/
- * P1 P2
- * T T
- * | |
- * \| |/
- * P3 P4
- * C C
- *
- * We can't guarantee the order in which P3 and P4's reject callbacks run so
- * we need to need to catch the case where move and non-move semantics are
- * mixed.
- */
- scoped_refptr<AbstractPromise> p0 =
- ThenPromise(FROM_HERE, nullptr).With(CallbackResultType::kCanReject);
-
- scoped_refptr<AbstractPromise> p1 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p0);
-
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, p1).WithReject(ArgumentPassingType::kMove);
-
- EXPECT_PROMISE_DCHECK_FAIL(
- { scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p2); });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(DetectThenCallbackDoubleMoveHazardInChain)) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * C C
- * | |
- * \| |/
- * P1 P2
- * C C
- * | |
- * \| |/
- * P3 P4
- * T T
- *
- * We need to make sure P3 & P4's resolve callback don't both use move
- * semantics since they share a common ancestor with no intermediate then's.
- */
- scoped_refptr<AbstractPromise> p0 = ThenPromise(FROM_HERE, nullptr);
- scoped_refptr<AbstractPromise> p1 = CatchPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p2 = CatchPromise(FROM_HERE, p0);
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1).WithResolve(ArgumentPassingType::kMove);
-
- EXPECT_PROMISE_DCHECK_FAIL({
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p2).WithResolve(ArgumentPassingType::kMove);
- });
-}
-
-TEST_F(AbstractPromiseTest, PROMISE_API_DCHECK_TEST(SimpleMissingCatch)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p1| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p1 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest, PROMISE_API_DCHECK_TEST(MissingCatch)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- // The missing catch here will get noticed.
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p2| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p2 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest, MissingCatchNotRequired) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(RejectPolicy::kCatchNotRequired)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- // The missing catch here will gets ignored.
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
-
- OnResolved(p0);
-
- RunLoop().RunUntilIdle();
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(MissingCatchFromCurriedPromise)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, nullptr)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0)
- .With(BindOnce(
- [](scoped_refptr<AbstractPromise> p1, AbstractPromise* p) {
- // Resolve with a promise that can and does reject.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p1));
- p->emplace(std::move(p1));
- },
- std::move(p1)));
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p2| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p2 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(MissingCatchFromCurriedPromiseWithDependent)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, nullptr)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0)
- .With(BindOnce(
- [&](scoped_refptr<AbstractPromise> p1, AbstractPromise* p) {
- // Resolve with a promise that can and does reject.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p1));
- p->emplace(std::move(p1));
- },
- std::move(p1)));
-
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p3| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p3 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(
- MissingCatchFromCurriedPromiseWithDependentAddedAfterExecution)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, nullptr)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0)
- .With(BindOnce(
- [&](scoped_refptr<AbstractPromise> p1, AbstractPromise* p) {
- // Resolve with a promise that can and does reject.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p1));
- p->emplace(std::move(p1));
- },
- std::move(p1)));
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p3| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p3 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest, PROMISE_API_DCHECK_TEST(MissingCatchLongChain)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p3);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p4| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p4 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(
- ThenAddedToSettledPromiseWithMissingCatchAndSeveralDependents)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p2);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- scoped_refptr<AbstractPromise> p5 = ThenPromise(FROM_HERE, p2);
-
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p5| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p5 = nullptr; });
-
- p3->IgnoreUncaughtCatchForTesting();
- p4->IgnoreUncaughtCatchForTesting();
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(ThenAddedAfterChainExecutionWithMissingCatch)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- // The missing catch here will get noticed.
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p3);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p4| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p4 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest, CatchAddedAfterChainExecution) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p3);
-
- // We shouldn't get a DCHECK failure because |p4| catches the rejection
- // from |p1|.
- RunLoop().RunUntilIdle();
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(MultipleThensAddedAfterChainExecution)) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
-
- // |p5| - |p7| should still inherit catch responsibility despite this.
- scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p3);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- // The missing catches will get noticed.
- scoped_refptr<AbstractPromise> p5 = ThenPromise(FROM_HERE, p3);
- scoped_refptr<AbstractPromise> p6 = ThenPromise(FROM_HERE, p3);
- scoped_refptr<AbstractPromise> p7 = ThenPromise(FROM_HERE, p3);
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p5|, |p6| or |p7| are deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p5 = nullptr; });
- EXPECT_PROMISE_DCHECK_FAIL({ p6 = nullptr; });
- EXPECT_PROMISE_DCHECK_FAIL({ p7 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest, MultipleDependentsAddedAfterChainExecution) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p3);
- scoped_refptr<AbstractPromise> p5 = CatchPromise(FROM_HERE, p4);
- scoped_refptr<AbstractPromise> p6 = ThenPromise(FROM_HERE, p3);
- scoped_refptr<AbstractPromise> p7 = CatchPromise(FROM_HERE, p6);
-
- // We shouldn't get a DCHECK failure because |p6| and |p7| catch the rejection
- // from |p1|.
- RunLoop().RunUntilIdle();
-}
-
-TEST_F(AbstractPromiseTest, CatchAfterLongChain) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, p0)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p3 = ThenPromise(FROM_HERE, p2);
- scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p3);
-
- OnResolved(p0);
-
- RunLoop().RunUntilIdle();
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(MissingCatchOneSideOfBranchedExecutionChain)) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * T T
- * | |
- * \| |/
- * P1 P2
- * T T
- * | |
- * \| |/
- * P3 P4
- * C T
- *
- * The missing catch for P4 should get noticed.
- */
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
-
- scoped_refptr<AbstractPromise> p1 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p3 = CatchPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p4 = ThenPromise(FROM_HERE, p2);
-
- OnRejected(p0);
-
- RunLoop().RunUntilIdle();
-
- // An error should be reported when |p4| is deleted.
- EXPECT_PROMISE_DCHECK_FAIL({ p4 = nullptr; });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(CantResolveIfPromiseDeclaredAsNonResolving)) {
- scoped_refptr<AbstractPromise> p = DoNothingPromiseBuilder(FROM_HERE);
-
- EXPECT_PROMISE_DCHECK_FAIL({ AbstractPromiseTest::OnResolved(p); });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(CantRejectIfPromiseDeclaredAsNonRejecting)) {
- scoped_refptr<AbstractPromise> p = DoNothingPromiseBuilder(FROM_HERE);
-
- EXPECT_PROMISE_DCHECK_FAIL({ AbstractPromiseTest::OnRejected(p); });
-}
-
-TEST_F(AbstractPromiseTest,
- PROMISE_API_DCHECK_TEST(DoubleMoveDoNothingPromise)) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<int>(42));
- }));
-
- EXPECT_PROMISE_DCHECK_FAIL({
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1)
- .WithResolve(ArgumentPassingType::kMove)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<int>(42));
- }));
- });
-}
-
-TEST_F(AbstractPromiseTest, CatchBothSidesOfBranchedExecutionChain) {
- /*
- * Key: T = Then, C = Catch
- *
- * P0
- * T T
- * | |
- * \| |/
- * P1 P2
- * T T
- * | |
- * \| |/
- * P3 P4
- * C C
- *
- * This should execute without DCHECKS.
- */
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
-
- scoped_refptr<AbstractPromise> p1 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p0);
- scoped_refptr<AbstractPromise> p3 = CatchPromise(FROM_HERE, p1);
- scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p2);
-
- OnRejected(p0);
-
- RunLoop().RunUntilIdle();
-}
-
-TEST_F(AbstractPromiseTest, ResolvedCurriedPromise) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- std::vector<int> run_order;
-
- // Promise |p3| will be resolved with.
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, nullptr)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(2);
- p->emplace(Resolved<void>());
- }));
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(3);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p2));
- p->emplace(std::move(p2));
-
- EXPECT_TRUE(p3->IsResolvedWithPromise());
- }));
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(4);
- p->emplace(Resolved<void>());
- }));
-
- OnResolved(p1);
- RunLoop().RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(3, 2, 4));
-}
-
-TEST_F(AbstractPromiseTest, UnresolvedCurriedPromise) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- std::vector<int> run_order;
-
- // Promise |p3| will be resolved with.
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(3);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p2));
- p->emplace(p2);
-
- EXPECT_TRUE(p3->IsResolvedWithPromise());
- }));
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(4);
- p->emplace(Resolved<void>());
- }));
-
- OnResolved(p1);
- RunLoop().RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(3));
-
- OnResolved(p2);
- RunLoop().RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(3, 4));
-}
-
-TEST_F(AbstractPromiseTest, NeverResolvedCurriedPromise) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- std::vector<int> run_order;
-
- // Promise |p3| will be resolved with.
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(3);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p2));
- p->emplace(p2);
-
- EXPECT_TRUE(p3->IsResolvedWithPromise());
- }));
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(4);
- p->emplace(Resolved<void>());
- }));
-
- OnResolved(p1);
- RunLoop().RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(3));
-
- // This shouldn't leak.
-}
-
-TEST_F(AbstractPromiseTest, CanceledCurriedPromise) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- // Promise |p3| will be resolved with.
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- OnCanceled(p2);
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p2));
- EXPECT_TRUE(p2->IsCanceled());
- p->emplace(p2);
- }));
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3)
- .With(BindLambdaForTesting(
- [&](AbstractPromise* p) { FAIL() << "Should not get here"; }));
-
- OnResolved(p1);
- RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(p3->IsCanceled());
- EXPECT_TRUE(p4->IsCanceled());
-}
-
-TEST_F(AbstractPromiseTest, CurriedPromiseChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- std::vector<int> run_order;
-
- // Promise |p3| will be resolved with.
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, nullptr)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(2);
- p->emplace(Resolved<void>());
- }));
-
- // Promise |p4| will be resolved with.
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, nullptr)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(3);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p2));
- p->emplace(std::move(p2));
- }));
-
- // Promise |p5| will be resolved with.
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, nullptr)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(4);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p3));
- p->emplace(std::move(p3));
- }));
-
- scoped_refptr<AbstractPromise> p5 =
- ThenPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(5);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p4));
- p->emplace(std::move(p4));
- }));
-
- scoped_refptr<AbstractPromise> p6 =
- ThenPromise(FROM_HERE, p3)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(6);
- p->emplace(Resolved<void>());
- }));
-
- OnResolved(p1);
- RunLoop().RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(5, 4, 3, 2, 6));
-}
-
-TEST_F(AbstractPromiseTest, RejectedCurriedPromiseChain) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true);
- std::vector<int> run_order;
-
- // Promise |p3| will be resolved with.
- scoped_refptr<AbstractPromise> p2 =
- CatchPromise(FROM_HERE, nullptr)
- .With(CallbackResultType::kCanReject)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(2);
- p->emplace(Rejected<void>());
- }));
-
- // Promise |p4| will be resolved with.
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, nullptr)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(3);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p2));
- p->emplace(std::move(p2));
- }));
-
- // Promise |p5| will be resolved with.
- scoped_refptr<AbstractPromise> p4 =
- CatchPromise(FROM_HERE, nullptr)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(4);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p3));
- p->emplace(std::move(p3));
- }));
-
- scoped_refptr<AbstractPromise> p5 =
- CatchPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(5);
- // Resolve with a promise.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p4));
- p->emplace(std::move(p4));
- }));
-
- scoped_refptr<AbstractPromise> p6 =
- CatchPromise(FROM_HERE, p3)
- .With(RejectPolicy::kCatchNotRequired)
- .With(CallbackResultType::kCanReject)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- run_order.push_back(6);
- p->emplace(Rejected<void>());
- }));
-
- OnRejected(p1);
- RunLoop().RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(5, 4, 3, 2, 6));
-}
-
-TEST_F(AbstractPromiseTest, CurriedPromiseChainType2) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(p1);
- }));
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p2)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(p2);
- }));
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(p3);
- }));
-
- OnResolved(p1);
- RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(p4->IsResolvedForTesting());
- EXPECT_EQ(p1.get(),
- GetCurriedPromise(GetCurriedPromise(GetCurriedPromise(p4.get()))));
-}
-
-TEST_F(AbstractPromiseTest, CurriedPromiseMoveArg) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, nullptr)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- }))
- .WithResolve(ArgumentPassingType::kMove);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0)
- .With(BindOnce(
- [](scoped_refptr<AbstractPromise> p1, AbstractPromise* p) {
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p1));
- p->emplace(std::move(p1));
- },
- std::move(p1)))
- .WithResolve(ArgumentPassingType::kMove);
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
-}
-
-TEST_F(AbstractPromiseTest, CatchCurriedPromise) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- ThenPromise(FROM_HERE, nullptr)
- .With(CallbackResultType::kCanReject)
- .With(BindOnce([](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0)
- .With(BindOnce(
- [](scoped_refptr<AbstractPromise> p1, AbstractPromise* p) {
- // Resolve with a promise that can and does reject.
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromise::Execute, p1));
- p->emplace(std::move(p1));
- },
- std::move(p1)));
-
- scoped_refptr<AbstractPromise> p3 = CatchPromise(FROM_HERE, p2);
-
- OnResolved(p0);
- EXPECT_FALSE(p3->IsResolvedForTesting());
-
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p3->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, ManuallyResolveWithNonSettledCurriedPromise) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p1);
-
- p1->emplace(p0);
- OnResolved(p1);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p1->IsResolvedForTesting());
- EXPECT_FALSE(p2->IsResolvedForTesting());
-
- OnResolved(p0);
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(p2->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, ExecuteCalledOnceForLateResolvedCurriedPromise) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<TestSimpleTaskRunner> task_runner =
- MakeRefCounted<TestSimpleTaskRunner>();
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(p1);
- }))
- .With(task_runner);
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p1).With(task_runner);
-
- OnResolved(p0);
- // |p2| should run but not |p3|.
- EXPECT_EQ(1u, CountTasksRunUntilIdle(task_runner));
- EXPECT_FALSE(p3->IsResolvedForTesting());
-
- OnResolved(p1);
- // |p3| should run.
- EXPECT_EQ(1u, CountTasksRunUntilIdle(task_runner));
- EXPECT_TRUE(p3->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, ExecuteCalledOnceForLateRejectedCurriedPromise) {
- scoped_refptr<AbstractPromise> p0 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
-
- scoped_refptr<TestSimpleTaskRunner> task_runner =
- MakeRefCounted<TestSimpleTaskRunner>();
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p0)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(p1);
- }))
- .With(task_runner);
-
- scoped_refptr<AbstractPromise> p3 =
- CatchPromise(FROM_HERE, p1).With(task_runner);
-
- OnResolved(p0);
- // |p2| should run but not |p3|.
- EXPECT_EQ(1u, CountTasksRunUntilIdle(task_runner));
- EXPECT_FALSE(p3->IsResolvedForTesting());
-
- OnRejected(p1);
- // |p3| should run.
- EXPECT_EQ(1u, CountTasksRunUntilIdle(task_runner));
- EXPECT_TRUE(p3->IsResolvedForTesting());
-}
-
-TEST_F(AbstractPromiseTest, ThreadHopping) {
- std::unique_ptr<Thread> thread_a(new Thread("AbstractPromiseTest_Thread_A"));
- std::unique_ptr<Thread> thread_b(new Thread("AbstractPromiseTest_Thread_B"));
- std::unique_ptr<Thread> thread_c(new Thread("AbstractPromiseTest_Thread_C"));
- thread_a->Start();
- thread_b->Start();
- thread_c->Start();
- RunLoop run_loop;
-
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- scoped_refptr<AbstractPromise> p2 =
- ThenPromise(FROM_HERE, p1)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- CHECK(thread_a->task_runner()->BelongsToCurrentThread());
- }))
- .With(thread_a->task_runner());
-
- scoped_refptr<AbstractPromise> p3 =
- ThenPromise(FROM_HERE, p2)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- CHECK(thread_b->task_runner()->BelongsToCurrentThread());
- }))
- .With(thread_b->task_runner());
-
- scoped_refptr<AbstractPromise> p4 =
- ThenPromise(FROM_HERE, p3)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- CHECK(thread_c->task_runner()->BelongsToCurrentThread());
- }))
- .With(thread_c->task_runner());
-
- scoped_refptr<SingleThreadTaskRunner> main_thread =
- ThreadTaskRunnerHandle::Get();
- scoped_refptr<AbstractPromise> p5 =
- ThenPromise(FROM_HERE, p4)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- run_loop.Quit();
- CHECK(main_thread->BelongsToCurrentThread());
- }))
- .With(main_thread);
-
- OnResolved(p1);
-
- EXPECT_FALSE(p5->IsResolvedForTesting());
- run_loop.Run();
- EXPECT_TRUE(p2->IsResolvedForTesting());
- EXPECT_TRUE(p3->IsResolvedForTesting());
- EXPECT_TRUE(p4->IsResolvedForTesting());
- EXPECT_TRUE(p5->IsResolvedForTesting());
-
- thread_a->Stop();
- thread_b->Stop();
- thread_c->Stop();
-}
-
-TEST_F(AbstractPromiseTest, MutipleThreadsAddingDependants) {
- constexpr int num_threads = 4;
- constexpr int num_promises = 100000;
-
- std::unique_ptr<Thread> thread[num_threads];
- for (int i = 0; i < num_threads; i++) {
- thread[i] = std::make_unique<Thread>("Test thread");
- thread[i]->Start();
- }
-
- scoped_refptr<AbstractPromise> root =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- RunLoop run_loop;
- std::atomic<int> pending_count(num_promises);
-
- // After being called |num_promises| times |decrement_cb| will quit |run_loop|
- auto decrement_cb = BindLambdaForTesting([&](AbstractPromise* p) {
- int count = pending_count.fetch_sub(1, std::memory_order_acq_rel);
- if (count == 1)
- run_loop.Quit();
- OnResolved(p);
- });
-
- // Post a bunch of tasks on multiple threads that create Then promises
- // dependent on |root| which call |decrement_cb| when resolved.
- for (int i = 0; i < num_promises; i++) {
- thread[i % num_threads]->task_runner()->PostTask(
- FROM_HERE, BindLambdaForTesting([&]() {
- scoped_refptr<AbstractPromise> p =
- ThenPromise(FROM_HERE, root).With(decrement_cb);
- }));
-
- // Mid way through post a task to resolve |root|.
- if (i == num_promises / 2) {
- thread[i % num_threads]->task_runner()->PostTask(
- FROM_HERE, BindOnce(&AbstractPromiseTest::OnResolved, root));
- }
- }
-
- // This should exit cleanly without any TSan errors.
- run_loop.Run();
-
- for (int i = 0; i < num_threads; i++) {
- thread[i]->Stop();
- }
-}
-
-TEST_F(AbstractPromiseTest, SingleRejectPrerequisitePolicyALLModified) {
- // Regression test to ensure cross thread rejection works as intended. Loop
- // increaces chances of catching any bugs.
- for (size_t i = 0; i < 1000; ++i) {
- scoped_refptr<AbstractPromise> p1 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p2 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p3 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
- scoped_refptr<AbstractPromise> p4 =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetCanResolve(
- false);
-
- std::vector<internal::DependentList::Node> prerequisite_list(4);
- prerequisite_list[0].SetPrerequisite(p1.get());
- prerequisite_list[1].SetPrerequisite(p2.get());
- prerequisite_list[2].SetPrerequisite(p3.get());
- prerequisite_list[3].SetPrerequisite(p4.get());
-
- scoped_refptr<AbstractPromise> all_promise =
- AllPromise(FROM_HERE, std::move(prerequisite_list))
- .With(CallbackResultType::kCanResolveOrReject)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(Rejected<void>());
- }));
-
- base::PostTask(FROM_HERE, {base::ThreadPool()},
- base::BindOnce(
- [](scoped_refptr<AbstractPromise> p2) {
- p2->emplace(Rejected<void>());
- },
- p2));
-
- RunLoop run_loop;
- scoped_refptr<AbstractPromise> p5 =
- CatchPromise(FROM_HERE, all_promise)
- .With(BindLambdaForTesting([&](AbstractPromise* p) {
- p->emplace(Resolved<void>());
- run_loop.Quit();
- }));
-
- OnRejected(p3);
- run_loop.Run();
- EXPECT_TRUE(all_promise->IsRejected());
- EXPECT_TRUE(p5->IsResolved());
- task_environment_.RunUntilIdle();
- }
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/all_container_executor.h b/task/promise/all_container_executor.h
deleted file mode 100644
index eb2a924..0000000
--- a/task/promise/all_container_executor.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_ALL_CONTAINER_EXECUTOR_H_
-#define BASE_TASK_PROMISE_ALL_CONTAINER_EXECUTOR_H_
-
-#include <tuple>
-
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/helpers.h"
-#include "base/task/promise/no_op_promise_executor.h"
-
-namespace base {
-namespace internal {
-
-// For Promises::All(std::vector<Promise<T>& promises)
-template <typename ResolveType, typename RejectType>
-class AllContainerPromiseExecutor {
- public:
- bool IsCancelled() const { return false; }
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- PromiseExecutor::PrerequisitePolicy::kAll;
-
- struct VoidResolveType {};
- struct NonVoidResolveType {};
-
- using ResolveTypeTag = std::conditional_t<std::is_void<ResolveType>::value,
- VoidResolveType,
- NonVoidResolveType>;
-
- void Execute(AbstractPromise* promise) {
- // All is rejected if any prerequisites are rejected.
- AbstractPromise* first_settled = promise->GetFirstSettledPrerequisite();
- if (first_settled && first_settled->IsRejected()) {
- AllPromiseRejectHelper<Rejected<RejectType>>::Reject(promise,
- first_settled);
- return;
- }
-
- ResolveInternal(promise, ResolveTypeTag());
- }
-
-#if DCHECK_IS_ON()
- PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const {
- return UseMoveSemantics<ResolveType>::argument_passing_type;
- }
-
- PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const {
- return UseMoveSemantics<RejectType>::argument_passing_type;
- }
-
- bool CanResolve() const {
- return !std::is_same<ResolveType, NoResolve>::value;
- }
-
- bool CanReject() const { return !std::is_same<RejectType, NoReject>::value; }
-#endif
-
- private:
- // For containers of Promise<void> there is no point resolving with
- // std::vector<Void>.
- void ResolveInternal(AbstractPromise* promise, VoidResolveType) {
- promise->emplace(Resolved<void>());
- }
-
- void ResolveInternal(AbstractPromise* promise, NonVoidResolveType) {
- using NonVoidResolveType = ToNonVoidT<ResolveType>;
- Resolved<std::vector<NonVoidResolveType>> result;
-
- const std::vector<DependentList::Node>* prerequisite_list =
- promise->prerequisite_list();
- DCHECK(prerequisite_list);
- result.value.reserve(prerequisite_list->size());
-
- for (const auto& node : *prerequisite_list) {
- DCHECK(node.prerequisite()->IsResolved());
- result.value.push_back(
- ArgMoveSemanticsHelper<
- NonVoidResolveType,
- Resolved<NonVoidResolveType>>::Get(node.prerequisite()));
- }
-
- promise->emplace(std::move(result));
- }
-};
-
-template <typename Container, typename ContainerT>
-struct AllContainerHelper;
-
-template <typename Container, typename ResolveType, typename RejectType>
-struct AllContainerHelper<Container, Promise<ResolveType, RejectType>> {
- using PromiseResolve = std::vector<ToNonVoidT<ResolveType>>;
-
- // As an optimization we don't return std::vector<ResolveType> for void
- // ResolveType.
- using PromiseType = std::conditional_t<std::is_void<ResolveType>::value,
- Promise<void, RejectType>,
- Promise<PromiseResolve, RejectType>>;
-
- static PromiseType All(const Location& from_here, const Container& promises) {
- size_t i = 0;
- std::vector<DependentList::Node> prerequisite_list(promises.size());
- // TODO(alexclarke): Move construction of this list and AbstractPromise out
- // of line to reduce template bloat.
- for (auto& promise : promises) {
- prerequisite_list[i++].SetPrerequisite(promise.abstract_promise_.get());
- }
-
- internal::PromiseExecutor::Data executor_data(
- (in_place_type_t<
- AllContainerPromiseExecutor<ResolveType, RejectType>>()));
-
- return PromiseType(AbstractPromise::Create(
- nullptr, from_here,
- std::make_unique<AbstractPromise::AdjacencyList>(
- std::move(prerequisite_list)),
- RejectPolicy::kMustCatchRejection, DependentList::ConstructUnresolved(),
- std::move(executor_data)));
- }
-};
-
-// TODO(alexclarke): Maybe specalize to support containers of variants.
-// E.g. Promises::All(std::vector<Variant<Promise<T>...>>& promises)
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_ALL_CONTAINER_EXECUTOR_H_
diff --git a/task/promise/all_tuple_executor.h b/task/promise/all_tuple_executor.h
deleted file mode 100644
index bc5a265..0000000
--- a/task/promise/all_tuple_executor.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_ALL_TUPLE_EXECUTOR_H_
-#define BASE_TASK_PROMISE_ALL_TUPLE_EXECUTOR_H_
-
-#include <tuple>
-
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/helpers.h"
-
-namespace base {
-namespace internal {
-
-template <typename Tuple,
- typename Indices =
- std::make_index_sequence<std::tuple_size<Tuple>::value>>
-struct TupleConstructor;
-
-template <typename Tuple, size_t... Indices>
-struct TupleConstructor<Tuple, std::index_sequence<Indices...>> {
- template <typename ArgType>
- static auto GetResolvedValueFromPromise(AbstractPromise* arg) {
- using ResolvedType = base::Resolved<UndoToNonVoidT<ArgType>>;
- return ArgMoveSemanticsHelper<ArgType, ResolvedType>::Get(arg);
- }
-
- // Resolves |result| with a std::tuple of the promise results of the dependent
- // promises.
- static void ConstructTuple(
- const std::vector<DependentList::Node>* prerequisite_list,
- AbstractPromise* result) {
- DCHECK_EQ(sizeof...(Indices), prerequisite_list->size());
- result->emplace(
- in_place_type_t<Resolved<Tuple>>(),
- GetResolvedValueFromPromise<std::tuple_element_t<Indices, Tuple>>(
- (*prerequisite_list)[Indices].prerequisite())...);
- }
-};
-
-template <typename T>
-struct TupleCanResolveHelper;
-
-template <typename... Ts>
-struct TupleCanResolveHelper<std::tuple<Ts...>> {
- static constexpr bool value =
- any_of({!std::is_same<Ts, NoResolve>::value...});
-};
-
-// For Promises::All(Promise<Ts>... promises)
-template <typename ResolveTuple, typename RejectType>
-class AllTuplePromiseExecutor {
- public:
- using RejectT = Rejected<RejectType>;
-
- bool IsCancelled() const { return false; }
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- PromiseExecutor::PrerequisitePolicy::kAll;
-
- void Execute(AbstractPromise* promise) {
- // All is rejected if any prerequisites are rejected.
- AbstractPromise* first_settled = promise->GetFirstSettledPrerequisite();
- if (first_settled && first_settled->IsRejected()) {
- AllPromiseRejectHelper<RejectT>::Reject(promise, first_settled);
- return;
- }
-
- const std::vector<DependentList::Node>* prerequisite_list =
- promise->prerequisite_list();
- DCHECK(prerequisite_list);
- TupleConstructor<ResolveTuple>::ConstructTuple(prerequisite_list, promise);
- }
-
-#if DCHECK_IS_ON()
- PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const {
- return UseMoveSemantics<ResolveTuple>::argument_passing_type;
- }
-
- PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const {
- return UseMoveSemantics<RejectType>::argument_passing_type;
- }
-
- bool CanResolve() const { return TupleCanResolveHelper<ResolveTuple>::value; }
-
- bool CanReject() const { return !std::is_same<RejectType, NoReject>::value; }
-#endif
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_ALL_TUPLE_EXECUTOR_H_
diff --git a/task/promise/dependent_list.cc b/task/promise/dependent_list.cc
deleted file mode 100644
index 6cbbf34..0000000
--- a/task/promise/dependent_list.cc
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/dependent_list.h"
-
-#include <algorithm>
-#include <atomic>
-#include <cstdint>
-
-#include "base/logging.h"
-#include "base/task/promise/abstract_promise.h"
-
-namespace base {
-namespace internal {
-
-// static
-DependentList::Node* DependentList::ReverseList(DependentList::Node* list) {
- DependentList::Node* prev = nullptr;
- while (list) {
- DependentList::Node* next = list->next_;
- list->next_ = prev;
- prev = list;
- list = next;
- }
- return prev;
-}
-
-// static
-void DependentList::DispatchAll(DependentList::Node* head,
- DependentList::Visitor* visitor,
- bool retain_prerequsites) {
- head = ReverseList(head);
- DependentList::Node* next = nullptr;
- while (head) {
- next = head->next_;
- if (retain_prerequsites)
- head->RetainSettledPrerequisite();
- // |visitor| might delete the node, so no access to node past this
- // call!
- visitor->Visit(std::move(head->dependent_));
- head = next;
- }
-}
-
-DependentList::Visitor::~Visitor() = default;
-
-DependentList::Node::Node() = default;
-
-DependentList::Node::Node(Node&& other) noexcept {
- prerequisite_ = other.prerequisite_.load(std::memory_order_relaxed);
- other.prerequisite_ = 0;
- dependent_ = std::move(other.dependent_);
- DCHECK_EQ(other.next_, nullptr);
-}
-
-DependentList::Node::Node(AbstractPromise* prerequisite,
- scoped_refptr<AbstractPromise> dependent)
- : prerequisite_(reinterpret_cast<intptr_t>(prerequisite)),
- dependent_(std::move(dependent)) {}
-
-DependentList::Node::~Node() {
- ClearPrerequisite();
-}
-
-DependentList::DependentList(State initial_state)
- : data_(CreateData(nullptr,
- initial_state,
- initial_state == State::kUnresolved ? kAllowInserts
- : kBlockInserts)) {}
-
-DependentList::DependentList(ConstructUnresolved)
- : DependentList(State::kUnresolved) {}
-
-DependentList::DependentList(ConstructResolved)
- : DependentList(State::kResolved) {}
-
-DependentList::DependentList(ConstructRejected)
- : DependentList(State::kRejected) {}
-
-DependentList::~DependentList() = default;
-
-void DependentList::Node::Reset(AbstractPromise* prerequisite,
- scoped_refptr<AbstractPromise> dependent) {
- SetPrerequisite(prerequisite);
- dependent_ = std::move(dependent);
- next_ = nullptr;
-}
-
-void DependentList::Node::SetPrerequisite(AbstractPromise* prerequisite) {
- DCHECK(prerequisite);
- intptr_t prev_value = prerequisite_.exchange(
- reinterpret_cast<intptr_t>(prerequisite), std::memory_order_acq_rel);
-
- if (prev_value & kIsRetained)
- reinterpret_cast<AbstractPromise*>(prev_value & ~kIsRetained)->Release();
-}
-
-AbstractPromise* DependentList::Node::prerequisite() const {
- return reinterpret_cast<AbstractPromise*>(
- prerequisite_.load(std::memory_order_acquire) & ~kIsRetained);
-}
-
-void DependentList::Node::RetainSettledPrerequisite() {
- intptr_t prerequisite = prerequisite_.load(std::memory_order_acquire);
- DCHECK((prerequisite & kIsRetained) == 0) << "May only be called once";
- if (!prerequisite)
- return;
-
- // Mark as retained, note we could have another thread trying to call
- // ClearPrerequisite.
- if (prerequisite_.compare_exchange_strong(
- prerequisite, prerequisite | kIsRetained, std::memory_order_release,
- std::memory_order_acquire)) {
- reinterpret_cast<AbstractPromise*>(prerequisite)->AddRef();
- }
-}
-
-void DependentList::Node::ClearPrerequisite() {
- intptr_t prerequisite = prerequisite_.exchange(0, std::memory_order_acq_rel);
- if (prerequisite & kIsRetained)
- reinterpret_cast<AbstractPromise*>(prerequisite & ~kIsRetained)->Release();
-}
-
-DependentList::InsertResult DependentList::Insert(Node* node) {
- DCHECK(!node->next_);
-
- // std::memory_order_acquire for hapens-after relation with
- // SettleAndDispatchAllDependents completing and thus this this call returning
- // an error.
- uintptr_t prev_data = data_.load(std::memory_order_acquire);
- bool did_insert = false;
- while (IsAllowingInserts(prev_data) && !did_insert) {
- node->next_ = ExtractHead(prev_data);
-
- // On success std::memory_order_release so that all memory operations become
- // visible in SettleAndDispatchAllDependents when iterating the list.
- // On failure std::memory_order_acquire for happens-after relation with
- // SettleAndDispatchAllDependents completing and thus this this call
- // returning an error.
- //
- // Note: ABA is not an issue here as we do not care that head_ might now be
- // pointing to a different node (but with same address) we only need to
- // guarantee that node->next points to the current head (which is now the
- // new node but with the same address so node->next is still valid).
- if (data_.compare_exchange_weak(
- prev_data, CreateData(node, ExtractState(prev_data), kAllowInserts),
- std::memory_order_seq_cst, std::memory_order_seq_cst)) {
- did_insert = true;
- } else {
- // Cleanup in case the loop terminates
- node->next_ = nullptr;
- }
- }
-
- if (did_insert) {
- return InsertResult::SUCCESS;
- }
-
- switch (ExtractState(prev_data)) {
- case State::kResolved:
- return InsertResult::FAIL_PROMISE_RESOLVED;
-
- case State::kRejected:
- return InsertResult::FAIL_PROMISE_REJECTED;
-
- case State::kCanceled:
- return InsertResult::FAIL_PROMISE_CANCELED;
-
- case State::kUnresolved:
- // We must have inserted, as inserts must be allowed if in state
- // kUnresolved
- NOTREACHED();
- return InsertResult::SUCCESS;
- }
-}
-
-bool DependentList::SettleAndDispatchAllDependents(const State settled_state,
- Visitor* visitor) {
- DCHECK_NE(settled_state, State::kUnresolved);
-
- // Whether this invocation won the settlement race. If so, it will now keep
- // dispatching all nodes in as many attempts as it takes to win the race
- // against Insert()'s.
- bool did_set_state = false;
-
- // This load, and the ones in for compare_exchange_weak failures can be
- // std::memory_order_relaxed as we do not make any ordering guarantee when
- // this method returns false.
- uintptr_t prev_data = data_.load(std::memory_order_seq_cst);
- while (true) {
- if (!did_set_state && ExtractState(prev_data) != State::kUnresolved) {
- // Somebody else set the state.
- return false;
- }
-
- if (!IsListEmpty(prev_data)) {
- // List is not empty and we might have set the state previously
- // We need to:
- // * Settle the state (or leave as is if we already did).
- // * allow_inserts. As we are going to dispatch the nodes we need to
- // make sure that other threads can still insert to the list
- // (instead of just resolving themselves) to preserve dispatch order.
- // * Take ownership of all nodes currently in the queue, i.e. set the
- // head to nullptr, marking it empty
- DCHECK_EQ(ExtractState(prev_data),
- did_set_state ? settled_state : State::kUnresolved);
- DCHECK(IsAllowingInserts(prev_data));
- uintptr_t new_data = CreateData(nullptr, settled_state, kAllowInserts);
-
- // On success std::memory_order_acquire for happens-after relation with
- // with the last successful Insert().
- if (!data_.compare_exchange_weak(prev_data, new_data,
- std::memory_order_seq_cst,
- std::memory_order_relaxed)) {
- continue;
- }
- did_set_state = true;
- // We don't want to retain prerequisites when cancelling.
- DispatchAll(ExtractHead(prev_data), visitor,
- settled_state != State::kCanceled);
- prev_data = new_data;
- }
-
- // List is empty and we might have set the state previously, so we
- // can settle the state (or leave as is if we already did) and freeze
- // the list.
- DCHECK(IsListEmpty(prev_data));
- DCHECK_EQ(ExtractState(prev_data),
- did_set_state ? settled_state : State::kUnresolved);
- // On success std::memory_order_release for happens-before relation with
- // Insert returning an error.
- if (data_.compare_exchange_weak(
- prev_data, CreateData(nullptr, settled_state, kBlockInserts),
- std::memory_order_seq_cst, std::memory_order_relaxed)) {
- // Inserts no longer allowed, state settled and list is empty. We are
- // done!
- return true;
- }
- }
-}
-
-// The following methods do not make any ordering guarantees, false return
-// values are always stale. A true return value just means that
-// SettleAndDispatchAllDependents was called but it gives no guarantees as
-// whether any of the nodes was dispatched or the call finished. Thus
-// std::memory_order_relaxed.
-
-bool DependentList::IsSettled() const {
- return ExtractState(data_.load(std::memory_order_seq_cst)) !=
- State::kUnresolved;
-}
-
-bool DependentList::IsResolved() const {
- DCHECK(IsSettled()) << "This check is racy";
- return ExtractState(data_.load(std::memory_order_seq_cst)) ==
- State::kResolved;
-}
-
-bool DependentList::IsRejected() const {
- DCHECK(IsSettled()) << "This check is racy";
- return ExtractState(data_.load(std::memory_order_seq_cst)) ==
- State::kRejected;
-}
-
-bool DependentList::IsCanceled() const {
- return ExtractState(data_.load(std::memory_order_seq_cst)) ==
- State::kCanceled;
-}
-
-bool DependentList::IsResolvedForTesting() const {
- return ExtractState(data_.load(std::memory_order_seq_cst)) ==
- State::kResolved;
-}
-
-bool DependentList::IsRejectedForTesting() const {
- return ExtractState(data_.load(std::memory_order_seq_cst)) ==
- State::kRejected;
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/dependent_list.h b/task/promise/dependent_list.h
deleted file mode 100644
index 3245c1c..0000000
--- a/task/promise/dependent_list.h
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_DEPENDENT_LIST_H_
-#define BASE_TASK_PROMISE_DEPENDENT_LIST_H_
-
-#include <atomic>
-#include <cstdint>
-#include <type_traits>
-
-#include "base/base_export.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-
-namespace base {
-namespace internal {
-
-// Returns 2^N where N is the smallest N possible so that 2^N > value.
-constexpr uintptr_t NextPowerOfTwo(uintptr_t value) {
- // Keep setting 1's to the right of the first one until there are only 1's. In
- // each iteration we double the number of 1's that we set. At last add 1 and
- // we have the next power of 2.
- for (size_t i = 1; i < sizeof(uintptr_t) * 8; i <<= 1) {
- value |= value >> i;
- }
- return value + 1;
-}
-
-class AbstractPromise;
-
-// AbstractPromise needs to know which promises depend upon it. This lock free
-// class stores the list of dependents. This is not a general purpose list
-// because the data can only be consumed once.
-//
-// This class is thread safe.
-class BASE_EXPORT DependentList {
- public:
- struct ConstructUnresolved {};
- struct ConstructResolved {};
- struct ConstructRejected {};
-
- explicit DependentList(ConstructUnresolved);
- explicit DependentList(ConstructResolved);
- explicit DependentList(ConstructRejected);
-
- ~DependentList();
-
- DependentList(const DependentList&) = delete;
- DependentList& operator=(const DependentList&) = delete;
-
- enum class InsertResult {
- SUCCESS,
- FAIL_PROMISE_RESOLVED,
- FAIL_PROMISE_REJECTED,
- FAIL_PROMISE_CANCELED,
- };
-
- // Align Node on an 8-byte boundary to ensure the first 3 bits are 0 and can
- // be used to store additional state (see static_asserts below).
- class BASE_EXPORT ALIGNAS(8) Node {
- public:
- Node();
- explicit Node(Node&& other) noexcept;
-
- // Constructs a Node, |prerequisite| will not be retained unless
- // RetainSettledPrerequisite is called.
- Node(AbstractPromise* prerequisite,
- scoped_refptr<AbstractPromise> dependent);
- ~Node();
-
- // Caution this is not thread safe.
- void Reset(AbstractPromise* prerequisite,
- scoped_refptr<AbstractPromise> dependent);
-
- // Expected prerequisite usage:
- // 1. prerequisite = null on creation (or is constructed with a value)
- // 2. (optional, once only) SetPrerequisite(value)
- // 3. (maybe, once only) RetainSettledPrerequisite();
- // 4. (maybe) ClearPrerequisite()
- // 5. Destructor called
-
- // Can be called on any thread.
- void SetPrerequisite(AbstractPromise* prerequisite);
-
- // Can be called on any thread.
- AbstractPromise* prerequisite() const;
-
- scoped_refptr<AbstractPromise>& dependent() { return dependent_; }
-
- const scoped_refptr<AbstractPromise>& dependent() const {
- return dependent_;
- }
-
- Node* next() const { return next_; }
-
- // Calls AddRef on |prerequisite()| and marks the prerequisite as being
- // retained. The |prerequisite()| will be released by Node's destructor or
- // a call to ClearPrerequisite. Does nothing if called more than once.
- // Can be called on any thread at any time. Can be called once only.
- void RetainSettledPrerequisite();
-
- // Calls Release() if the rerequsite was retained and then sets
- // |prerequisite_| to zero. Can be called on any thread at any time. Can be
- // called more than once.
- void ClearPrerequisite();
-
- private:
- friend class DependentList;
-
- void MarkAsRetained() { prerequisite_ |= kIsRetained; }
-
- // An AbstractPromise* where the LSB is a flag which specified if it's
- // retained or not.
- // A reference for |prerequisite_| is acquired with an explicit call to
- // AddRef() if it's resolved or rejected.
- std::atomic<intptr_t> prerequisite_{0};
-
- scoped_refptr<AbstractPromise> dependent_;
- Node* next_ = nullptr;
-
- static constexpr intptr_t kIsRetained = 1;
- };
-
- // Insert will only succeed if neither ResolveAndConsumeAllDependents nor
- // RejectAndConsumeAllDependents nor CancelAndConsumeAllDependents have been
- // called yet. If the call succeeds, |node| must remain valid pointer until it
- // is consumed by one of the *AndConsumeAllDependents methods. If none of
- // those methods is called |node| must only be valid for the duration of this
- // call. Nodes will be consumed in the same order as they are inserted.
- InsertResult Insert(Node* node);
-
- // Callback for *AndConsumeAllDependents methods.
- // TODO(carlscab): Consider using a callable object instead.
- class BASE_EXPORT Visitor {
- public:
- virtual ~Visitor();
- // Called from the *AndConsumeAllDependents methods for each node.
- // |dependent| is the consumed (i.e. moved) from the one associated with the
- // node. It is fine if the pointer to the node becomes invalid inside this
- // call (i.e it is fine to delete the node).
- virtual void Visit(scoped_refptr<AbstractPromise> dependent) = 0;
- };
-
- // The following *AndConsumeAllDependents methods will settle the list and
- // consume all previously inserted nodes. It is guaranteed that Insert()
- // failures will happen-after all nodes have been consumed. In particular that
- // means that if an Insert happens while we are still consuming nodes the
- // Insert will succeed and the node will be appended to the list of nodes to
- // consume and eventually be consumed.
- //
- // ATTENTION: Calls to any of this methods will fail if itself or a different
- // consume method has been previously called. ResolveAndConsumeAllDependents
- // and RejectAndConsumeAllDependents will DCHECK on failures and
- // CancelAndConsumeAllDependents will return false if it fails.
-
- void ResolveAndConsumeAllDependents(Visitor* visitor) {
- const bool success =
- SettleAndDispatchAllDependents(State::kResolved, visitor);
- DCHECK(success) << "Was already settled";
- }
-
- void RejectAndConsumeAllDependents(Visitor* visitor) {
- const bool success =
- SettleAndDispatchAllDependents(State::kRejected, visitor);
- DCHECK(success) << "Was already settled";
- }
-
- // TODO(alexclarke): Consider DCHECK for failures which would also allow us to
- // greatly simplify SettleAndDispatchAllDependents
- bool CancelAndConsumeAllDependents(Visitor* visitor) {
- return SettleAndDispatchAllDependents(State::kCanceled, visitor);
- }
-
- // Returns true if any of IsResolved, IsRejected, or IsCanceled would return
- // true
- bool IsSettled() const;
-
- // Returns true if (Resolve/Reject/Cancel)AndConsumeAllDependents
- // has resolved/rejected/canceled the promise, respectively.
- //
- // ATTENTION: No guarantees are made as of whether the
- // (Resolve/Reject/Cancel)AndConsumeAllDependents method is still executing.
- bool IsCanceled() const;
-
- // DCHECKs if not settled.
- bool IsResolved() const;
-
- // DCHECKs if not settled.
- bool IsRejected() const;
-
- // Like the above but doesn't DCHECK if unsettled.
- bool IsResolvedForTesting() const;
- bool IsRejectedForTesting() const;
-
- private:
- // The data for this class is:
- // * head: Pointer to the head of the list of Node instances
- // * allow_inserts: flag indicating whether further inserts are allowed
- // * state: State value
- //
- // We store all this information in a uintptr_t to support atomic operations
- // as follows:
- // PP...PPPFSS
- // * P: Pointer to the head of the list of Node instances (head)
- // * F: Flag inidicating whether further inserts are allowed (allow_inserts)
- // * S: State value (state)
- //
- // The various *Mask constants contain the bit masks for the various fields.
- //
- // Inserts can be allowed in any of the states, but they MUST be allowed in
- // State::kUnresolved. Inserts are allowed while in one of the settled states
- // while the SettleAndDispatchAllDependents is dispatching nodes. This is done
- // so to preserve dispatch order. Once all nodes have been dispatched (i.e.
- // the list is empty), the allow_inserts is atomically (making sure list is
- // still empty) set to false. From that point on Inserts will fail.
- //
- // All valid state transitions start from State::kUnresolved i.e. only the
- // first call to SettleAndDispatchAllDependents will be able to settle the
- // state and succeed, all others will fail.
- //
- // The Is(Resolved|Rejected|Canceled) methods must return true while we are
- // dispatching nodes. That is we need to access the settled state while we are
- // still dispatching nodes. Thus we need and extra bit (allow_inserts) so that
- // Insert can determine whether to insert or fail when there is a settled
- // state.
-
- enum class InsertPolicy {
- kAllow,
- kBlock,
- };
- static constexpr auto kAllowInserts = InsertPolicy::kAllow;
- static constexpr auto kBlockInserts = InsertPolicy::kBlock;
-
- enum class State {
- kUnresolved = 0,
- kResolved,
- kRejected,
- kCanceled,
- kLastValue = kCanceled
- };
-
- static constexpr uintptr_t kStateMask =
- NextPowerOfTwo(static_cast<uintptr_t>(State::kLastValue)) - 1;
- static constexpr uintptr_t kAllowInsertsBitMask = kStateMask + 1;
- static constexpr uintptr_t kHeadMask = ~(kAllowInsertsBitMask | kStateMask);
-
- static_assert(
- std::alignment_of<Node>() > kAllowInsertsBitMask,
- "Will not be able to hold the Node* and all the state in a uintptr_t");
-
- static State ExtractState(uintptr_t data) {
- return static_cast<State>(data & kStateMask);
- }
-
- static DependentList::Node* ExtractHead(uintptr_t data) {
- return reinterpret_cast<DependentList::Node*>(data & kHeadMask);
- }
-
- static bool IsListEmpty(uintptr_t data) {
- return ExtractHead(data) == nullptr;
- }
-
- static bool IsAllowingInserts(uintptr_t data) {
- return data & kAllowInsertsBitMask;
- }
-
- static uintptr_t CreateData(Node* head,
- State state,
- InsertPolicy insert_policy) {
- DCHECK_EQ(uintptr_t(head), uintptr_t(head) & kHeadMask)
- << "Node doesn't have enough alignment";
- DCHECK(insert_policy == kAllowInserts || head == nullptr)
- << "List must be empty if no more inserts are allowed";
- DCHECK(insert_policy == kAllowInserts || state != State::kUnresolved)
- << "Can not block inserts and remain in kUnresolved state";
- return reinterpret_cast<uintptr_t>(head) |
- (insert_policy == kAllowInserts ? kAllowInsertsBitMask : 0) |
- (static_cast<uintptr_t>(state) & kStateMask);
- }
-
- explicit DependentList(State initial_state);
-
- // Settles the list and consumes all previously inserted nodes. If the list is
- // already settled it does nothing and returns false, true otherwise.
- bool SettleAndDispatchAllDependents(State settled_state, Visitor* visitor);
-
- static DependentList::Node* ReverseList(DependentList::Node* list);
-
- // Goes through the list starting at |head| consuming node->dependent and
- // passing it to the provided |visitor|.
- static void DispatchAll(DependentList::Node* head,
- DependentList::Visitor* visitor,
- bool retain_prerequsites);
-
- std::atomic<uintptr_t> data_;
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_DEPENDENT_LIST_H_
diff --git a/task/promise/dependent_list_unittest.cc b/task/promise/dependent_list_unittest.cc
deleted file mode 100644
index 9373aff..0000000
--- a/task/promise/dependent_list_unittest.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/dependent_list.h"
-
-#include <cstdint>
-#include <limits>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/task/promise/abstract_promise.h"
-#include "base/test/do_nothing_promise.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace internal {
-namespace {
-
-class PushBackVisitor : public DependentList::Visitor {
- public:
- void Visit(scoped_refptr<AbstractPromise> dependent) override {
- dependents_.push_back(dependent.get());
- }
-
- const std::vector<AbstractPromise*> visited_dependents() const {
- return dependents_;
- }
-
- private:
- std::vector<AbstractPromise*> dependents_;
-};
-
-class FailTestVisitor : public DependentList::Visitor {
- public:
- void Visit(scoped_refptr<AbstractPromise> dependent) override {
- ADD_FAILURE();
- }
-};
-
-} // namespace
-
-using ::testing::ElementsAre;
-
-TEST(DependentList, ConstructUnresolved) {
- DependentList list(DependentList::ConstructUnresolved{});
- DependentList::Node node;
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node));
- EXPECT_FALSE(list.IsRejectedForTesting());
- EXPECT_FALSE(list.IsCanceled());
- EXPECT_FALSE(list.IsResolvedForTesting());
- EXPECT_FALSE(list.IsSettled());
-}
-
-TEST(DependentList, ConstructResolved) {
- DependentList list(DependentList::ConstructResolved{});
- DependentList::Node node;
- EXPECT_EQ(DependentList::InsertResult::FAIL_PROMISE_RESOLVED,
- list.Insert(&node));
- EXPECT_TRUE(list.IsResolved());
- EXPECT_FALSE(list.IsRejected());
- EXPECT_FALSE(list.IsCanceled());
- EXPECT_TRUE(list.IsSettled());
-}
-
-TEST(DependentList, ConstructRejected) {
- DependentList list(DependentList::ConstructRejected{});
- DependentList::Node node;
- EXPECT_EQ(DependentList::InsertResult::FAIL_PROMISE_REJECTED,
- list.Insert(&node));
- EXPECT_TRUE(list.IsRejected());
- EXPECT_FALSE(list.IsCanceled());
- EXPECT_FALSE(list.IsResolved());
- EXPECT_TRUE(list.IsSettled());
-}
-
-TEST(DependentList, ResolveAndConsumeAllDependents) {
- DependentList list(DependentList::ConstructUnresolved{});
- DependentList::Node node1;
- DependentList::Node node2;
- DependentList::Node node3;
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node1));
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node2));
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node3));
-
- EXPECT_FALSE(list.IsResolvedForTesting());
- EXPECT_FALSE(list.IsSettled());
-
- std::vector<AbstractPromise*> expected_dependants = {node1.dependent().get(),
- node2.dependent().get(),
- node3.dependent().get()};
-
- PushBackVisitor visitor;
- list.ResolveAndConsumeAllDependents(&visitor);
- EXPECT_TRUE(list.IsResolved());
- EXPECT_TRUE(list.IsSettled());
-
- EXPECT_EQ(expected_dependants, visitor.visited_dependents());
-
- // Can't insert any more nodes.
- DependentList::Node node4;
- EXPECT_EQ(DependentList::InsertResult::FAIL_PROMISE_RESOLVED,
- list.Insert(&node4));
-}
-
-TEST(DependentList, RejectAndConsumeAllDependents) {
- DependentList list(DependentList::ConstructUnresolved{});
- DependentList::Node node1;
- DependentList::Node node2;
- DependentList::Node node3;
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node1));
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node2));
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node3));
-
- EXPECT_FALSE(list.IsResolvedForTesting());
- EXPECT_FALSE(list.IsSettled());
- std::vector<AbstractPromise*> expected_dependants = {node1.dependent().get(),
- node2.dependent().get(),
- node3.dependent().get()};
-
- PushBackVisitor visitor;
- list.RejectAndConsumeAllDependents(&visitor);
- EXPECT_TRUE(list.IsRejected());
- EXPECT_TRUE(list.IsSettled());
-
- EXPECT_EQ(expected_dependants, visitor.visited_dependents());
-
- // Can't insert any more nodes.
- DependentList::Node node4;
- EXPECT_EQ(DependentList::InsertResult::FAIL_PROMISE_REJECTED,
- list.Insert(&node4));
-}
-
-TEST(DependentList, CancelAndConsumeAllDependents) {
- DependentList list(DependentList::ConstructUnresolved{});
- DependentList::Node node1;
- DependentList::Node node2;
- DependentList::Node node3;
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node1));
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node2));
- EXPECT_EQ(DependentList::InsertResult::SUCCESS, list.Insert(&node3));
-
- EXPECT_FALSE(list.IsResolvedForTesting());
- EXPECT_FALSE(list.IsSettled());
- std::vector<AbstractPromise*> expected_dependants = {node1.dependent().get(),
- node2.dependent().get(),
- node3.dependent().get()};
-
- PushBackVisitor visitor;
- EXPECT_TRUE(list.CancelAndConsumeAllDependents(&visitor));
- EXPECT_TRUE(list.IsCanceled());
- EXPECT_TRUE(list.IsSettled());
-
- EXPECT_EQ(expected_dependants, visitor.visited_dependents());
-
- // Can't insert any more nodes.
- DependentList::Node node4;
- EXPECT_EQ(DependentList::InsertResult::FAIL_PROMISE_CANCELED,
- list.Insert(&node4));
-}
-
-TEST(DependentList, CancelAndConsumeAllDependentsFailsIfAlreadySettled) {
- DependentList list(DependentList::ConstructUnresolved{});
-
- FailTestVisitor visitor;
- list.ResolveAndConsumeAllDependents(&visitor);
-
- EXPECT_FALSE(list.CancelAndConsumeAllDependents(&visitor));
-
- EXPECT_FALSE(list.IsCanceled());
- EXPECT_TRUE(list.IsResolved());
-}
-
-TEST(DependentList, NextPowerOfTwo) {
- static_assert(NextPowerOfTwo(0) == 1u, "");
- static_assert(NextPowerOfTwo(1) == 2u, "");
- static_assert(NextPowerOfTwo(2) == 4u, "");
- static_assert(NextPowerOfTwo(3) == 4u, "");
- static_assert(NextPowerOfTwo(4) == 8u, "");
- static_assert(NextPowerOfTwo((1ull << 21) + (1ull << 19)) == 1ull << 22, "");
- static_assert(NextPowerOfTwo(std::numeric_limits<uintptr_t>::max() >> 1) ==
- 1ull << (sizeof(uintptr_t) * 8 - 1),
- "");
- static_assert(NextPowerOfTwo(std::numeric_limits<uintptr_t>::max()) == 0u,
- "");
-}
-
-TEST(DependentListNode, Simple) {
- DependentList::Node node;
- EXPECT_EQ(nullptr, node.prerequisite());
-
- scoped_refptr<AbstractPromise> p = DoNothingPromiseBuilder(FROM_HERE);
- EXPECT_TRUE(p->HasOneRef());
- node.SetPrerequisite(p.get());
- EXPECT_EQ(p.get(), node.prerequisite());
- EXPECT_TRUE(p->HasOneRef());
-
- EXPECT_TRUE(p->HasOneRef());
- node.RetainSettledPrerequisite();
- EXPECT_EQ(p.get(), node.prerequisite());
- EXPECT_FALSE(p->HasOneRef());
-
- node.ClearPrerequisite();
- EXPECT_EQ(nullptr, node.prerequisite());
- EXPECT_TRUE(p->HasOneRef());
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/finally_executor.cc b/task/promise/finally_executor.cc
deleted file mode 100644
index 52da567..0000000
--- a/task/promise/finally_executor.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/finally_executor.h"
-
-namespace base {
-namespace internal {
-
-FinallyExecutorCommon::FinallyExecutorCommon(
- internal::CallbackBase&& callback) noexcept
- : callback_(std::move(callback)) {}
-
-FinallyExecutorCommon::~FinallyExecutorCommon() = default;
-
-bool FinallyExecutorCommon::IsCancelled() const {
- return callback_.IsCancelled();
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/finally_executor.h b/task/promise/finally_executor.h
deleted file mode 100644
index a80f81c..0000000
--- a/task/promise/finally_executor.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_FINALLY_EXECUTOR_H_
-#define BASE_TASK_PROMISE_FINALLY_EXECUTOR_H_
-
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/helpers.h"
-
-namespace base {
-namespace internal {
-
-// Exists to reduce template bloat.
-class BASE_EXPORT FinallyExecutorCommon {
- public:
- explicit FinallyExecutorCommon(CallbackBase&& callback) noexcept;
- ~FinallyExecutorCommon();
-
- // PromiseExecutor:
- bool IsCancelled() const;
-
- CallbackBase callback_;
-};
-
-// A finally promise executor runs regardless of whether the prerequisite was
-// resolved or rejected. If the prerequsite is cancelled, the finally promise
-// and any dependents are cancelled too.
-template <typename CallbackT, typename ResolveStorage, typename RejectStorage>
-class FinallyExecutor {
- public:
- using CallbackReturnT = typename CallbackTraits<CallbackT>::ReturnType;
-
- explicit FinallyExecutor(CallbackBase&& callback) noexcept
- : common_(std::move(callback)) {}
-
- ~FinallyExecutor() = default;
-
- bool IsCancelled() const { return common_.IsCancelled(); }
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- PromiseExecutor::PrerequisitePolicy::kAll;
-
- void Execute(AbstractPromise* promise) {
- AbstractPromise* prerequisite = promise->GetOnlyPrerequisite();
- // Internally RunHelper uses const RepeatingCallback<>& to avoid the
- // binary size overhead of moving a scoped_refptr<> about. We respect
- // the onceness of the callback and RunHelper will overwrite the callback
- // with the result.
- using RepeatingCB = typename ToRepeatingCallback<CallbackT>::value;
- RepeatingCB* resolve_executor =
- static_cast<RepeatingCB*>(&common_.callback_);
- RunHelper<RepeatingCB, void, ResolveStorage, RejectStorage>::Run(
- *resolve_executor, prerequisite, promise);
- }
-
-#if DCHECK_IS_ON()
- PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const {
- return PromiseExecutor::ArgumentPassingType::kNormal;
- }
-
- PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const {
- return PromiseExecutor::ArgumentPassingType::kNormal;
- }
-
- bool CanResolve() const {
- return PromiseCallbackTraits<CallbackReturnT>::could_resolve;
- }
-
- bool CanReject() const {
- return PromiseCallbackTraits<CallbackReturnT>::could_reject;
- }
-#endif
-
- private:
- FinallyExecutorCommon common_;
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_FINALLY_EXECUTOR_H_
diff --git a/task/promise/helpers.cc b/task/promise/helpers.cc
deleted file mode 100644
index f100cac..0000000
--- a/task/promise/helpers.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/helpers.h"
-
-#include "base/bind_helpers.h"
-#include "base/task/promise/no_op_promise_executor.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-
-namespace base {
-namespace internal {
-
-DoNothing ToCallbackBase(DoNothing task) {
- return task;
-}
-
-PassedPromise ConstructAbstractPromiseWithSinglePrerequisite(
- const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- AbstractPromise* prerequisite,
- internal::PromiseExecutor::Data&& executor_data) noexcept {
- // Note |prerequisite| can legitimately be null when posting a promise chain
- // during shutdown.
- if (!prerequisite) {
- // Ensure the destructor for |executor_data| runs.
- PromiseExecutor dummy_executor(std::move(executor_data));
- return PassedPromise();
- }
-
- return PassedPromise(AbstractPromise::Create(
- task_runner, from_here,
- std::make_unique<AbstractPromise::AdjacencyList>(prerequisite),
- RejectPolicy::kMustCatchRejection,
- internal::DependentList::ConstructUnresolved(),
- std::move(executor_data)));
-}
-
-PassedPromise ConstructHereAbstractPromiseWithSinglePrerequisite(
- const Location& from_here,
- AbstractPromise* prerequisite,
- internal::PromiseExecutor::Data&& executor_data) noexcept {
- return ConstructAbstractPromiseWithSinglePrerequisite(
- SequencedTaskRunnerHandle::Get(), from_here, prerequisite,
- std::move(executor_data));
-}
-
-PassedPromise ConstructManualPromiseResolverPromise(const Location& from_here,
- RejectPolicy reject_policy,
- bool can_resolve,
- bool can_reject) {
- return PassedPromise(AbstractPromise::CreateNoPrerequisitePromise(
- from_here, reject_policy, internal::DependentList::ConstructUnresolved(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::NoOpPromiseExecutor>(), can_resolve,
- can_reject)));
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/helpers.h b/task/promise/helpers.h
deleted file mode 100644
index 87d9ff6..0000000
--- a/task/promise/helpers.h
+++ /dev/null
@@ -1,716 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_HELPERS_H_
-#define BASE_TASK_PROMISE_HELPERS_H_
-
-#include <tuple>
-#include <type_traits>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/parameter_pack.h"
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/promise_result.h"
-
-namespace base {
-class DoNothing;
-
-namespace internal {
-
-template <typename T>
-using ToNonVoidT = std::conditional_t<std::is_void<T>::value, Void, T>;
-
-template <typename T>
-using UndoToNonVoidT =
- std::conditional_t<std::is_same<Void, T>::value, void, T>;
-
-// Tag dispatch helper for PostTaskExecutor and ThenAndCatchExecutor.
-struct CouldResolveOrReject {};
-struct CanOnlyResolve {};
-struct CanOnlyReject {};
-
-// PromiseCallbackTraits computes the resolve and reject types of a Promise
-// from the return type of a resolve or reject callback.
-//
-// Usage example:
-// using Traits = PromiseCallbackTraits<int>;
-//
-// Traits::
-// ResolveType is int
-// RejectType is NoReject
-// could_resolve is true
-// could_reject is false
-template <typename T>
-struct PromiseCallbackTraits {
- using ResolveType = T;
- using RejectType = NoReject;
- using TagType = CanOnlyResolve;
- static constexpr bool could_resolve = true;
- static constexpr bool could_reject = false;
-};
-
-template <typename T>
-struct PromiseCallbackTraits<Resolved<T>> {
- using ResolveType = T;
- using RejectType = NoReject;
- using TagType = CanOnlyResolve;
- static constexpr bool could_resolve = true;
- static constexpr bool could_reject = false;
-};
-
-template <typename T>
-struct PromiseCallbackTraits<Rejected<T>> {
- using ResolveType = NoResolve;
- using RejectType = T;
- using TagType = CanOnlyReject;
- static constexpr bool could_resolve = false;
- static constexpr bool could_reject = true;
-};
-
-template <typename Reject>
-struct PromiseCallbackTraits<Promise<NoResolve, Reject>> {
- using ResolveType = NoResolve;
- using RejectType = Reject;
- using TagType = CanOnlyReject;
- static constexpr bool could_resolve = false;
- static constexpr bool could_reject = true;
-};
-
-template <typename Resolve>
-struct PromiseCallbackTraits<Promise<Resolve, NoReject>> {
- using ResolveType = Resolve;
- using RejectType = NoReject;
- using TagType = CanOnlyResolve;
- static constexpr bool could_resolve = true;
- static constexpr bool could_reject = false;
-};
-
-template <typename Resolve, typename Reject>
-struct PromiseCallbackTraits<Promise<Resolve, Reject>> {
- using ResolveType = Resolve;
- using RejectType = Reject;
- using TagType = CouldResolveOrReject;
- static constexpr bool could_resolve = true;
- static constexpr bool could_reject = true;
-};
-
-template <typename Reject>
-struct PromiseCallbackTraits<PromiseResult<NoResolve, Reject>> {
- using ResolveType = NoResolve;
- using RejectType = Reject;
- using TagType = CanOnlyReject;
- static constexpr bool could_resolve = false;
- static constexpr bool could_reject = true;
-};
-
-template <typename Resolve>
-struct PromiseCallbackTraits<PromiseResult<Resolve, NoReject>> {
- using ResolveType = Resolve;
- using RejectType = NoReject;
- using TagType = CanOnlyResolve;
- static constexpr bool could_resolve = true;
- static constexpr bool could_reject = false;
-};
-
-template <typename Resolve, typename Reject>
-struct PromiseCallbackTraits<PromiseResult<Resolve, Reject>> {
- using ResolveType = Resolve;
- using RejectType = Reject;
- using TagType = CouldResolveOrReject;
- static constexpr bool could_resolve = true;
- static constexpr bool could_reject = true;
-};
-
-template <typename T>
-struct IsScopedRefPtr {
- static constexpr bool value = false;
-};
-
-template <typename T>
-struct IsScopedRefPtr<scoped_refptr<T>> {
- static constexpr bool value = true;
-};
-
-// UseMoveSemantics determines whether move semantics should be used to
-// pass |T| as a function parameter.
-//
-// Usage example:
-//
-// UseMoveSemantics<std::unique_ptr<int>>::value; // is true
-// UseMoveSemantics<int>::value; // is false
-// UseMoveSemantics<scoped_refptr<Dummy>>::value; // is false
-//
-// Will give false positives for some copyable types, but that should be
-// harmless.
-template <typename T>
-constexpr bool UseMove() {
- return !std::is_reference<T>::value && !std::is_pointer<T>::value &&
- !std::is_fundamental<std::decay_t<T>>::value &&
- !IsScopedRefPtr<T>::value;
-}
-
-template <typename T>
-struct UseMoveSemantics : public std::integral_constant<bool, UseMove<T>()> {
- static_assert(!std::is_rvalue_reference<T>::value,
- "Promise<T&&> not supported");
-
- static constexpr PromiseExecutor::ArgumentPassingType argument_passing_type =
- UseMove<T>() ? PromiseExecutor::ArgumentPassingType::kMove
- : PromiseExecutor::ArgumentPassingType::kNormal;
-};
-
-// A std::tuple is deemed to need move semantics if any of it's members need
-// to be moved according to UseMove<>.
-template <typename... Ts>
-struct UseMoveSemantics<std::tuple<Ts...>>
- : public std::integral_constant<bool, any_of({UseMove<Ts>()...})> {
- static constexpr PromiseExecutor::ArgumentPassingType argument_passing_type =
- any_of({UseMove<Ts>()...})
- ? PromiseExecutor::ArgumentPassingType::kMove
- : PromiseExecutor::ArgumentPassingType::kNormal;
-};
-
-// CallbackTraits extracts properties relevant to Promises from a callback.
-//
-// Usage example:
-//
-// using Traits = CallbackTraits<
-// base::OnceCallback<PromiseResult<int, std::string>(float)>;
-//
-// Traits::
-// ResolveType is int
-// RejectType is std::string
-// ArgType is float
-// ReturnType is PromiseResult<int, std::string>
-// SignatureType is PromiseResult<int, std::string>(float)
-// argument_passing_type is kNormal
-template <typename T>
-struct CallbackTraits;
-
-template <typename T>
-struct CallbackTraits<T()> {
- using ResolveType = typename internal::PromiseCallbackTraits<T>::ResolveType;
- using RejectType = typename internal::PromiseCallbackTraits<T>::RejectType;
- using ArgType = void;
- using ReturnType = T;
- using SignatureType = T();
- static constexpr PromiseExecutor::ArgumentPassingType argument_passing_type =
- PromiseExecutor::ArgumentPassingType::kNormal;
-};
-
-template <typename T, typename Arg>
-struct CallbackTraits<T(Arg)> {
- using ResolveType = typename internal::PromiseCallbackTraits<T>::ResolveType;
- using RejectType = typename internal::PromiseCallbackTraits<T>::RejectType;
- using ArgType = Arg;
- using ReturnType = T;
- using SignatureType = T(Arg);
- static constexpr PromiseExecutor::ArgumentPassingType argument_passing_type =
- UseMoveSemantics<Arg>::argument_passing_type;
-};
-
-template <typename T, typename... Args>
-struct CallbackTraits<T(Args...)> {
- using ResolveType = typename internal::PromiseCallbackTraits<T>::ResolveType;
- using RejectType = typename internal::PromiseCallbackTraits<T>::RejectType;
- using ArgType =
- std::conditional_t<(sizeof...(Args) > 0), std::tuple<Args...>, void>;
- using ReturnType = T;
- using SignatureType = T(Args...);
-
- // If any arguments need move semantics, treat as if they all do.
- static constexpr PromiseExecutor::ArgumentPassingType argument_passing_type =
- any_of({UseMoveSemantics<Args>::value...})
- ? PromiseExecutor::ArgumentPassingType::kMove
- : PromiseExecutor::ArgumentPassingType::kNormal;
-};
-
-template <>
-struct CallbackTraits<DoNothing> {
- using ResolveType = void;
- using RejectType = NoReject;
- using ArgType = void;
- using ReturnType = void;
- using SignatureType = void();
- static constexpr PromiseExecutor::ArgumentPassingType argument_passing_type =
- PromiseExecutor::ArgumentPassingType::kNormal;
-};
-
-// Adaptors for OnceCallback and RepeatingCallback
-template <typename T, typename... Args>
-struct CallbackTraits<OnceCallback<T(Args...)>>
- : public CallbackTraits<T(Args...)> {};
-
-template <typename T, typename... Args>
-struct CallbackTraits<RepeatingCallback<T(Args...)>>
- : public CallbackTraits<T(Args...)> {};
-
-// Helper for combining the resolve types of two promises.
-template <typename A, typename B>
-struct ResolveCombinerHelper {
- using Type = A;
- static constexpr bool valid = false;
-};
-
-template <typename A>
-struct ResolveCombinerHelper<A, A> {
- using Type = A;
- static constexpr bool valid = true;
-};
-
-template <typename B>
-struct ResolveCombinerHelper<NoResolve, B> {
- using Type = B;
- static constexpr bool valid = true;
-};
-
-template <typename A>
-struct ResolveCombinerHelper<A, NoResolve> {
- using Type = A;
- static constexpr bool valid = true;
-};
-
-template <>
-struct ResolveCombinerHelper<NoResolve, NoResolve> {
- using Type = NoResolve;
- static constexpr bool valid = true;
-};
-
-// Helper for combining the reject types of two promises.
-template <typename A, typename B>
-struct RejectCombinerHelper {
- using Type = A;
- static constexpr bool valid = false;
-};
-
-template <typename A>
-struct RejectCombinerHelper<A, A> {
- using Type = A;
- static constexpr bool valid = true;
-};
-
-template <typename B>
-struct RejectCombinerHelper<NoReject, B> {
- using Type = B;
- static constexpr bool valid = true;
-};
-
-template <typename A>
-struct RejectCombinerHelper<A, NoReject> {
- using Type = A;
- static constexpr bool valid = true;
-};
-
-template <>
-struct RejectCombinerHelper<NoReject, NoReject> {
- using Type = NoReject;
- static constexpr bool valid = true;
-};
-
-// Helper that computes and validates the return type for combining promises.
-// Essentially the promise types have to match unless there's NoResolve or
-// or NoReject in which case they can be combined.
-template <typename ThenReturnResolveT,
- typename ThenReturnRejectT,
- typename CatchReturnResolveT,
- typename CatchReturnRejectT>
-struct PromiseCombiner {
- using ResolveHelper =
- ResolveCombinerHelper<ThenReturnResolveT, CatchReturnResolveT>;
- using RejectHelper =
- RejectCombinerHelper<ThenReturnRejectT, CatchReturnRejectT>;
- using ResolveType = typename ResolveHelper::Type;
- using RejectType = typename RejectHelper::Type;
- static constexpr bool valid = ResolveHelper::valid && RejectHelper::valid;
-};
-
-template <typename RejectStorage>
-struct EmplaceInnerHelper {
- template <typename Resolve, typename Reject>
- static void Emplace(AbstractPromise* promise,
- PromiseResult<Resolve, Reject>&& result) {
- promise->emplace(std::move(result.value()));
- }
-};
-
-// TODO(alexclarke): Specialize |EmplaceInnerHelper| where RejectStorage is
-// base::Variant to support Promises::All.
-
-template <typename ResolveStorage, typename RejectStorage>
-struct EmplaceHelper {
- template <typename Resolve, typename Reject>
- static void Emplace(AbstractPromise* promise,
- PromiseResult<Resolve, Reject>&& result) {
- static_assert(std::is_same<typename ResolveStorage::Type, Resolve>::value ||
- std::is_same<NoResolve, Resolve>::value,
- "Resolve should match ResolveStorage");
- static_assert(std::is_same<typename RejectStorage::Type, Reject>::value ||
- std::is_same<NoReject, Reject>::value,
- "Reject should match RejectStorage");
- EmplaceInnerHelper<RejectStorage>::Emplace(promise, std::move(result));
- }
-
- template <typename Resolve, typename Reject>
- static void Emplace(AbstractPromise* promise,
- Promise<Resolve, Reject>&& result) {
- static_assert(std::is_same<typename ResolveStorage::Type, Resolve>::value ||
- std::is_same<NoResolve, Resolve>::value,
- "Resolve should match ResolveStorage");
- static_assert(std::is_same<typename RejectStorage::Type, Reject>::value ||
- std::is_same<NoReject, Reject>::value,
- "Reject should match RejectStorage");
- promise->emplace(std::move(result.abstract_promise_));
- }
-
- template <typename Result>
- static void Emplace(AbstractPromise* promise, Result&& result) {
- static_assert(std::is_same<typename ResolveStorage::Type, Result>::value,
- "Result should match ResolveStorage");
- promise->emplace(in_place_type_t<Resolved<Result>>(),
- std::forward<Result>(result));
- }
-
- template <typename Resolve>
- static void Emplace(AbstractPromise* promise, Resolved<Resolve>&& resolved) {
- static_assert(std::is_same<typename ResolveStorage::Type, Resolve>::value,
- "Resolve should match ResolveStorage");
- promise->emplace(std::move(resolved));
- }
-
- template <typename Reject>
- static void Emplace(AbstractPromise* promise, Rejected<Reject>&& rejected) {
- static_assert(std::is_same<typename RejectStorage::Type, Reject>::value,
- "Reject should match RejectStorage");
- promise->emplace(std::move(rejected));
- }
-};
-
-// Helper that decides whether or not to std::move arguments for a callback
-// based on the type the callback specifies (i.e. we don't need to move if the
-// callback requests a reference).
-template <typename CbArg, typename ArgStorageType>
-class ArgMoveSemanticsHelper {
- public:
- static CbArg Get(AbstractPromise* arg) {
- return GetImpl(arg, UseMoveSemantics<CbArg>());
- }
-
- private:
- static CbArg GetImpl(AbstractPromise* arg, std::true_type should_move) {
- return std::move(arg->TakeValue().value().Get<ArgStorageType>()->value);
- }
-
- static CbArg GetImpl(AbstractPromise* arg, std::false_type should_move) {
- return arg->value().Get<ArgStorageType>()->value;
- }
-};
-
-// Helper for converting a callback to its repeating variant.
-template <typename Cb>
-struct ToRepeatingCallback;
-
-template <typename Cb>
-struct ToRepeatingCallback<OnceCallback<Cb>> {
- using value = RepeatingCallback<Cb>;
-};
-
-template <typename Cb>
-struct ToRepeatingCallback<RepeatingCallback<Cb>> {
- using value = RepeatingCallback<Cb>;
-};
-
-// Helper for running a promise callback and storing the result if any.
-//
-// Callback = signature of the callback to execute. Note we use repeating
-// callbacks to avoid the binary size overhead of a once callback which will
-// generate a destructor which is redundant because we overwrite the executor
-// with the promise result which also triggers the destructor.
-// ArgStorageType = type of the callback parameter (or void if none)
-// ResolveStorage = type to use for resolve, usually Resolved<T>.
-// RejectStorage = type to use for reject, usually Rejected<T>.
-// TODO(alexclarke): Add support for Rejected<Variant<...>>.
-template <typename Callback,
- typename ArgStorageType,
- typename ResolveStorage,
- typename RejectStorage>
-struct RunHelper;
-
-// Run helper for callbacks with a single argument.
-template <typename CbResult,
- typename CbArg,
- typename ArgStorageType,
- typename ResolveStorage,
- typename RejectStorage>
-struct RunHelper<RepeatingCallback<CbResult(CbArg)>,
- ArgStorageType,
- ResolveStorage,
- RejectStorage> {
- using Callback = RepeatingCallback<CbResult(CbArg)>;
-
- static void Run(const Callback& executor,
- AbstractPromise* arg,
- AbstractPromise* result) {
- EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(
- result,
- executor.Run(ArgMoveSemanticsHelper<CbArg, ArgStorageType>::Get(arg)));
- }
-};
-
-// Run helper for callbacks with a single argument and void return value.
-template <typename CbArg,
- typename ArgStorageType,
- typename ResolveStorage,
- typename RejectStorage>
-struct RunHelper<RepeatingCallback<void(CbArg)>,
- ArgStorageType,
- ResolveStorage,
- RejectStorage> {
- using Callback = RepeatingCallback<void(CbArg)>;
-
- static void Run(const Callback& executor,
- AbstractPromise* arg,
- AbstractPromise* result) {
- static_assert(std::is_void<typename ResolveStorage::Type>::value, "");
- executor.Run(ArgMoveSemanticsHelper<CbArg, ArgStorageType>::Get(arg));
- result->EmplaceResolvedVoid();
- }
-};
-
-// Run helper for callbacks with no arguments.
-template <typename CbResult,
- typename ArgStorageType,
- typename ResolveStorage,
- typename RejectStorage>
-struct RunHelper<RepeatingCallback<CbResult()>,
- ArgStorageType,
- ResolveStorage,
- RejectStorage> {
- using Callback = RepeatingCallback<CbResult()>;
-
- static void Run(const Callback& executor,
- AbstractPromise* arg,
- AbstractPromise* result) {
- EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(result,
- executor.Run());
- }
-};
-
-// Run helper for callbacks with no arguments and void return type.
-template <typename ArgStorageType,
- typename ResolveStorage,
- typename RejectStorage>
-struct RunHelper<RepeatingCallback<void()>,
- ArgStorageType,
- ResolveStorage,
- RejectStorage> {
- static void Run(const RepeatingCallback<void()>& executor,
- AbstractPromise* arg,
- AbstractPromise* result) {
- static_assert(std::is_void<typename ResolveStorage::Type>::value, "");
- executor.Run();
- result->EmplaceResolvedVoid();
- }
-};
-
-template <typename T>
-struct UnwrapCallback;
-
-template <typename R, typename... Args>
-struct UnwrapCallback<R(Args...)> {
- using ArgsTuple = std::tuple<Args...>;
-};
-
-// Helper for getting callback arguments from a tuple, which works out if move
-// semantics are needed.
-template <typename Callback, typename Tuple, size_t Index>
-struct TupleArgMoveSemanticsHelper {
- using CallbackArgsTuple =
- typename UnwrapCallback<typename Callback::RunType>::ArgsTuple;
- using CbArg = std::tuple_element_t<Index, CallbackArgsTuple>;
-
- static CbArg Get(Tuple& tuple) {
- return GetImpl(tuple, UseMoveSemantics<CbArg>());
- }
-
- private:
- static CbArg GetImpl(Tuple& tuple, std::true_type should_move) {
- return std::move(std::get<Index>(tuple));
- }
-
- static CbArg GetImpl(Tuple& tuple, std::false_type should_move) {
- return std::get<Index>(tuple);
- }
-};
-
-// Run helper for running a callbacks with the arguments unpacked from a tuple.
-template <typename CbResult,
- typename... CbArgs,
- typename ResolveStorage,
- typename RejectStorage>
-struct RunHelper<RepeatingCallback<CbResult(CbArgs...)>,
- Resolved<std::tuple<CbArgs...>>,
- ResolveStorage,
- RejectStorage> {
- using Callback = RepeatingCallback<CbResult(CbArgs...)>;
- using StorageType = Resolved<std::tuple<CbArgs...>>;
- using IndexSequence = std::index_sequence_for<CbArgs...>;
-
- static void Run(const Callback& executor,
- AbstractPromise* arg,
- AbstractPromise* result) {
- AbstractPromise::ValueHandle value = arg->TakeValue();
- std::tuple<CbArgs...>& tuple = value.value().Get<StorageType>()->value;
- RunInternal(executor, tuple, result,
- std::integral_constant<bool, std::is_void<CbResult>::value>(),
- IndexSequence{});
- }
-
- private:
- template <typename Callback, size_t... Indices>
- static void RunInternal(const Callback& executor,
- std::tuple<CbArgs...>& tuple,
- AbstractPromise* result,
- std::false_type void_result,
- std::index_sequence<Indices...>) {
- EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(executor.Run(
- TupleArgMoveSemanticsHelper<Callback, std::tuple<CbArgs...>,
- Indices>::Get(tuple)...));
- }
-
- template <typename Callback, size_t... Indices>
- static void RunInternal(const Callback& executor,
- std::tuple<CbArgs...>& tuple,
- AbstractPromise* result,
- std::true_type void_result,
- std::index_sequence<Indices...>) {
- executor.Run(TupleArgMoveSemanticsHelper<Callback, std::tuple<CbArgs...>,
- Indices>::Get(tuple)...);
- result->EmplaceResolvedVoid();
- }
-};
-
-// Used by ManualPromiseResolver<> to generate callbacks. Note the use of
-// WrappedPromise, this is necessary because we want to cancel the promise (to
-// release memory) if the callback gets deleted without having being run.
-template <typename T, typename... Args>
-class PromiseCallbackHelper {
- public:
- using Callback = base::OnceCallback<void(Args...)>;
- using RepeatingCallback = base::RepeatingCallback<void(Args...)>;
-
- static Callback GetResolveCallback(scoped_refptr<AbstractPromise>& promise) {
- return base::BindOnce(
- [](scoped_refptr<AbstractPromise> promise, Args... args) {
- promise->emplace(in_place_type_t<Resolved<T>>(),
- std::forward<Args>(args)...);
- promise->OnResolved();
- },
- promise);
- }
-
- static RepeatingCallback GetRepeatingResolveCallback(
- scoped_refptr<AbstractPromise>& promise) {
- return base::BindRepeating(
- [](scoped_refptr<AbstractPromise> promise, Args... args) {
- promise->emplace(in_place_type_t<Resolved<T>>(),
- std::forward<Args>(args)...);
- promise->OnResolved();
- },
- promise);
- }
-
- static Callback GetRejectCallback(scoped_refptr<AbstractPromise>& promise) {
- return base::BindOnce(
- [](scoped_refptr<AbstractPromise> promise, Args... args) {
- promise->emplace(in_place_type_t<Rejected<T>>(),
- std::forward<Args>(args)...);
- promise->OnRejected();
- },
- promise);
- }
-
- static RepeatingCallback GetRepeatingRejectCallback(
- scoped_refptr<AbstractPromise>& promise) {
- return base::BindRepeating(
- [](scoped_refptr<AbstractPromise> promise, Args... args) {
- promise->emplace(in_place_type_t<Rejected<T>>(),
- std::forward<Args>(args)...);
- promise->OnRejected();
- },
- promise);
- }
-};
-
-// Validates that the argument type |CallbackArgType| of a resolve or
-// reject callback is compatible with the resolve or reject type
-// |PromiseType| of this Promise.
-template <typename PromiseType, typename CallbackArgType>
-struct IsValidPromiseArg {
- static constexpr bool value =
- std::is_convertible<PromiseType, std::decay_t<CallbackArgType>>::value;
-};
-
-template <typename PromiseType, typename CallbackArgType>
-struct IsValidPromiseArg<PromiseType&, CallbackArgType> {
- static constexpr bool value =
- std::is_convertible<PromiseType&, CallbackArgType>::value;
-};
-
-// This template helps assign the reject value from a prerequisite into the
-// rejection storage type.
-template <typename RejectT>
-struct AllPromiseRejectHelper {
- static void Reject(AbstractPromise* result, AbstractPromise* prerequisite) {
- result->emplace(scoped_refptr<AbstractPromise>(prerequisite));
- }
-};
-
-// TODO(alexclarke): Specalize AllPromiseRejectHelper for variants.
-
-// To reduce template bloat executors hold CallbackBase. These functions convert
-// various types to CallbackBase.
-DoNothing BASE_EXPORT ToCallbackBase(DoNothing task);
-
-template <typename CallbackT>
-CallbackBase&& ToCallbackBase(CallbackT&& task) {
- static_assert(sizeof(CallbackBase) == sizeof(CallbackT),
- "We assume it's possible to cast from CallbackBase to "
- "CallbackT");
- return static_cast<CallbackBase&&>(task);
-}
-
-template <typename CallbackT>
-CallbackBase&& ToCallbackBase(const CallbackT&& task) {
- static_assert(sizeof(CallbackBase) == sizeof(CallbackT),
- "We assume it's possible to cast from CallbackBase to "
- "CallbackT");
- return static_cast<CallbackBase&&>(const_cast<CallbackT&&>(task));
-}
-
-// Helps reduce template bloat by moving AbstractPromise construction out of
-// line.
-PassedPromise BASE_EXPORT ConstructAbstractPromiseWithSinglePrerequisite(
- const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- AbstractPromise* prerequsite,
- PromiseExecutor::Data&& executor_data) noexcept;
-
-// Like ConstructAbstractPromiseWithSinglePrerequisite except tasks are posted
-// onto SequencedTaskRunnerHandle::Get().
-PassedPromise BASE_EXPORT ConstructHereAbstractPromiseWithSinglePrerequisite(
- const Location& from_here,
- AbstractPromise* prerequsite,
- PromiseExecutor::Data&& executor_data) noexcept;
-
-PassedPromise BASE_EXPORT
-ConstructManualPromiseResolverPromise(const Location& from_here,
- RejectPolicy reject_policy,
- bool can_resolve,
- bool can_reject);
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_HELPERS_H_
diff --git a/task/promise/helpers_unittest.cc b/task/promise/helpers_unittest.cc
deleted file mode 100644
index f13fb5c..0000000
--- a/task/promise/helpers_unittest.cc
+++ /dev/null
@@ -1,419 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/helpers.h"
-
-#include "base/bind.h"
-#include "base/task/promise/promise.h"
-#include "base/task_runner.h"
-#include "base/test/bind_test_util.h"
-#include "base/test/do_nothing_promise.h"
-#include "base/test/gtest_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace internal {
-
-TEST(UseMoveSemantics, GeneralTypes) {
- static_assert(!UseMoveSemantics<int>::value,
- "Integral types don't need to be moved");
-
- static_assert(UseMoveSemantics<std::unique_ptr<int>>::value,
- "Move only types should be moved");
-
- static_assert(
- !UseMoveSemantics<scoped_refptr<AbstractPromise>>::value,
- "To support multiple callbacks scoped_refptr doesn't need to be moved.");
-}
-
-TEST(CallbackTraits, CallbackReferenceTypes) {
- static_assert(
- std::is_same<int&,
- CallbackTraits<Callback<int&(int&)>>::ResolveType>::value,
- "");
-
- static_assert(
- std::is_same<int&, CallbackTraits<Callback<int&(int&)>>::ArgType>::value,
- "");
-}
-
-TEST(CallbackTraits, RepeatingCallbackReferenceTypes) {
- static_assert(
- std::is_same<
- int&,
- CallbackTraits<RepeatingCallback<int&(int&)>>::ResolveType>::value,
- "");
-
- static_assert(
- std::is_same<
- int&, CallbackTraits<RepeatingCallback<int&(int&)>>::ArgType>::value,
- "");
-}
-
-TEST(PromiseCombiner, InvalidCombos) {
- static_assert(!PromiseCombiner<Resolved<int>, Rejected<float>, Resolved<int>,
- Rejected<bool>>::valid,
- "Invalid, reject types differ");
- static_assert(!PromiseCombiner<Resolved<int>, Rejected<float>, Resolved<void>,
- Rejected<float>>::valid,
- "Invalid, resolve types differ");
-}
-
-TEST(PromiseCombiner, TypesMatch) {
- using Result = PromiseCombiner<Resolved<int>, Rejected<float>, Resolved<int>,
- Rejected<float>>;
- static_assert(Result::valid, "Types are the same, should match");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(PromiseCombiner, NoResolve) {
- using Result = PromiseCombiner<NoResolve, Rejected<float>, Resolved<int>,
- Rejected<float>>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(PromiseCombiner, NoResolve2) {
- using Result = PromiseCombiner<Resolved<int>, Rejected<float>, NoResolve,
- Rejected<float>>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(PromiseCombiner, BothNoResolve) {
- using Result =
- PromiseCombiner<NoResolve, Rejected<float>, NoResolve, Rejected<float>>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, NoResolve>::value,
- "Resolve type should be NoResolve");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(PromiseCombiner, NoReject) {
- using Result =
- PromiseCombiner<Resolved<int>, NoReject, Resolved<int>, Rejected<float>>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(PromiseCombiner, NoReject2) {
- using Result =
- PromiseCombiner<Resolved<int>, Rejected<float>, Resolved<int>, NoReject>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(PromiseCombiner, BothNoReject) {
- using Result =
- PromiseCombiner<Resolved<int>, NoReject, Resolved<int>, NoReject>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, NoReject>::value,
- "Resolve type should be NoReject");
-}
-
-TEST(PromiseCombiner, NoResolveAndNoReject) {
- using Result =
- PromiseCombiner<Resolved<int>, NoReject, NoResolve, Rejected<float>>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(PromiseCombiner, NoResolveAndNoReject2) {
- using Result =
- PromiseCombiner<NoResolve, Rejected<float>, Resolved<int>, NoReject>;
- static_assert(Result::valid, "Valid combination");
-
- static_assert(std::is_same<Result::ResolveType, Resolved<int>>::value,
- "Resolve type should be int");
-
- static_assert(std::is_same<Result::RejectType, Rejected<float>>::value,
- "Resolve type should be float");
-}
-
-TEST(EmplaceHelper, EmplacePromiseResult) {
- scoped_refptr<AbstractPromise> resolve =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> reject =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
-
- EmplaceHelper<Resolved<int>, Rejected<std::string>>::Emplace(
- resolve.get(), PromiseResult<int, std::string>(123));
- EmplaceHelper<Resolved<int>, Rejected<std::string>>::Emplace(
- reject.get(), PromiseResult<int, std::string>("Oh no!"));
-
- EXPECT_EQ(resolve->value().Get<Resolved<int>>()->value, 123);
- EXPECT_EQ(reject->value().Get<Rejected<std::string>>()->value, "Oh no!");
-}
-
-TEST(EmplaceHelper, EmplacePromise) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- PassedPromise curried = NoOpPromiseExecutor::Create(
- FROM_HERE, false, false, RejectPolicy::kCatchNotRequired);
- EmplaceHelper<Resolved<int>, Rejected<NoReject>>::Emplace(
- promise.get(), Promise<int>(std::move(curried)));
-
- EXPECT_TRUE(promise->IsResolvedWithPromise());
-}
-
-TEST(EmplaceHelper, NakedType) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- EmplaceHelper<Resolved<int>, Rejected<NoReject>>::Emplace(promise.get(), 123);
-
- EXPECT_EQ(promise->value().template Get<Resolved<int>>()->value, 123);
-}
-
-TEST(EmplaceHelper, ReferenceType) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- int a = 12345;
-
- EmplaceHelper<Resolved<int&>, Rejected<NoReject>>::Emplace<int&>(
- promise.get(), a);
-
- EXPECT_EQ(promise->value().template Get<Resolved<int&>>()->value, 12345);
-}
-
-TEST(EmplaceHelper, ResolvedInt) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- EmplaceHelper<Resolved<int>, Rejected<NoReject>>::Emplace(promise.get(),
- Resolved<int>(123));
-
- EXPECT_EQ(promise->value().template Get<Resolved<int>>()->value, 123);
-}
-
-TEST(EmplaceHelper, RejectedString) {
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
-
- EmplaceHelper<Resolved<void>, Rejected<std::string>>::Emplace(
- promise.get(), Rejected<std::string>("Whoops!"));
-
- EXPECT_EQ(promise->value().template Get<Rejected<std::string>>()->value,
- "Whoops!");
-}
-
-TEST(RunHelper, CallbackVoidArgumentIntResult) {
- scoped_refptr<AbstractPromise> arg = DoNothingPromiseBuilder(FROM_HERE);
- scoped_refptr<AbstractPromise> result =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- RunHelper<RepeatingCallback<int()>, Resolved<void>, Resolved<int>,
- Rejected<std::string>>::Run(BindRepeating([]() { return 123; }),
- arg.get(), result.get());
-
- EXPECT_EQ(result->value().template Get<Resolved<int>>()->value, 123);
-}
-
-TEST(RunHelper, CallbackVoidArgumentVoidResult) {
- scoped_refptr<AbstractPromise> arg = DoNothingPromiseBuilder(FROM_HERE);
- scoped_refptr<AbstractPromise> result =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- RunHelper<RepeatingCallback<void()>, Resolved<void>, Resolved<void>,
- Rejected<std::string>>::Run(BindRepeating([]() {}), arg.get(),
- result.get());
-
- EXPECT_TRUE(result->value().ContainsResolved());
-}
-
-TEST(RunHelper, CallbackIntArgumentIntResult) {
- scoped_refptr<AbstractPromise> arg = DoNothingPromiseBuilder(FROM_HERE);
- scoped_refptr<AbstractPromise> result =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- arg->emplace(Resolved<int>(123));
-
- RunHelper<RepeatingCallback<int(int)>, Resolved<int>, Resolved<int>,
- Rejected<std::string>>::Run(BindRepeating([](int value) {
- return value + 1;
- }),
- arg.get(), result.get());
-
- EXPECT_EQ(result->value().template Get<Resolved<int>>()->value, 124);
-}
-
-TEST(RunHelper, CallbackIntArgumentArgumentVoidResult) {
- scoped_refptr<AbstractPromise> arg = DoNothingPromiseBuilder(FROM_HERE);
- scoped_refptr<AbstractPromise> result =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- arg->emplace(Resolved<int>(123));
-
- int value;
- RunHelper<RepeatingCallback<void(int)>, Resolved<int>, Resolved<void>,
- Rejected<std::string>>::Run(BindLambdaForTesting([&](int arg) {
- value = arg;
- }),
- arg.get(), result.get());
-
- EXPECT_EQ(value, 123);
- EXPECT_TRUE(result->value().ContainsResolved());
-}
-
-TEST(PromiseCallbackHelper, GetResolveCallback) {
- PromiseCallbackHelper<int, int> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- OnceCallback<void(int)> resolve_cb = helper.GetResolveCallback(promise);
-
- std::move(resolve_cb).Run(1234);
-
- EXPECT_EQ(promise->value().template Get<Resolved<int>>()->value, 1234);
-}
-
-TEST(PromiseCallbackHelper, GetResolveReferenceCallback) {
- int foo = 123;
- PromiseCallbackHelper<int&, int&> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- OnceCallback<void(int&)> resolve_cb = helper.GetResolveCallback(promise);
-
- std::move(resolve_cb).Run(foo);
-
- EXPECT_EQ(&promise->value().template Get<Resolved<int&>>()->value, &foo);
-}
-
-TEST(PromiseCallbackHelper, GetRejectCallback) {
- PromiseCallbackHelper<int, int> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
-
- OnceCallback<void(int)> reject_cb = helper.GetRejectCallback(promise);
-
- std::move(reject_cb).Run(1234);
-
- EXPECT_EQ(promise->value().template Get<Rejected<int>>()->value, 1234);
-}
-
-TEST(PromiseCallbackHelper, GetRejectReferenceCallback) {
- int foo = 123;
- PromiseCallbackHelper<int&, int&> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
-
- OnceCallback<void(int&)> reject_cb = helper.GetRejectCallback(promise);
-
- std::move(reject_cb).Run(foo);
-
- EXPECT_EQ(&promise->value().template Get<Rejected<int&>>()->value, &foo);
-}
-
-TEST(PromiseCallbackHelper, GetRepeatingResolveCallback) {
- PromiseCallbackHelper<int, int> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- RepeatingCallback<void(int)> resolve_cb =
- helper.GetRepeatingResolveCallback(promise);
-
- resolve_cb.Run(1234);
-
- EXPECT_EQ(promise->value().template Get<Resolved<int>>()->value, 1234);
-
- // Can't run |resolve_cb| more than once.
- EXPECT_DCHECK_DEATH({ resolve_cb.Run(1234); });
-}
-
-TEST(PromiseCallbackHelper, GetRepeatingResolveReferenceCallback) {
- int foo = 123;
- PromiseCallbackHelper<int&, int&> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
-
- RepeatingCallback<void(int&)> resolve_cb =
- helper.GetRepeatingResolveCallback(promise);
-
- resolve_cb.Run(foo);
-
- EXPECT_EQ(&promise->value().template Get<Resolved<int&>>()->value, &foo);
-
- // Can't run |resolve_cb| more than once.
- EXPECT_DCHECK_DEATH({ resolve_cb.Run(foo); });
-}
-
-TEST(PromiseCallbackHelper, GetRepeatingRejectCallback) {
- PromiseCallbackHelper<int, int> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
-
- RepeatingCallback<void(int)> reject_cb =
- helper.GetRepeatingRejectCallback(promise);
-
- reject_cb.Run(1234);
-
- EXPECT_EQ(promise->value().template Get<Rejected<int>>()->value, 1234);
-
- // Can't run |reject_cb| more than once.
- EXPECT_DCHECK_DEATH({ reject_cb.Run(1234); });
-}
-
-TEST(PromiseCallbackHelper, GetRepeatingRejectReferenceCallback) {
- int foo = 123;
- PromiseCallbackHelper<int&, int&> helper;
- scoped_refptr<AbstractPromise> promise =
- DoNothingPromiseBuilder(FROM_HERE).SetCanReject(true).SetRejectPolicy(
- RejectPolicy::kCatchNotRequired);
-
- RepeatingCallback<void(int&)> reject_cb =
- helper.GetRepeatingRejectCallback(promise);
-
- reject_cb.Run(foo);
-
- EXPECT_EQ(&promise->value().template Get<Rejected<int&>>()->value, &foo);
-
- // Can't run |reject_cb| more than once.
- EXPECT_DCHECK_DEATH({ reject_cb.Run(foo); });
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/no_op_promise_executor.cc b/task/promise/no_op_promise_executor.cc
deleted file mode 100644
index e168ed9..0000000
--- a/task/promise/no_op_promise_executor.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/no_op_promise_executor.h"
-#include "base/task_runner.h"
-
-namespace base {
-namespace internal {
-
-NoOpPromiseExecutor::NoOpPromiseExecutor(bool can_resolve, bool can_reject)
-#if DCHECK_IS_ON()
- : can_resolve_(can_resolve),
- can_reject_(can_reject)
-#endif
-{
-}
-
-NoOpPromiseExecutor::~NoOpPromiseExecutor() {}
-
-bool NoOpPromiseExecutor::IsCancelled() const {
- return false;
-}
-
-#if DCHECK_IS_ON()
-PromiseExecutor::ArgumentPassingType
-NoOpPromiseExecutor::ResolveArgumentPassingType() const {
- return PromiseExecutor::ArgumentPassingType::kNoCallback;
-}
-
-PromiseExecutor::ArgumentPassingType
-NoOpPromiseExecutor::RejectArgumentPassingType() const {
- return PromiseExecutor::ArgumentPassingType::kNoCallback;
-}
-
-bool NoOpPromiseExecutor::CanResolve() const {
- return can_resolve_;
-}
-
-bool NoOpPromiseExecutor::CanReject() const {
- return can_reject_;
-}
-#endif
-
-void NoOpPromiseExecutor::Execute(AbstractPromise* promise) {}
-
-// static
-PassedPromise NoOpPromiseExecutor::Create(Location from_here,
- bool can_resolve,
- bool can_reject,
- RejectPolicy reject_policy) {
- return PassedPromise(AbstractPromise::CreateNoPrerequisitePromise(
- from_here, reject_policy, DependentList::ConstructUnresolved(),
- PromiseExecutor::Data(in_place_type_t<NoOpPromiseExecutor>(), can_resolve,
- can_reject)));
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/no_op_promise_executor.h b/task/promise/no_op_promise_executor.h
deleted file mode 100644
index 13f8ef0..0000000
--- a/task/promise/no_op_promise_executor.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_NO_OP_PROMISE_EXECUTOR_H_
-#define BASE_TASK_PROMISE_NO_OP_PROMISE_EXECUTOR_H_
-
-#include "base/macros.h"
-#include "base/task/promise/abstract_promise.h"
-
-namespace base {
-namespace internal {
-
-// An Executor that doesn't do anything.
-class BASE_EXPORT NoOpPromiseExecutor {
- public:
- NoOpPromiseExecutor(bool can_resolve, bool can_reject);
-
- ~NoOpPromiseExecutor();
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- PromiseExecutor::PrerequisitePolicy::kNever;
-
- static PassedPromise Create(Location from_here,
- bool can_resolve,
- bool can_reject,
- RejectPolicy reject_policy);
-
- PromiseExecutor::PrerequisitePolicy GetPrerequisitePolicy() const;
- bool IsCancelled() const;
-
-#if DCHECK_IS_ON()
- PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const;
- PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const;
- bool CanResolve() const;
- bool CanReject() const;
-#endif
- void Execute(AbstractPromise* promise);
-
- private:
-#if DCHECK_IS_ON()
- bool can_resolve_;
- bool can_reject_;
-#endif
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_NO_OP_PROMISE_EXECUTOR_H_
diff --git a/task/promise/post_task_executor.h b/task/promise/post_task_executor.h
deleted file mode 100644
index e3882ba..0000000
--- a/task/promise/post_task_executor.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_POST_TASK_EXECUTOR_H_
-#define BASE_TASK_PROMISE_POST_TASK_EXECUTOR_H_
-
-#include "base/bind_helpers.h"
-#include "base/macros.h"
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/helpers.h"
-
-namespace base {
-namespace internal {
-
-// PromiseExecutor for use by PostTask.
-template <typename ReturnType>
-class PostTaskExecutor {
- public:
- // Extract properties from |ReturnType|.
- using CallbackTraits = PromiseCallbackTraits<ReturnType>;
- using ReturnedPromiseResolveT = typename CallbackTraits::ResolveType;
- using ReturnedPromiseRejectT = typename CallbackTraits::RejectType;
- using ResolveStorage = Resolved<ReturnedPromiseResolveT>;
- using RejectStorage = Rejected<ReturnedPromiseRejectT>;
-
- explicit PostTaskExecutor(CallbackBase&& task) noexcept
- : task_(std::move(task)) {}
-
- explicit PostTaskExecutor(DoNothing task) noexcept : task_(task.Once()) {}
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- PromiseExecutor::PrerequisitePolicy::kAll;
-
- bool IsCancelled() const { return task_.IsCancelled(); }
-
-#if DCHECK_IS_ON()
- PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const {
- return PromiseExecutor::ArgumentPassingType::kNoCallback;
- }
-
- PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const {
- return PromiseExecutor::ArgumentPassingType::kNoCallback;
- }
-
- bool CanResolve() const { return CallbackTraits::could_resolve; }
-
- bool CanReject() const { return CallbackTraits::could_reject; }
-#endif
-
- void Execute(AbstractPromise* promise) {
- static_assert(sizeof(CallbackBase) == sizeof(OnceCallback<ReturnType()>),
- "We assume it's possible to cast from CallbackBase to "
- "OnceCallback<ReturnType()>");
- // Internally RunHelper uses const RepeatingCallback<>& to avoid the
- // binary size overhead of moving a scoped_refptr<> about. We respect
- // the onceness of the callback and RunHelper will overwrite the callback
- // with the result.
- RepeatingCallback<ReturnType()>* task =
- static_cast<RepeatingCallback<ReturnType()>*>(&task_);
- internal::RunHelper<RepeatingCallback<ReturnType()>, void, ResolveStorage,
- RejectStorage>::Run(*task, nullptr, promise);
- }
-
- private:
- CallbackBase task_;
-
- DISALLOW_COPY_AND_ASSIGN(PostTaskExecutor);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_POST_TASK_EXECUTOR_H_
diff --git a/task/promise/post_task_executor_unittest.cc b/task/promise/post_task_executor_unittest.cc
deleted file mode 100644
index 1d3fc57..0000000
--- a/task/promise/post_task_executor_unittest.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/post_task_executor.h"
-
-#include "base/bind.h"
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/helpers.h"
-#include "base/task_runner.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace internal {
-
-class PostTaskExecutorTest : public testing::Test {
- public:
- template <typename CallbackT>
- WrappedPromise CreatePostTaskPromise(const Location& from_here,
- CallbackT&& task) {
- // Extract properties from |task| callback.
- using CallbackTraits = CallbackTraits<std::decay_t<CallbackT>>;
-
- internal::PromiseExecutor::Data executor_data(
- in_place_type_t<
- internal::PostTaskExecutor<typename CallbackTraits::ReturnType>>(),
- internal::ToCallbackBase(std::move(task)));
-
- return WrappedPromise(AbstractPromise::CreateNoPrerequisitePromise(
- from_here, RejectPolicy::kMustCatchRejection,
- internal::DependentList::ConstructUnresolved(),
- std::move(executor_data)));
- }
-};
-
-TEST_F(PostTaskExecutorTest, OnceClosure) {
- bool run = false;
-
- WrappedPromise p = CreatePostTaskPromise(
- FROM_HERE, BindOnce([](bool* run) { *run = true; }, &run));
-
- p.Execute();
-
- EXPECT_TRUE(run);
-}
-
-TEST_F(PostTaskExecutorTest, RepeatingClosure) {
- bool run = false;
-
- WrappedPromise p = CreatePostTaskPromise(
- FROM_HERE, BindRepeating([](bool* run) { *run = true; }, &run));
-
- p.Execute();
-
- EXPECT_TRUE(run);
-}
-
-TEST_F(PostTaskExecutorTest, DoNothing) {
- // Check it compiles and the executor doesn't crash when run.
- WrappedPromise p = CreatePostTaskPromise(FROM_HERE, DoNothing());
-
- p.Execute();
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/promise.h b/task/promise/promise.h
deleted file mode 100644
index 467f74c..0000000
--- a/task/promise/promise.h
+++ /dev/null
@@ -1,807 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_PROMISE_H_
-#define BASE_TASK_PROMISE_PROMISE_H_
-
-#include "base/run_loop.h"
-#include "base/task/promise/all_container_executor.h"
-#include "base/task/promise/all_tuple_executor.h"
-#include "base/task/promise/finally_executor.h"
-#include "base/task/promise/helpers.h"
-#include "base/task/promise/no_op_promise_executor.h"
-#include "base/task/promise/promise_result.h"
-#include "base/task/promise/then_and_catch_executor.h"
-#include "base/task/task_traits.h"
-
-namespace base {
-
-// We can't include post_task.h here so we forward declare it.
-BASE_EXPORT scoped_refptr<TaskRunner> CreateTaskRunner(
- const TaskTraits& traits);
-
-// Inspired by ES6 promises, Promise<> is a PostTask based callback system for
-// asynchronous operations. An operation can resolve (succeed) with a value and
-// optionally reject (fail) with a different result. Interested parties can be
-// notified using ThenOn() and CatchOn() which schedule callbacks to run as
-// appropriate on the specified task runner or task traits. If a promise is
-// settled when a ThenOn() / CatchOn() / FinallyOn() statement is added, the
-// callback will be posted immediately, otherwise it has to wait.
-//
-// Promise<> is copyable, moveable and thread safe. Under the hood
-// AbstractPromise is refcounted so retaining multiple Promises<> will
-// prevent that part of the promise graph from being released.
-template <typename ResolveType, typename RejectType = NoReject>
-class Promise : public internal::BasePromise {
- public:
- Promise() = default;
-
- static_assert(
- !std::is_reference<ResolveType>::value ||
- std::is_const<std::remove_reference_t<ResolveType>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- static_assert(
- !std::is_reference<RejectType>::value ||
- std::is_const<std::remove_reference_t<RejectType>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- explicit Promise(
- scoped_refptr<internal::AbstractPromise> abstract_promise) noexcept
- : BasePromise(std::move(abstract_promise)) {}
-
- // Every PostTask calls this constructor so we need to be careful to avoid
- // unnecessary binary bloat.
- explicit Promise(internal::PassedPromise passed_promise) noexcept
- : BasePromise(std::move(passed_promise),
- BasePromise::InlineConstructor()) {}
-
- ~Promise() = default;
-
- bool IsCancelledForTesting() const { return abstract_promise_->IsCanceled(); }
-
- // Waits until the promise has settled and if resolved it returns the resolved
- // value.
- template <typename T = ResolveType,
- std::enable_if_t<!std::is_reference<T>::value &&
- !std::is_void<T>::value>* = nullptr>
- T TakeResolveValueForTesting() {
- static_assert(!std::is_same<NoResolve, T>::value,
- "A NoResolve promise can't resolve.");
- if (!abstract_promise_->IsSettled()) {
- RunLoop run_loop;
- FinallyHere(FROM_HERE, run_loop.QuitClosure());
- run_loop.Run();
- }
- DCHECK(abstract_promise_->IsResolved())
- << "Can't take resolved value, promise wasn't resolved.";
- return std::move(abstract_promise_->TakeValue()
- .value()
- .template Get<Resolved<T>>()
- ->value);
- }
-
- // Waits until the promise has settled and if rejected it returns the rejected
- // value.
- template <typename T = RejectType,
- std::enable_if_t<!std::is_reference<T>::value &&
- !std::is_void<T>::value>* = nullptr>
- T TakeRejectValueForTesting() {
- static_assert(!std::is_same<NoReject, T>::value,
- "A NoReject promise can't reject.");
- if (!abstract_promise_->IsSettled()) {
- RunLoop run_loop;
- FinallyHere(FROM_HERE, run_loop.QuitClosure());
- run_loop.Run();
- }
- abstract_promise_->IgnoreUncaughtCatchForTesting();
- DCHECK(abstract_promise_->IsRejected())
- << "Can't take rejected value, promise wasn't rejected.";
- return std::move(abstract_promise_->TakeValue()
- .value()
- .template Get<Rejected<T>>()
- ->value);
- }
-
- bool IsResolvedForTesting() const {
- DCHECK(abstract_promise_);
- return abstract_promise_->IsResolvedForTesting();
- }
-
- bool IsRejectedForTesting() const {
- DCHECK(abstract_promise_);
- return abstract_promise_->IsRejectedForTesting();
- }
-
- // A task to execute |on_reject| is posted on |task_runner| as soon as this
- // promise (or an uncaught ancestor) is rejected. A Promise<> for the return
- // value of |on_reject| is returned.
- //
- // The following callback return types have special meanings:
- // 1. PromiseResult<Resolve, Reject> lets the callback resolve, reject or
- // curry a Promise<Resolve, Reject>
- // 2. Promise<Resolve, Reject> where the result is a curried promise.
- //
- // If a promise has multiple Catches they will be run in order of creation.
- //
- // |task_runner| is const-ref to avoid bloat due the destructor (which posts a
- // task).
- template <typename CatchCb>
- auto CatchOn(const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- CatchCb on_reject) noexcept {
- DCHECK(!on_reject.is_null());
-
- // Extract properties from the |on_reject| callback.
- using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
- using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
-
- // Compute the resolve and reject types of the returned Promise.
- using ReturnedPromiseTraits =
- internal::PromiseCombiner<ResolveType,
- NoReject, // We've caught the reject case.
- typename CatchCallbackTraits::ResolveType,
- typename CatchCallbackTraits::RejectType>;
- using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
- using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
-
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't catch a NoReject promise.");
-
- // Check we wouldn't need to return Promise<Variant<...>, ...>
- static_assert(ReturnedPromiseTraits::valid,
- "Ambiguous promise resolve type");
- static_assert(
- internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
- std::is_void<CatchCallbackArgT>::value,
- "|on_reject| callback must accept Promise::RejectType or void.");
-
- static_assert(
- !std::is_reference<CatchCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructAbstractPromiseWithSinglePrerequisite(
- task_runner, from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::ThenAndCatchExecutor<
- OnceClosure, // Never called.
- OnceCallback<typename CatchCallbackTraits::SignatureType>,
- internal::NoCallback, RejectType,
- Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- OnceClosure(),
- internal::ToCallbackBase(std::move(on_reject)))));
- }
-
- template <typename CatchCb>
- auto CatchOn(const TaskTraits& traits,
- const Location& from_here,
- CatchCb&& on_reject) noexcept {
- return CatchOn(CreateTaskRunner(traits), from_here,
- std::forward<CatchCb>(on_reject));
- }
-
- template <typename CatchCb>
- auto CatchHere(const Location& from_here, CatchCb&& on_reject) noexcept {
- DCHECK(!on_reject.is_null());
-
- // Extract properties from the |on_reject| callback.
- using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
- using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
-
- // Compute the resolve and reject types of the returned Promise.
- using ReturnedPromiseTraits =
- internal::PromiseCombiner<ResolveType,
- NoReject, // We've caught the reject case.
- typename CatchCallbackTraits::ResolveType,
- typename CatchCallbackTraits::RejectType>;
- using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
- using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
-
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't catch a NoReject promise.");
-
- // Check we wouldn't need to return Promise<Variant<...>, ...>
- static_assert(ReturnedPromiseTraits::valid,
- "Ambiguous promise resolve type");
- static_assert(
- internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
- std::is_void<CatchCallbackArgT>::value,
- "|on_reject| callback must accept Promise::RejectType or void.");
-
- static_assert(
- !std::is_reference<CatchCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructHereAbstractPromiseWithSinglePrerequisite(
- from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::ThenAndCatchExecutor<
- OnceClosure, // Never called.
- OnceCallback<typename CatchCallbackTraits::SignatureType>,
- internal::NoCallback, RejectType,
- Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- OnceClosure(),
- internal::ToCallbackBase(std::move(on_reject)))));
- }
-
- // A task to execute |on_resolve| is posted on |task_runner| as soon as this
- // promise (or an unhandled ancestor) is resolved. A Promise<> for the return
- // value of |on_resolve| is returned.
- //
- // The following callback return types have special meanings:
- // 1. PromiseResult<Resolve, Reject> lets the callback resolve, reject or
- // curry a Promise<Resolve, Reject>
- // 2. Promise<Resolve, Reject> where the result is a curried promise.
- //
- // If a promise has multiple Thens they will be run in order of creation.
- //
- // |task_runner| is const-ref to avoid bloat due the destructor (which posts a
- // task).
- template <typename ThenCb>
- auto ThenOn(const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- ThenCb on_resolve) noexcept {
- DCHECK(!on_resolve.is_null());
-
- // Extract properties from the |on_resolve| callback.
- using ThenCallbackTraits = internal::CallbackTraits<std::decay_t<ThenCb>>;
- using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
-
- // Compute the resolve and reject types of the returned Promise.
- using ReturnedPromiseTraits =
- internal::PromiseCombiner<NoResolve, // We've caught the resolve case.
- RejectType,
- typename ThenCallbackTraits::ResolveType,
- typename ThenCallbackTraits::RejectType>;
- using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
- using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
-
- // Check we wouldn't need to return Promise<..., Variant<...>>
- static_assert(ReturnedPromiseTraits::valid,
- "Ambiguous promise reject type");
-
- static_assert(
- internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
- std::is_void<ThenCallbackArgT>::value,
- "|on_resolve| callback must accept Promise::ResolveType or void.");
-
- static_assert(
- !std::is_reference<ThenCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructAbstractPromiseWithSinglePrerequisite(
- task_runner, from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::ThenAndCatchExecutor<
- OnceCallback<typename ThenCallbackTraits::SignatureType>,
- OnceClosure, ResolveType, internal::NoCallback,
- Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- internal::ToCallbackBase(std::move(on_resolve)),
- OnceClosure())));
- }
-
- template <typename ThenCb>
- auto ThenOn(const TaskTraits& traits,
- const Location& from_here,
- ThenCb&& on_resolve) noexcept {
- return ThenOn(CreateTaskRunner(traits), from_here,
- std::forward<ThenCb>(on_resolve));
- }
-
- template <typename ThenCb>
- auto ThenHere(const Location& from_here, ThenCb&& on_resolve) noexcept {
- DCHECK(!on_resolve.is_null());
-
- // Extract properties from the |on_resolve| callback.
- using ThenCallbackTraits = internal::CallbackTraits<std::decay_t<ThenCb>>;
- using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
-
- // Compute the resolve and reject types of the returned Promise.
- using ReturnedPromiseTraits =
- internal::PromiseCombiner<NoResolve, // We've caught the resolve case.
- RejectType,
- typename ThenCallbackTraits::ResolveType,
- typename ThenCallbackTraits::RejectType>;
- using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
- using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
-
- // Check we wouldn't need to return Promise<..., Variant<...>>
- static_assert(ReturnedPromiseTraits::valid,
- "Ambiguous promise reject type");
-
- static_assert(
- internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
- std::is_void<ThenCallbackArgT>::value,
- "|on_resolve| callback must accept Promise::ResolveType or void.");
-
- static_assert(
- !std::is_reference<ThenCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructHereAbstractPromiseWithSinglePrerequisite(
- from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::ThenAndCatchExecutor<
- OnceCallback<typename ThenCallbackTraits::SignatureType>,
- OnceClosure, ResolveType, internal::NoCallback,
- Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- internal::ToCallbackBase(std::move(on_resolve)),
- OnceClosure())));
- }
-
- // A task to execute |on_reject| is posted on |task_runner| as soon as this
- // promise (or an uncaught ancestor) is rejected. Likewise a task to execute
- // |on_resolve| is posted on |task_runner| as soon as this promise (or an
- // unhandled ancestor) is resolved. A Promise<> for the return value of
- // |on_resolve| or |on_reject| is returned.
- //
- // The following callback return types have special meanings:
- // 1. PromiseResult<Resolve, Reject> lets the callback resolve, reject or
- // curry a Promise<Resolve, Reject>
- // 2. Promise<Resolve, Reject> where the result is a curried promise.
- //
- // If a promise has multiple Catches/ Thens, they will be run in order of
- // creation.
- //
- // Note if either |on_resolve| or |on_reject| are canceled (due to weak
- // pointer invalidation), then the other must be canceled at the same time as
- // well. This restriction only applies to this form of ThenOn/ThenHere.
- //
- // |task_runner| is const-ref to avoid bloat due the destructor (which posts a
- // task).
- template <typename ThenCb, typename CatchCb>
- auto ThenOn(const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- ThenCb on_resolve,
- CatchCb on_reject) noexcept {
- DCHECK(!on_resolve.is_null());
- DCHECK(!on_reject.is_null());
-
- // Extract properties from the |on_resolve| and |on_reject| callbacks.
- using ThenCallbackTraits = internal::CallbackTraits<ThenCb>;
- using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
- using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
- using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
-
- // Compute the resolve and reject types of the returned Promise.
- using ReturnedPromiseTraits =
- internal::PromiseCombiner<typename ThenCallbackTraits::ResolveType,
- typename ThenCallbackTraits::RejectType,
- typename CatchCallbackTraits::ResolveType,
- typename CatchCallbackTraits::RejectType>;
- using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
- using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
-
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't catch a NoReject promise.");
-
- static_assert(ReturnedPromiseTraits::valid,
- "|on_resolve| callback and |on_resolve| callback must return "
- "compatible types.");
-
- static_assert(
- internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
- std::is_void<ThenCallbackArgT>::value,
- "|on_resolve| callback must accept Promise::ResolveType or void.");
-
- static_assert(
- internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
- std::is_void<CatchCallbackArgT>::value,
- "|on_reject| callback must accept Promise::RejectType or void.");
-
- static_assert(
- !std::is_reference<ThenCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- static_assert(
- !std::is_reference<CatchCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructAbstractPromiseWithSinglePrerequisite(
- task_runner, from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::ThenAndCatchExecutor<
- OnceCallback<typename ThenCallbackTraits::SignatureType>,
- OnceCallback<typename CatchCallbackTraits::SignatureType>,
- ResolveType, RejectType, Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- internal::ToCallbackBase(std::move(on_resolve)),
- internal::ToCallbackBase(std::move(on_reject)))));
- }
-
- template <typename ThenCb, typename CatchCb>
- auto ThenOn(const TaskTraits& traits,
- const Location& from_here,
- ThenCb on_resolve,
- CatchCb on_reject) noexcept {
- return ThenOn(CreateTaskRunner(traits), from_here,
- std::forward<ThenCb>(on_resolve),
- std::forward<CatchCb>(on_reject));
- }
-
- template <typename ThenCb, typename CatchCb>
- auto ThenHere(const Location& from_here,
- ThenCb on_resolve,
- CatchCb on_reject) noexcept {
- DCHECK(!on_resolve.is_null());
- DCHECK(!on_reject.is_null());
-
- // Extract properties from the |on_resolve| and |on_reject| callbacks.
- using ThenCallbackTraits = internal::CallbackTraits<ThenCb>;
- using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
- using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
- using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
-
- // Compute the resolve and reject types of the returned Promise.
- using ReturnedPromiseTraits =
- internal::PromiseCombiner<typename ThenCallbackTraits::ResolveType,
- typename ThenCallbackTraits::RejectType,
- typename CatchCallbackTraits::ResolveType,
- typename CatchCallbackTraits::RejectType>;
- using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
- using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
-
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't catch a NoReject promise.");
-
- static_assert(ReturnedPromiseTraits::valid,
- "|on_resolve| callback and |on_resolve| callback must return "
- "compatible types.");
-
- static_assert(
- internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
- std::is_void<ThenCallbackArgT>::value,
- "|on_resolve| callback must accept Promise::ResolveType or void.");
-
- static_assert(
- internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
- std::is_void<CatchCallbackArgT>::value,
- "|on_reject| callback must accept Promise::RejectType or void.");
-
- static_assert(
- !std::is_reference<ThenCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- static_assert(
- !std::is_reference<CatchCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
- "Google C++ Style: References in function parameters must be const.");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructHereAbstractPromiseWithSinglePrerequisite(
- from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::ThenAndCatchExecutor<
- OnceCallback<typename ThenCallbackTraits::SignatureType>,
- OnceCallback<typename CatchCallbackTraits::SignatureType>,
- ResolveType, RejectType, Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- internal::ToCallbackBase(std::move(on_resolve)),
- internal::ToCallbackBase(std::move(on_reject)))));
- }
-
- // A task to execute |finally_callback| on |task_runner| is posted after the
- // parent promise is resolved or rejected. |finally_callback| is not executed
- // if the parent promise is cancelled. Unlike the finally() in Javascript
- // promises, this doesn't return a Promise that is resolved or rejected with
- // the parent's value if |finally_callback| returns void. (We could support
- // this if needed it but it seems unlikely to be used).
- //
- // |task_runner| is const-ref to avoid bloat due the destructor (which posts a
- // task).
- template <typename FinallyCb>
- auto FinallyOn(const scoped_refptr<TaskRunner>& task_runner,
- const Location& from_here,
- FinallyCb finally_callback) noexcept {
- // Extract properties from |finally_callback| callback.
- using CallbackTraits = internal::CallbackTraits<FinallyCb>;
- using ReturnedPromiseResolveT = typename CallbackTraits::ResolveType;
- using ReturnedPromiseRejectT = typename CallbackTraits::RejectType;
-
- using CallbackArgT = typename CallbackTraits::ArgType;
- static_assert(std::is_void<CallbackArgT>::value,
- "|finally_callback| callback must have no arguments");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructAbstractPromiseWithSinglePrerequisite(
- task_runner, from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::FinallyExecutor<
- OnceCallback<typename CallbackTraits::ReturnType()>,
- Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- internal::ToCallbackBase(std::move(finally_callback)))));
- }
-
- template <typename FinallyCb>
- auto FinallyOn(const TaskTraits& traits,
- const Location& from_here,
- FinallyCb finally_callback) noexcept {
- return FinallyOn(CreateTaskRunner(traits), from_here,
- std::move(finally_callback));
- }
-
- template <typename FinallyCb>
- auto FinallyHere(const Location& from_here,
- FinallyCb finally_callback) noexcept {
- // Extract properties from |finally_callback| callback.
- using CallbackTraits = internal::CallbackTraits<FinallyCb>;
- using ReturnedPromiseResolveT = typename CallbackTraits::ResolveType;
- using ReturnedPromiseRejectT = typename CallbackTraits::RejectType;
-
- using CallbackArgT = typename CallbackTraits::ArgType;
- static_assert(std::is_void<CallbackArgT>::value,
- "|finally_callback| callback must have no arguments");
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- ConstructHereAbstractPromiseWithSinglePrerequisite(
- from_here, abstract_promise_.get(),
- internal::PromiseExecutor::Data(
- in_place_type_t<internal::FinallyExecutor<
- OnceCallback<typename CallbackTraits::ReturnType()>,
- Resolved<ReturnedPromiseResolveT>,
- Rejected<ReturnedPromiseRejectT>>>(),
- internal::ToCallbackBase(std::move(finally_callback)))));
- }
-
- template <typename... Args>
- NOINLINE static Promise<ResolveType, RejectType> CreateResolved(
- const Location& from_here,
- Args&&... args) noexcept {
- internal::PromiseExecutor::Data executor_data(
- in_place_type_t<internal::NoOpPromiseExecutor>(),
- /* can_resolve */ true,
- /* can_reject */ false);
-
- scoped_refptr<internal::AbstractPromise> promise(
- internal::AbstractPromise::Create(
- nullptr, from_here, nullptr, RejectPolicy::kMustCatchRejection,
- internal::DependentList::ConstructResolved(),
- std::move(executor_data)));
- promise->emplace(in_place_type_t<Resolved<ResolveType>>(),
- std::forward<Args>(args)...);
- return Promise<ResolveType, RejectType>(std::move(promise));
- }
-
- template <typename... Args>
- NOINLINE static Promise<ResolveType, RejectType> CreateRejected(
- const Location& from_here,
- Args&&... args) noexcept {
- internal::PromiseExecutor::Data executor_data(
- in_place_type_t<internal::NoOpPromiseExecutor>(),
- /* can_resolve */ false,
- /* can_reject */ true);
-
- scoped_refptr<internal::AbstractPromise> promise(
- internal::AbstractPromise::Create(
- nullptr, from_here, nullptr, RejectPolicy::kMustCatchRejection,
- internal::DependentList::ConstructResolved(),
- std::move(executor_data)));
- return Promise<ResolveType, RejectType>(std::move(promise));
- }
-
- using ResolveT = ResolveType;
- using RejectT = RejectType;
-
- void IgnoreUncaughtCatchForTesting() {
- abstract_promise_->IgnoreUncaughtCatchForTesting();
- }
-
- const scoped_refptr<internal::AbstractPromise>& GetScopedRefptrForTesting()
- const {
- return abstract_promise_;
- }
-
- private:
- template <typename A, typename B>
- friend class Promise;
-
- friend class Promises;
-
- template <typename A, typename B>
- friend class PromiseResult;
-
- template <typename Container, typename ContainerT>
- friend struct internal::AllContainerHelper;
-
- template <typename RejectStorage, typename ResultStorage>
- friend struct internal::EmplaceHelper;
-
- template <typename A, typename B>
- friend class ManualPromiseResolver;
-};
-
-// Used for manually resolving and rejecting a Promise. This is for
-// compatibility with old code and will eventually be removed.
-template <typename ResolveType, typename RejectType = NoReject>
-class ManualPromiseResolver {
- public:
- using ResolveHelper = std::conditional_t<
- std::is_void<ResolveType>::value,
- internal::PromiseCallbackHelper<void>,
- internal::PromiseCallbackHelper<ResolveType, ResolveType>>;
-
- using RejectHelper = std::conditional_t<
- std::is_void<RejectType>::value,
- internal::PromiseCallbackHelper<void>,
- internal::PromiseCallbackHelper<RejectType, RejectType>>;
-
- ManualPromiseResolver(
- const Location& from_here,
- RejectPolicy reject_policy = RejectPolicy::kMustCatchRejection) {
- promise_ = Promise<ResolveType, RejectType>(
- internal::ConstructManualPromiseResolverPromise(
- from_here, reject_policy,
- /* can_resolve */ !std::is_same<ResolveType, NoResolve>::value,
- /* can_reject */ !std::is_same<RejectType, NoReject>::value));
- }
-
- ~ManualPromiseResolver() = default;
-
- void Resolve(Promise<ResolveType, RejectType> promise) noexcept {
- promise_.abstract_promise_->emplace(std::move(promise.abstract_promise_));
- promise_.abstract_promise_->OnResolved();
- }
-
- template <typename... Args>
- void Resolve(Args&&... arg) noexcept {
- DCHECK(!promise_.abstract_promise_->IsSettled());
- static_assert(!std::is_same<NoResolve, ResolveType>::value,
- "Can't resolve a NoResolve promise.");
- promise_.abstract_promise_->emplace(
- Resolved<ResolveType>{std::forward<Args>(arg)...});
- promise_.abstract_promise_->OnResolved();
- }
-
- template <typename... Args>
- void Reject(Args&&... arg) noexcept {
- DCHECK(!promise_.abstract_promise_->IsSettled());
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't reject a NoReject promise.");
- promise_.abstract_promise_->emplace(
- Rejected<RejectType>{std::forward<Args>(arg)...});
- promise_.abstract_promise_->OnRejected();
- }
-
- typename ResolveHelper::Callback GetResolveCallback() {
- static_assert(!std::is_same<ResolveType, NoResolve>::value,
- "Cant resolve a NoResolve promise");
- return ResolveHelper::GetResolveCallback(promise_.abstract_promise_);
- }
-
- template <typename... Args>
- auto GetResolveCallback() {
- static_assert(!std::is_same<ResolveType, NoResolve>::value,
- "Cant resolve a NoResolve promise");
- using Helper = internal::PromiseCallbackHelper<ResolveType, Args...>;
- return Helper::GetResolveCallback(promise_.abstract_promise_);
- }
-
- typename ResolveHelper::RepeatingCallback GetRepeatingResolveCallback() {
- static_assert(!std::is_same<ResolveType, NoResolve>::value,
- "Cant resolve a NoResolve promise");
- return ResolveHelper::GetRepeatingResolveCallback(
- promise_.abstract_promise_);
- }
-
- template <typename... Args>
- auto GetRepeatingResolveCallback() {
- static_assert(!std::is_same<ResolveType, NoResolve>::value,
- "Cant resolve a NoResolve promise");
- using Helper = internal::PromiseCallbackHelper<ResolveType, Args...>;
- return Helper::GetRepeatingResolveCallback(promise_.abstract_promise_);
- }
-
- typename RejectHelper::Callback GetRejectCallback() {
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't reject a NoReject promise.");
- return RejectHelper::GetRejectCallback(promise_.abstract_promise_);
- }
-
- template <typename... Args>
- auto GetRejectCallback() {
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't reject a NoReject promise.");
- using Helper = internal::PromiseCallbackHelper<RejectType, Args...>;
- return Helper::GetRejectCallback(promise_.abstract_promise_);
- }
-
- typename RejectHelper::RepeatingCallback GetRepeatingRejectCallback() {
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't reject a NoReject promise.");
- return RejectHelper::GetRepeatingRejectCallback(promise_.abstract_promise_);
- }
-
- template <typename... Args>
- auto GetRepeatingRejectCallback() {
- static_assert(!std::is_same<NoReject, RejectType>::value,
- "Can't reject a NoReject promise.");
- using Helper = internal::PromiseCallbackHelper<RejectType, Args...>;
- return Helper::GetRepeatingRejectCallback(promise_.abstract_promise_);
- }
-
- Promise<ResolveType, RejectType>& promise() { return promise_; }
-
- private:
- Promise<ResolveType, RejectType> promise_;
-};
-
-class Promises {
- public:
- // Accepts a container of Promise<Resolve, Reject> and returns a
- // Promise<std::vector<Resolve>, Reject>. This is resolved when all
- // prerequisite promises are resolved returning a vector of all the Resolve
- // values, or rejects with the Reject value of the first promise to do so.
- //
- // TODO(alexclarke): Maybe support a container of Variants of promises.
- template <typename Container>
- static auto All(const Location& from_here, const Container& promises) {
- using PromissType = typename internal::AllContainerHelper<
- Container, typename Container::value_type>::PromiseType;
- if (promises.empty())
- return PromissType::CreateResolved(from_here);
- return internal::AllContainerHelper<
- Container, typename Container::value_type>::All(from_here, promises);
- }
-
- // Accepts one or more promises and returns a
- // Promise<std::tuple<Resolve> ...>, Reject> which is resolved when all
- // promises resolve or rejects with the Reject value of the first promise to
- // do so.
- //
- // TODO(alexclarke): Support multiple Reject types via variants.
- template <typename... Resolve, typename Reject>
- static auto All(const Location& from_here,
- Promise<Resolve, Reject>... promises) {
- using ReturnedPromiseResolveT =
- std::tuple<internal::ToNonVoidT<Resolve>...>;
- using ReturnedPromiseRejectT = Reject;
-
- std::vector<internal::DependentList::Node> prerequisite_list(
- sizeof...(promises));
- int i = 0;
- for (auto&& p : {promises.abstract_promise_.get()...}) {
- prerequisite_list[i++].SetPrerequisite(p);
- }
-
- internal::PromiseExecutor::Data executor_data(
- (in_place_type_t<internal::AllTuplePromiseExecutor<
- ReturnedPromiseResolveT, ReturnedPromiseRejectT>>()));
-
- return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
- internal::AbstractPromise::Create(
- nullptr, from_here,
- std::make_unique<internal::AbstractPromise::AdjacencyList>(
- std::move(prerequisite_list)),
- RejectPolicy::kMustCatchRejection,
- internal::DependentList::ConstructUnresolved(),
- std::move(executor_data)));
- }
-
- template <typename Resolve, typename Reject>
- static Promise<Resolve, Reject> All(const Location& from_here,
- Promise<Resolve, Reject> promise) {
- return promise;
- }
-};
-
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_PROMISE_H_
diff --git a/task/promise/promise_executor.cc b/task/promise/promise_executor.cc
deleted file mode 100644
index e9269af..0000000
--- a/task/promise/promise_executor.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/promise_executor.h"
-
-namespace base {
-namespace internal {
-
-PromiseExecutor::~PromiseExecutor() {
- if (data_.vtable_)
- data_.vtable_->destructor(data_.storage_.array);
- data_.vtable_ = nullptr;
-}
-
-#if DCHECK_IS_ON()
-PromiseExecutor::ArgumentPassingType
-PromiseExecutor::ResolveArgumentPassingType() const {
- return data_.vtable_->resolve_argument_passing_type(data_.storage_.array);
-}
-
-PromiseExecutor::ArgumentPassingType
-PromiseExecutor::RejectArgumentPassingType() const {
- return data_.vtable_->reject_argument_passing_type(data_.storage_.array);
-}
-
-bool PromiseExecutor::CanResolve() const {
- return data_.vtable_->can_resolve(data_.storage_.array);
-}
-
-bool PromiseExecutor::CanReject() const {
- return data_.vtable_->can_reject(data_.storage_.array);
-}
-#endif
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/promise_executor.h b/task/promise/promise_executor.h
deleted file mode 100644
index d0f3025..0000000
--- a/task/promise/promise_executor.h
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_PROMISE_EXECUTOR_H_
-#define BASE_TASK_PROMISE_PROMISE_EXECUTOR_H_
-
-#include "base/base_export.h"
-#include "base/logging.h"
-#include "base/task/promise/promise_value.h"
-
-namespace base {
-namespace internal {
-class AbstractPromise;
-
-// Unresolved promises have an executor which invokes one of the callbacks
-// associated with the promise. Once the callback has been invoked the
-// Executor is destroyed.
-//
-// Ideally Executor would be a pure virtual class, but we want to store these
-// inline to reduce the number of memory allocations (small object
-// optimization). The problem is even though placement new returns the same
-// address it was allocated at, you have to use the returned pointer. Casting
-// the buffer to the derived class is undefined behavior. STL implementations
-// usually store an extra pointer, but there we have opted for implementing
-// our own VTable to save a little bit of memory.
-class BASE_EXPORT PromiseExecutor {
- private:
- static constexpr size_t MaxSize = sizeof(void*) * 2;
- struct VTable;
-
- public:
- // We could just construct Executor in place, but that means templates need
- // to inline the AbstractPromise constructor which we'd like to avoid due to
- // binary size concerns. Despite containing refcounted objects, Data is
- // intended to be memcopied into the Executor and it deliberately does not
- // have a destructor. The type erasure provided by Executor allows us to
- // move the AbstractPromise construction out of line.
- class Data {
- public:
- // Constructs |Derived| in place.
- template <typename Derived, typename... Args>
- explicit Data(in_place_type_t<Derived>, Args&&... args) {
- static_assert(sizeof(Derived) <= MaxSize, "Derived is too big");
- static_assert(
- sizeof(PromiseExecutor) <= sizeof(PromiseValueInternal::InlineAlloc),
- "Executor is too big");
- vtable_ = &VTableHelper<Derived>::vtable_;
- new (storage_.array) Derived(std::forward<Args>(args)...);
- }
-
- Data(Data&& other) noexcept
- : vtable_(other.vtable_), storage_(other.storage_) {
-#if DCHECK_IS_ON()
- other.vtable_ = nullptr;
-#endif
- }
-
- Data(const Data& other) = delete;
-
- ~Data() { DCHECK_EQ(vtable_, nullptr); }
-
- private:
- friend class PromiseExecutor;
-
- const VTable* vtable_;
- struct {
- char array[MaxSize];
- } storage_;
- };
-
- // Caution it's an error to use |data| after this.
- explicit PromiseExecutor(Data&& data) : data_(std::move(data)) {}
-
- PromiseExecutor(PromiseExecutor&& other) noexcept
- : data_(std::move(other.data_)) {
- other.data_.vtable_ = nullptr;
- }
-
- PromiseExecutor(const PromiseExecutor& other) = delete;
-
- ~PromiseExecutor();
-
- PromiseExecutor& operator=(const PromiseExecutor& other) = delete;
-
- // Controls whether or not a promise should wait for its prerequisites
- // before becoming eligible for execution.
- enum class PrerequisitePolicy : uint8_t {
- // Wait for all prerequisites to resolve (or any to reject) before
- // becoming eligible for execution. If any prerequisites are canceled it
- // will be canceled too.
- kAll,
-
- // Wait for any prerequisite to resolve or reject before becoming eligible
- // for execution. If all prerequisites are canceled it will be canceled
- // too.
- kAny,
-
- // Never become eligible for execution. Cancellation is ignored.
- kNever,
- };
-
- // Returns the associated PrerequisitePolicy.
- PrerequisitePolicy GetPrerequisitePolicy() const {
- return data_.vtable_->prerequsite_policy;
- }
-
- // NB if there is both a resolve and a reject executor we require them to
- // be both canceled at the same time.
- bool IsCancelled() const {
- return data_.vtable_->is_cancelled(data_.storage_.array);
- }
-
- // Describes an executor callback.
- enum class ArgumentPassingType : uint8_t {
- // No callback. E.g. the RejectArgumentPassingType in a promise with a
- // resolve callback but no reject callback.
- kNoCallback,
-
- // Executor callback argument passed by value or by reference.
- kNormal,
-
- // Executor callback argument passed by r-value reference.
- kMove,
- };
-
-#if DCHECK_IS_ON()
- // Returns details of the resolve and reject executor callbacks if any. This
- // data is used to diagnose double moves and missing catches.
- ArgumentPassingType ResolveArgumentPassingType() const;
- ArgumentPassingType RejectArgumentPassingType() const;
- bool CanResolve() const;
- bool CanReject() const;
-#endif
-
- // Invokes the associate callback for |promise|. If the callback was
- // cancelled it should call |promise->OnCanceled()|. If the callback
- // resolved it should store the resolve result via |promise->emplace()|. If
- // the callback was rejected it should store the reject result in
- // |promise->state()|. Caution the Executor will be destructed when
- // |promise->state()| is written to.
- void Execute(AbstractPromise* promise) {
- return data_.vtable_->execute(data_.storage_.array, promise);
- }
-
- private:
- struct VTable {
- void (*destructor)(void* self);
- PrerequisitePolicy prerequsite_policy;
- bool (*is_cancelled)(const void* self);
-#if DCHECK_IS_ON()
- ArgumentPassingType (*resolve_argument_passing_type)(const void* self);
- ArgumentPassingType (*reject_argument_passing_type)(const void* self);
- bool (*can_resolve)(const void* self);
- bool (*can_reject)(const void* self);
-#endif
- void (*execute)(void* self, AbstractPromise* promise);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(VTable);
- };
-
- template <typename DerivedType>
- struct VTableHelper {
- VTableHelper(const VTableHelper& other) = delete;
- VTableHelper& operator=(const VTableHelper& other) = delete;
-
- static void Destructor(void* self) {
- static_cast<DerivedType*>(self)->~DerivedType();
- }
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- DerivedType::kPrerequisitePolicy;
-
- static PrerequisitePolicy GetPrerequisitePolicy(const void* self) {
- return static_cast<const DerivedType*>(self)->GetPrerequisitePolicy();
- }
-
- static bool IsCancelled(const void* self) {
- return static_cast<const DerivedType*>(self)->IsCancelled();
- }
-
-#if DCHECK_IS_ON()
- static ArgumentPassingType ResolveArgumentPassingType(const void* self) {
- return static_cast<const DerivedType*>(self)
- ->ResolveArgumentPassingType();
- }
-
- static ArgumentPassingType RejectArgumentPassingType(const void* self) {
- return static_cast<const DerivedType*>(self)->RejectArgumentPassingType();
- }
-
- static bool CanResolve(const void* self) {
- return static_cast<const DerivedType*>(self)->CanResolve();
- }
-
- static bool CanReject(const void* self) {
- return static_cast<const DerivedType*>(self)->CanReject();
- }
-#endif
-
- static void Execute(void* self, AbstractPromise* promise) {
- return static_cast<DerivedType*>(self)->Execute(promise);
- }
-
- static constexpr VTable vtable_ = {
- &VTableHelper::Destructor,
- VTableHelper::kPrerequisitePolicy,
- &VTableHelper::IsCancelled,
-#if DCHECK_IS_ON()
- &VTableHelper::ResolveArgumentPassingType,
- &VTableHelper::RejectArgumentPassingType,
- &VTableHelper::CanResolve,
- &VTableHelper::CanReject,
-#endif
- &VTableHelper::Execute,
- };
- };
-
- Data data_;
-};
-
-// static
-template <typename T>
-const PromiseExecutor::VTable PromiseExecutor::VTableHelper<T>::vtable_;
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_PROMISE_EXECUTOR_H_
diff --git a/task/promise/promise_result.h b/task/promise/promise_result.h
deleted file mode 100644
index aef6e3a..0000000
--- a/task/promise/promise_result.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_PROMISE_RESULT_H_
-#define BASE_TASK_PROMISE_PROMISE_RESULT_H_
-
-#include <type_traits>
-
-#include "base/task/promise/promise_value.h"
-
-namespace base {
-
-// An optional return type from a promise callback, which allows the callback to
-// decide whether or not it should reject. E.g.
-//
-// enum class Error { kReason };
-//
-// PromiseResult<int, Error> MyFn() {
-// int result;
-// ...
-// if (error)
-// return Error::kReason;
-// return result;
-// }
-//
-// If ResolveType and RejectType are distinct PromiseResult's constructor will
-// accept them. E.g.
-//
-// PromiseResult<int, std::string> pr(123); // Resolve
-// PromiseResult<int, std::string> pr("whoops"); // Reject
-//
-// If ResolveType and RejectType are the same you need to use Resolved<> and
-// Rejected<> to disambiguate. E.g.
-//
-// PromiseResult<int, int> pr(Resolved{123}); // Resolve
-// PromiseResult<int, int> pr(Rejected{123}); // Reject
-//
-// PromiseResult<ResolveType, RejectType> has a constructor that accepts
-// Promise<ResolveType, RejectType>.
-template <typename ResolveType, typename RejectType = NoReject>
-class PromiseResult {
- public:
- template <typename ResolveT = ResolveType,
- typename RejectT = RejectType,
- class Enable = std::enable_if<std::is_void<ResolveT>::value ^
- std::is_void<RejectT>::value>>
- PromiseResult() : PromiseResult(typename Analyze<void>::TagType()) {}
-
- template <typename T>
- PromiseResult(T&& t)
- : PromiseResult(typename Analyze<std::decay_t<T>>::TagType(),
- std::forward<T>(t)) {}
-
- PromiseResult(PromiseResult&& other) noexcept = default;
-
- PromiseResult(const PromiseResult&) = delete;
- PromiseResult& operator=(const PromiseResult&) = delete;
-
- internal::PromiseValue& value() { return value_; }
-
- private:
- struct IsWrapped {};
- struct IsResolved {};
- struct IsRejected {};
- struct IsPromise {};
-
- // Helper that assigns one of the above tags for |T|.
- template <typename T>
- struct Analyze {
- using DecayedT = std::decay_t<T>;
-
- static constexpr bool is_resolve =
- std::is_convertible<DecayedT, std::decay_t<ResolveType>>::value;
-
- static constexpr bool is_reject =
- std::is_convertible<DecayedT, std::decay_t<RejectType>>::value;
-
- static_assert(!is_reject || !std::is_same<DecayedT, NoReject>::value,
- "A NoReject promise can't reject");
-
- static_assert(!std::is_same<std::decay_t<ResolveType>,
- std::decay_t<RejectType>>::value,
- "Ambiguous because ResolveType and RejectType are the same");
-
- static_assert(is_resolve || is_reject,
- "Argument matches neither resolve nor reject type.");
-
- static_assert(
- is_resolve != is_reject && (is_resolve || is_reject),
- "Ambiguous because argument matches both ResolveType and RejectType");
-
- using TagType = std::conditional_t<is_resolve, IsResolved, IsRejected>;
- };
-
- template <typename T>
- struct Analyze<Resolved<T>> {
- using TagType = IsWrapped;
- static_assert(std::is_same<ResolveType, T>::value,
- "T in Resolved<T> is not ResolveType");
- };
-
- template <typename T>
- struct Analyze<Rejected<T>> {
- static_assert(std::is_same<RejectType, T>::value,
- "T in Rejected<T> is not RejectType");
-
- static_assert(!std::is_same<RejectType, NoReject>::value,
- "A NoReject promise can't reject");
- using TagType = IsWrapped;
- };
-
- template <typename ResolveT, typename RejectT>
- struct Analyze<Promise<ResolveT, RejectT>> {
- using TagType = IsPromise;
-
- static_assert(std::is_same<ResolveT, ResolveType>::value,
- "Promise resolve types don't match");
-
- static_assert(std::is_same<RejectT, RejectType>::value,
- "Promise reject types don't match");
- };
-
- template <typename... Args>
- PromiseResult(IsResolved, Args&&... args)
- : value_(in_place_type_t<Resolved<ResolveType>>(),
- std::forward<Args>(args)...) {}
-
- template <typename... Args>
- PromiseResult(IsRejected, Args&&... args)
- : value_(in_place_type_t<Rejected<RejectType>>(),
- std::forward<Args>(args)...) {}
-
- PromiseResult(IsPromise, const Promise<ResolveType, RejectType>& promise)
- : value_(promise.abstract_promise_) {}
-
- template <typename T>
- PromiseResult(IsWrapped, T&& t) : value_(std::forward<T>(t)) {}
-
- internal::PromiseValue value_;
-};
-
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_PROMISE_RESULT_H_
diff --git a/task/promise/promise_unittest.cc b/task/promise/promise_unittest.cc
deleted file mode 100644
index d81adac..0000000
--- a/task/promise/promise_unittest.cc
+++ /dev/null
@@ -1,2391 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/promise.h"
-
-#include <memory>
-#include <string>
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
-#include "base/test/do_nothing_promise.h"
-#include "base/test/gtest_util.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAre;
-
-namespace base {
-namespace {
-
-void RecordOrder(std::vector<int>* run_order, int order) {
- run_order->push_back(order);
-}
-
-class ObjectToDelete : public RefCounted<ObjectToDelete> {
- public:
- // |delete_flag| is set to true when this object is deleted
- ObjectToDelete(bool* delete_flag) : delete_flag_(delete_flag) {
- EXPECT_FALSE(*delete_flag_);
- }
-
- private:
- friend class RefCounted<ObjectToDelete>;
- ~ObjectToDelete() { *delete_flag_ = true; }
-
- bool* const delete_flag_;
-
- DISALLOW_COPY_AND_ASSIGN(ObjectToDelete);
-};
-
-class MockObject {
- public:
- MockObject() = default;
-
- void Task(scoped_refptr<ObjectToDelete>) {}
- void Reply(scoped_refptr<ObjectToDelete>) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockObject);
-};
-
-struct DummyError {};
-
-struct Cancelable {
- Cancelable() {}
-
- void LogTask(std::vector<std::string>* log, std::string value) {
- log->push_back(value);
- }
-
- void NopTask() {}
-
- WeakPtrFactory<Cancelable> weak_ptr_factory{this};
-};
-
-} // namespace
-
-class PromiseTest : public testing::Test {
- public:
- test::TaskEnvironment task_environment_;
-};
-
-TEST(PromiseMemoryLeakTest, TargetTaskRunnerClearsTasks) {
- scoped_refptr<TestMockTimeTaskRunner> post_runner =
- MakeRefCounted<TestMockTimeTaskRunner>();
- scoped_refptr<TestMockTimeTaskRunner> reply_runner =
- MakeRefCounted<TestMockTimeTaskRunner>(
- TestMockTimeTaskRunner::Type::kBoundToThread);
- MockObject mock_object;
- bool delete_task_flag = false;
- bool delete_reply_flag = false;
-
- Promise<int>::CreateResolved(FROM_HERE, 42)
- .ThenOn(post_runner, FROM_HERE,
- BindOnce(&MockObject::Task, Unretained(&mock_object),
- MakeRefCounted<ObjectToDelete>(&delete_task_flag)))
- .ThenHere(FROM_HERE,
- BindOnce(&MockObject::Reply, Unretained(&mock_object),
- MakeRefCounted<ObjectToDelete>(&delete_reply_flag)));
-
- post_runner->ClearPendingTasks();
-
- post_runner = nullptr;
- reply_runner = nullptr;
-
- EXPECT_TRUE(delete_task_flag);
- EXPECT_TRUE(delete_reply_flag);
-}
-
-TEST(PromiseMemoryLeakTest, GetResolveCallbackNeverRun) {
- test::TaskEnvironment task_environment_;
- OnceCallback<void(int)> cb;
- MockObject mock_object;
- bool delete_task_flag = false;
-
- {
- ManualPromiseResolver<int> p(FROM_HERE);
- cb = p.GetResolveCallback();
-
- p.promise().ThenHere(
- FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
- MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
- }
-
- EXPECT_FALSE(delete_task_flag);
- cb = OnceCallback<void(int)>();
- EXPECT_TRUE(delete_task_flag);
-}
-
-TEST(PromiseMemoryLeakTest, GetRepeatingResolveCallbackNeverRun) {
- test::TaskEnvironment task_environment_;
- RepeatingCallback<void(int)> cb;
- MockObject mock_object;
- bool delete_task_flag = false;
-
- {
- ManualPromiseResolver<int> p(FROM_HERE);
- cb = p.GetRepeatingResolveCallback();
-
- p.promise().ThenHere(
- FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
- MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
- }
-
- EXPECT_FALSE(delete_task_flag);
- cb = RepeatingCallback<void(int)>();
- EXPECT_TRUE(delete_task_flag);
-}
-
-TEST(PromiseMemoryLeakTest, GetRejectCallbackNeverRun) {
- test::TaskEnvironment task_environment_;
- OnceCallback<void(int)> cb;
- MockObject mock_object;
- bool delete_task_flag = false;
-
- {
- ManualPromiseResolver<void, int> p(FROM_HERE);
- cb = p.GetRejectCallback();
-
- p.promise().CatchHere(
- FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
- MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
- }
-
- EXPECT_FALSE(delete_task_flag);
- cb = OnceCallback<void(int)>();
- EXPECT_TRUE(delete_task_flag);
-}
-
-TEST(PromiseMemoryLeakTest, GetRepeatingRejectCallbackNeverRun) {
- test::TaskEnvironment task_environment_;
- RepeatingCallback<void(int)> cb;
- MockObject mock_object;
- bool delete_task_flag = false;
-
- {
- ManualPromiseResolver<void, int> p(FROM_HERE);
- cb = p.GetRepeatingRejectCallback();
-
- p.promise().CatchHere(
- FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
- MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
- }
-
- EXPECT_FALSE(delete_task_flag);
- cb = RepeatingCallback<void(int)>();
- EXPECT_TRUE(delete_task_flag);
-}
-
-TEST_F(PromiseTest, GetResolveCallbackThen) {
- ManualPromiseResolver<int> p(FROM_HERE);
- p.GetResolveCallback().Run(123);
-
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, GetResolveCallbackThenWithConstInt) {
- ManualPromiseResolver<int> p(FROM_HERE);
- p.GetResolveCallback().Run(123);
-
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE, BindLambdaForTesting([&](const int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, GetResolveCallbackMultipleArgs) {
- ManualPromiseResolver<std::tuple<int, bool, float>> p(FROM_HERE);
- static_assert(
- std::is_same<OnceCallback<void(int, bool, float)>,
- decltype(p.GetResolveCallback<int, bool, float>())>::value,
- "");
- p.GetResolveCallback<int, bool, float>().Run(123, true, 1.5f);
-
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE,
- BindLambdaForTesting([&](int a, bool b, float c) {
- EXPECT_EQ(123, a);
- EXPECT_TRUE(b);
- EXPECT_EQ(1.5f, c);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverCallbackLifetimeCanOutliveParent) {
- OnceCallback<void(int)> resolve_cb;
-
- RunLoop run_loop;
- {
- ManualPromiseResolver<int> p(FROM_HERE);
- resolve_cb = p.GetResolveCallback();
-
- p.promise().ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
- }
-
- std::move(resolve_cb).Run(123);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveWithTuple) {
- ManualPromiseResolver<void> p(FROM_HERE);
- p.Resolve();
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindOnce([]() { return std::tuple<int, bool>(123, false); }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](const std::tuple<int, bool>& tuple) {
- EXPECT_EQ(123, std::get<0>(tuple));
- EXPECT_FALSE(std::get<1>(tuple));
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveWithUnpackedTuple) {
- ManualPromiseResolver<void> p(FROM_HERE);
- p.Resolve();
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindOnce([]() { return std::tuple<int, bool>(123, false); }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int a, bool b) {
- EXPECT_EQ(123, a);
- EXPECT_FALSE(b);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveWithUnpackedTupleMoveOnlyTypes) {
- ManualPromiseResolver<void> p(FROM_HERE);
- p.Resolve();
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([]() {
- return std::make_tuple(std::make_unique<int>(42),
- std::make_unique<float>(4.2f));
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](std::unique_ptr<int> a,
- std::unique_ptr<float> b) {
- EXPECT_EQ(42, *a);
- EXPECT_EQ(4.2f, *b);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, GetRejectCallbackCatch) {
- ManualPromiseResolver<int, std::string> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&](int result) {
- run_loop.Quit();
- FAIL() << "We shouldn't get here, the promise was rejected!";
- }),
- BindLambdaForTesting([&](const std::string& err) {
- run_loop.Quit();
- EXPECT_EQ("Oh no!", err);
- }));
-
- p.GetRejectCallback().Run(std::string("Oh no!"));
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, GetRepeatingResolveCallbackThen) {
- ManualPromiseResolver<int> p(FROM_HERE);
- p.GetRepeatingResolveCallback().Run(123);
-
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, GetRepeatingRejectCallbackCatch) {
- ManualPromiseResolver<int, std::string> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&](int result) {
- run_loop.Quit();
- FAIL() << "We shouldn't get here, the promise was rejected!";
- }),
- BindLambdaForTesting([&](const std::string& err) {
- run_loop.Quit();
- EXPECT_EQ("Oh no!", err);
- }));
-
- p.GetRepeatingRejectCallback().Run(std::string("Oh no!"));
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CreateResolvedThen) {
- RunLoop run_loop;
- Promise<int>::CreateResolved(FROM_HERE, 123)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenRejectWithTuple) {
- ManualPromiseResolver<void> p(FROM_HERE);
- p.Resolve();
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([]() {
- return Rejected<std::tuple<int, bool>>{123, false};
- }))
- .CatchHere(FROM_HERE,
- BindLambdaForTesting([&](const std::tuple<int, bool>& tuple) {
- EXPECT_EQ(123, std::get<0>(tuple));
- EXPECT_FALSE(std::get<1>(tuple));
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverMultipleArgs) {
- ManualPromiseResolver<int, std::tuple<bool, std::string>> p(FROM_HERE);
- p.GetRejectCallback<bool, std::string>().Run(false, "Noes!");
- std::tuple<bool, std::string> err = p.promise().TakeRejectValueForTesting();
- EXPECT_FALSE(std::get<0>(err));
- EXPECT_EQ("Noes!", std::get<1>(err));
-}
-
-TEST_F(PromiseTest, GetRejectCallbackMultipleArgs) {
- ManualPromiseResolver<int, std::tuple<bool, std::string>> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&](int result) {
- run_loop.Quit();
- FAIL() << "We shouldn't get here, the promise was rejected!";
- }),
- BindLambdaForTesting([&](const std::tuple<bool, std::string>& err) {
- // NB we don't currently support tuple expansion for reject.
- // Its not hard to add, but it's unclear if it will ever be used.
- run_loop.Quit();
- EXPECT_FALSE(std::get<0>(err));
- EXPECT_EQ("Noes!", std::get<1>(err));
- }));
-
- p.GetRejectCallback<bool, std::string>().Run(false, "Noes!");
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CatchHereReturnTypes) {
- ManualPromiseResolver<int, void> p1(FROM_HERE);
-
- // Check CatchHere returns the expected return types for various
- // return types.
- Promise<int> r1 =
- p1.promise().CatchHere(FROM_HERE, BindOnce([]() { return 123; }));
- Promise<int> r2 = p1.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Resolved<int>(123); }));
- Promise<int, int> r3 = p1.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Rejected<int>(123); }));
-
- Promise<int, void> r4 = p1.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return PromiseResult<int, void>(123.0); }));
- Promise<int> r5 = p1.promise().CatchHere(
- FROM_HERE,
- BindOnce([]() { return PromiseResult<int, NoReject>(123.0); }));
- Promise<int, int> r6 = p1.promise().CatchHere(
- FROM_HERE,
- BindOnce([]() { return PromiseResult<NoResolve, int>(123.0); }));
-
- Promise<int, void> r7 = p1.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Promise<int, void>(); }));
- Promise<int> r8 = p1.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Promise<int, NoReject>(); }));
- Promise<int, int> r9 = p1.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Promise<NoResolve, int>(); }));
-
- ManualPromiseResolver<NoResolve, void> p2(FROM_HERE);
- Promise<int> r10 =
- p2.promise().CatchHere(FROM_HERE, BindOnce([]() { return 123; }));
- Promise<int> r11 = p2.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Resolved<int>(123); }));
- Promise<NoResolve, int> r12 = p2.promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Rejected<int>(123); }));
-}
-
-TEST_F(PromiseTest, ThenHereReturnTypes) {
- ManualPromiseResolver<std::string, void> p1(FROM_HERE);
-
- // Check ThenHere returns the expected return types for various
- // return types.
- Promise<int, void> r1 =
- p1.promise().ThenHere(FROM_HERE, BindOnce([]() { return 123; }));
- Promise<int, void> r2 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<int>(123); }));
- Promise<NoResolve, void> r3 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Rejected<void>(); }));
-
- Promise<int, void> r4 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return PromiseResult<int, void>(123.0); }));
- Promise<int, void> r5 = p1.promise().ThenHere(
- FROM_HERE,
- BindOnce([]() { return PromiseResult<int, NoReject>(123.0); }));
- Promise<NoResolve, void> r6 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return PromiseResult<NoResolve, void>(); }));
-
- Promise<int, void> r7 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Promise<int, void>(); }));
- Promise<int, void> r8 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Promise<int, NoReject>(); }));
- Promise<NoResolve, void> r9 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Promise<NoResolve, void>(); }));
-
- ManualPromiseResolver<std::string> p2(FROM_HERE);
- Promise<int> r10 =
- p2.promise().ThenHere(FROM_HERE, BindOnce([]() { return 123; }));
- Promise<int> r11 = p2.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<int>(123); }));
- Promise<NoResolve, int> r12 = p2.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Rejected<int>(123); }));
-}
-
-TEST_F(PromiseTest, ThenAndCatchHereReturnTypes) {
- struct A {};
- struct B {};
- struct C {};
- struct D {};
-
- Promise<B, NoReject> p1 =
- ManualPromiseResolver<A, NoReject>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<B>(); }));
- Promise<NoResolve, B> p2 =
- ManualPromiseResolver<A, NoReject>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Rejected<B>(); }));
- Promise<B, C> p3 =
- ManualPromiseResolver<A, NoReject>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() -> PromiseResult<B, C> { return B{}; }));
-
- Promise<B, NoReject> p4 =
- ManualPromiseResolver<NoResolve, A>(FROM_HERE).promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Resolved<B>(); }));
- Promise<NoResolve, B> p5 =
- ManualPromiseResolver<NoResolve, A>(FROM_HERE).promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Rejected<B>(); }));
- Promise<B, C> p6 =
- ManualPromiseResolver<NoResolve, A>(FROM_HERE).promise().CatchHere(
- FROM_HERE, BindOnce([]() -> PromiseResult<B, C> { return B{}; }));
-
- Promise<B, C> p7 = ManualPromiseResolver<A, C>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<B>(); }));
- Promise<NoResolve, C> p8 =
- ManualPromiseResolver<A, C>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Rejected<C>(); }));
- Promise<B, C> p9 = ManualPromiseResolver<A, C>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() -> PromiseResult<B, C> { return B{}; }));
-
- Promise<A, NoReject> p10 =
- ManualPromiseResolver<A, C>(FROM_HERE).promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Resolved<A>(); }));
- Promise<A, B> p11 =
- ManualPromiseResolver<A, C>(FROM_HERE).promise().CatchHere(
- FROM_HERE, BindOnce([]() { return Rejected<B>(); }));
- Promise<A, B> p12 =
- ManualPromiseResolver<A, C>(FROM_HERE).promise().CatchHere(
- FROM_HERE, BindOnce([]() -> PromiseResult<A, B> { return B{}; }));
-
- Promise<C, NoReject> p13 =
- ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<C>(); }),
- BindOnce([]() { return Resolved<C>(); }));
- Promise<NoResolve, D> p14 =
- ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Rejected<D>(); }),
- BindOnce([]() { return Rejected<D>(); }));
- Promise<C, D> p15 = ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<C>(); }),
- BindOnce([]() { return Rejected<D>(); }));
- Promise<C, D> p16 = ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Rejected<D>(); }),
- BindOnce([]() { return Resolved<C>(); }));
-
- Promise<C, D> p17 = ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() -> PromiseResult<C, D> { return C{}; }),
- BindOnce([]() { return Resolved<C>(); }));
- Promise<C, D> p18 = ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() -> PromiseResult<C, D> { return C{}; }),
- BindOnce([]() { return Rejected<D>(); }));
- Promise<C, D> p19 = ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<C>(); }),
- BindOnce([]() -> PromiseResult<C, D> { return C{}; }));
- Promise<C, D> p20 = ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Rejected<D>(); }),
- BindOnce([]() -> PromiseResult<C, D> { return C{}; }));
-
- Promise<C, D> p21 = ManualPromiseResolver<A, B>(FROM_HERE).promise().ThenHere(
- FROM_HERE, BindOnce([]() -> PromiseResult<C, D> { return C{}; }),
- BindOnce([]() -> PromiseResult<C, D> { return C{}; }));
-}
-
-TEST_F(PromiseTest, UnsettledManualPromiseResolverCancelsChain) {
- bool delete_flag = false;
- Promise<void> p2;
-
- {
- ManualPromiseResolver<int> p1(FROM_HERE);
- p2 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([](scoped_refptr<ObjectToDelete> v) {},
- MakeRefCounted<ObjectToDelete>(&delete_flag)));
- }
-
- EXPECT_TRUE(delete_flag);
- EXPECT_TRUE(p2.IsCancelledForTesting());
-}
-
-TEST_F(PromiseTest, CancellationSpottedByExecute) {
- bool delete_flag = false;
- Promise<void> p3;
-
- {
- Cancelable cancelable;
- ManualPromiseResolver<void> p1(FROM_HERE);
- Promise<void> p2 = p1.promise().ThenHere(
- FROM_HERE, BindOnce(&Cancelable::NopTask,
- cancelable.weak_ptr_factory.GetWeakPtr()));
-
- p1.Resolve();
- cancelable.weak_ptr_factory.InvalidateWeakPtrs();
-
- p3 = p2.ThenHere(FROM_HERE,
- BindOnce([](scoped_refptr<ObjectToDelete> v) {},
- MakeRefCounted<ObjectToDelete>(&delete_flag)));
- }
-
- RunLoop().RunUntilIdle();
- EXPECT_TRUE(delete_flag);
- EXPECT_TRUE(p3.IsCancelledForTesting());
-}
-
-TEST_F(PromiseTest, RejectAndReReject) {
- ManualPromiseResolver<int, std::string> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .CatchHere(
- FROM_HERE,
- BindOnce([](const std::string& err) -> PromiseResult<int, int> {
- EXPECT_EQ("Oh no!", err);
- // Re-Reject with -1 this time.
- return Rejected<int>(-1);
- }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](int err) {
- EXPECT_EQ(-1, err);
- run_loop.Quit();
- return -1;
- }));
-
- p.GetRejectCallback().Run("Oh no!");
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectAndReRejectThenCatch) {
- ManualPromiseResolver<int, std::string> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .CatchHere(FROM_HERE, BindLambdaForTesting(
- [](std::string) { return Rejected<int>(-1); }))
- .CatchHere(FROM_HERE,
- BindLambdaForTesting([&](int) { return Resolved<int>(1000); }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int value) {
- EXPECT_EQ(1000, value);
- return Rejected<DummyError>();
- }))
- .CatchHere(FROM_HERE,
- BindLambdaForTesting([&](DummyError) { run_loop.Quit(); }));
-
- p.GetRejectCallback().Run("Oh no!");
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenWhichAlwayResolves) {
- ManualPromiseResolver<void> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([]() -> Resolved<int> {
- // Resolve
- return 123;
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int value) {
- EXPECT_EQ(123, value);
- run_loop.Quit();
- }));
-
- p.GetResolveCallback().Run();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenWhichAlwayRejects) {
- ManualPromiseResolver<void, int> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([]() -> Rejected<int> {
- // Reject
- return -1;
- }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](int err) {
- EXPECT_EQ(-1, err);
- run_loop.Quit();
- }));
-
- p.GetResolveCallback().Run();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenWhichAlwayRejectsTypeTwo) {
- ManualPromiseResolver<void> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([]() -> Rejected<int> {
- // Reject
- return -1;
- }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](int err) {
- EXPECT_EQ(-1, err);
- run_loop.Quit();
- }));
-
- p.GetResolveCallback().Run();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenWhichAlwayRejectsTypeThree) {
- ManualPromiseResolver<int> p(FROM_HERE);
-
- base::RunLoop run_loop;
-
- p.promise()
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- return Rejected<std::string>(std::string("reject"));
- }))
- .CatchHere(FROM_HERE, BindLambdaForTesting(
- [&](std::string result) { run_loop.Quit(); }));
-
- p.GetResolveCallback().Run(123);
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ReferenceType) {
- int a = 123;
- int b = 456;
- ManualPromiseResolver<const int&> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](const int& value) -> const int& {
- EXPECT_EQ(123, value);
- return b;
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](const int& value) {
- EXPECT_EQ(456, value);
- run_loop.Quit();
- }));
-
- p.GetResolveCallback().Run(a);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, PromiseResultVoid) {
- ManualPromiseResolver<void> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { return PromiseResult<void>(); }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&]() { run_loop.Quit(); }));
-
- p.Resolve();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RefcountedType) {
- scoped_refptr<internal::AbstractPromise> a =
- DoNothingPromiseBuilder(FROM_HERE);
- scoped_refptr<internal::AbstractPromise> b =
- DoNothingPromiseBuilder(FROM_HERE);
- ManualPromiseResolver<scoped_refptr<internal::AbstractPromise>> p(FROM_HERE);
- RunLoop run_loop;
-
- p.promise()
- .ThenHere(FROM_HERE,
- BindLambdaForTesting(
- [&](scoped_refptr<internal::AbstractPromise> value) {
- EXPECT_EQ(a, value);
- return b;
- }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting(
- [&](scoped_refptr<internal::AbstractPromise> value) {
- EXPECT_EQ(b, value);
- run_loop.Quit();
- }));
-
- p.Resolve(a);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveThenVoidFunction) {
- ManualPromiseResolver<int> p(FROM_HERE);
- p.Resolve(123);
-
- // You don't have to use the resolve (or reject) arguments from the
- // previous promise.
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { run_loop.Quit(); }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveThenStdTupleUnpack) {
- RunLoop run_loop;
- Promise<std::tuple<int, std::string>>::CreateResolved(FROM_HERE, 10,
- std::string("Hi"))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int a, std::string b) {
- EXPECT_EQ(10, a);
- EXPECT_EQ("Hi", b);
- run_loop.Quit();
- }));
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveAfterThen) {
- ManualPromiseResolver<int> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- p.Resolve(123);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectOutsidePromiseAfterThen) {
- ManualPromiseResolver<int, void> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&](int result) {
- run_loop.Quit();
- FAIL() << "We shouldn't get here, the promise was rejected!";
- }),
- run_loop.QuitClosure());
-
- p.Reject();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenChainMoveOnlyType) {
- ManualPromiseResolver<std::unique_ptr<int>> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindOnce([](std::unique_ptr<int> result) { return result; }))
- .ThenHere(FROM_HERE,
- BindOnce([](std::unique_ptr<int> result) { return result; }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](std::unique_ptr<int> result) {
- EXPECT_THAT(123, *result);
- run_loop.Quit();
- }));
-
- p.Resolve(std::make_unique<int>(123));
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, MultipleMovesNotAllowed) {
- ManualPromiseResolver<std::unique_ptr<int>> p(FROM_HERE);
-
- // The executor argument will be called with move semantics.
- p.promise().ThenHere(FROM_HERE, BindOnce([](std::unique_ptr<int> result) {}));
-
- // It's an error to do that twice.
- EXPECT_DCHECK_DEATH({
- p.promise().ThenHere(FROM_HERE,
- BindOnce([](std::unique_ptr<int> result) {}));
- });
-}
-
-TEST_F(PromiseTest, ThenChain) {
- ManualPromiseResolver<std::vector<size_t>> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](std::vector<size_t> result) {
- result.push_back(1);
- return result;
- }))
- .ThenHere(FROM_HERE, BindOnce([](std::vector<size_t> result) {
- result.push_back(2);
- return result;
- }))
- .ThenHere(FROM_HERE, BindOnce([](std::vector<size_t> result) {
- result.push_back(3);
- return result;
- }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](std::vector<size_t> result) {
- EXPECT_THAT(result, ElementsAre(0u, 1u, 2u, 3u));
- run_loop.Quit();
- }));
-
- p.Resolve(std::vector<size_t>{0});
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectionInThenChainDefaultVoid) {
- ManualPromiseResolver<std::vector<size_t>> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](std::vector<size_t> result) {
- result.push_back(result.size());
- return result;
- }))
- .ThenHere(FROM_HERE, BindOnce([](std::vector<size_t> result) {
- result.push_back(result.size());
- return result;
- }))
- .ThenHere(FROM_HERE,
- BindOnce([](std::vector<size_t> result)
- -> PromiseResult<std::vector<size_t>, void> {
- return Rejected<void>();
- }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](std::vector<size_t> result) {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- }),
- BindLambdaForTesting([&]() { run_loop.Quit(); }));
-
- p.Resolve(std::vector<size_t>{0});
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectPropagation) {
- ManualPromiseResolver<int, bool> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result + 1; }))
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result + 1; }))
- .ThenHere(FROM_HERE,
- BindOnce([](int result) -> PromiseResult<int, std::string> {
- return std::string("Fail shouldn't get here");
- }),
- BindOnce([](bool value) -> PromiseResult<int, std::string> {
- EXPECT_FALSE(value);
- return std::string("Oh no!");
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- BindLambdaForTesting([&](const std::string& err) {
- EXPECT_EQ("Oh no!", err);
- run_loop.Quit();
- }));
-
- p.Reject(false);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectPropagationThensAfterRejectSkipped) {
- ManualPromiseResolver<int, bool> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result + 1; }))
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result + 1; }))
- .ThenHere(FROM_HERE,
- BindOnce([](int result) -> PromiseResult<int, std::string> {
- return std::string("Fail shouldn't get here");
- }),
- BindOnce([](bool value) -> PromiseResult<int, std::string> {
- EXPECT_FALSE(value);
- return std::string("Oh no!"); // Reject
- }))
- .ThenHere(FROM_HERE, BindOnce([](int result) {
- CHECK(false) << "Shouldn't get here";
- return result + 1;
- }))
- .ThenHere(FROM_HERE, BindOnce([](int result) {
- CHECK(false) << "Shouldn't get here";
- return result + 1;
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- BindLambdaForTesting([&](const std::string& err) {
- EXPECT_EQ("Oh no!", err);
- run_loop.Quit();
- }));
-
- p.Reject(false);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenOnWithHetrogenousButCompatibleReturnTypes) {
- ManualPromiseResolver<void, int> p(FROM_HERE);
-
- // Make sure ThenHere returns the expected type.
- Promise<int, std::string> p2 = p.promise().ThenHere(
- FROM_HERE,
- BindOnce([]() -> PromiseResult<int, std::string> { return 123; }),
- BindOnce([](int err) -> Resolved<int> { return 123; }));
-}
-
-TEST_F(PromiseTest, ThenOnWithHetrogenousButCompatibleReturnTypes2) {
- ManualPromiseResolver<void, int> p(FROM_HERE);
-
- // Make sure ThenHere returns the expected type.
- Promise<int, std::string> p2 = p.promise().ThenHere(
- FROM_HERE,
- BindOnce([]() -> PromiseResult<int, std::string> { return 123; }),
- BindOnce([](int err) -> Rejected<std::string> { return "123"; }));
-}
-
-TEST_F(PromiseTest, ThenOnWithHetrogenousButCompatibleReturnTypes3) {
- ManualPromiseResolver<int, std::string> p(FROM_HERE);
-
- // Make sure ThenHere returns the expected type.
- Promise<void, bool> p2 = p.promise().ThenHere(
- FROM_HERE, BindOnce([](int value) -> PromiseResult<void, bool> {
- if (value % 2) {
- return Resolved<void>();
- } else {
- return true;
- }
- }),
- BindOnce([](const std::string& err) -> Rejected<bool> { return false; }));
-}
-
-TEST_F(PromiseTest, ThenOnAfterNoResolvePromiseResult) {
- ManualPromiseResolver<std::unique_ptr<int>, int> p1(FROM_HERE);
-
- RunLoop run_loop;
- p1.promise()
- .CatchHere(FROM_HERE, BindLambdaForTesting(
- [&](int) -> PromiseResult<NoResolve, int> {
- return Rejected<int>();
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](std::unique_ptr<int>) {
- run_loop.Quit();
- return std::make_unique<int>(42);
- }),
- BindLambdaForTesting([&](int err) {
- CHECK(false) << "Shouldn't get here";
- return std::make_unique<int>(42);
- }));
-
- p1.GetResolveCallback().Run(std::make_unique<int>(42));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CatchCreatesNoRejectPromise) {
- ManualPromiseResolver<int> p(FROM_HERE);
-
- // Make sure CatchHere returns the expected type.
- Promise<int> p2 =
- p.promise()
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int) {
- return Rejected<std::string>();
- }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](std::string) {
- return Resolved<int>();
- }));
-}
-
-TEST_F(PromiseTest, ResolveSkipsCatches) {
- ManualPromiseResolver<int, void> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result + 1; }))
- .CatchHere(FROM_HERE, BindOnce([]() -> PromiseResult<int, void> {
- CHECK(false) << "Shouldn't get here";
- return -1;
- }))
- .CatchHere(FROM_HERE, BindOnce([]() -> PromiseResult<int, void> {
- CHECK(false) << "Shouldn't get here";
- return -1;
- }))
- .CatchHere(FROM_HERE, BindOnce([]() -> PromiseResult<int, void> {
- CHECK(false) << "Shouldn't get here";
- return -1;
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(2, result);
- run_loop.Quit();
- }),
- BindLambdaForTesting([&]() {
- FAIL() << "We shouldn't get here, the promise was resolved!";
- run_loop.Quit();
- }));
-
- p.Resolve(1);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ThenChainVariousReturnTypes) {
- ManualPromiseResolver<void> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([]() { return 5; }))
- .ThenHere(FROM_HERE, BindOnce([](int result) {
- EXPECT_EQ(5, result);
- return std::string("Hello");
- }))
- .ThenHere(FROM_HERE, BindOnce([](std::string result) {
- EXPECT_EQ("Hello", result);
- return true;
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](bool result) {
- EXPECT_TRUE(result);
- run_loop.Quit();
- }));
-
- p.GetResolveCallback().Run();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CurriedVoidPromise) {
- Promise<void> p = Promise<void>::CreateResolved(FROM_HERE);
- ManualPromiseResolver<void> promise_resolver(FROM_HERE);
-
- RunLoop run_loop;
- p.ThenHere(FROM_HERE, BindOnce(
- [](ManualPromiseResolver<void>* promise_resolver) {
- return promise_resolver->promise();
- },
- &promise_resolver))
- .ThenHere(FROM_HERE, run_loop.QuitClosure());
- RunLoop().RunUntilIdle();
-
- promise_resolver.Resolve();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CurriedIntPromise) {
- Promise<int> p = Promise<int>::CreateResolved(FROM_HERE, 1000);
- ManualPromiseResolver<int> promise_resolver(FROM_HERE);
-
- RunLoop run_loop;
- p.ThenHere(FROM_HERE,
- BindOnce(
- [](ManualPromiseResolver<int>* promise_resolver, int result) {
- EXPECT_EQ(1000, result);
- return promise_resolver->promise();
- },
- &promise_resolver))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
- RunLoop().RunUntilIdle();
-
- promise_resolver.Resolve(123);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CurriedIntPromiseChain) {
- Promise<int> p = Promise<int>::CreateResolved(FROM_HERE, 1000);
-
- ManualPromiseResolver<int> promise_resolver_1(FROM_HERE);
- ManualPromiseResolver<int> promise_resolver_2(FROM_HERE);
- promise_resolver_2.Resolve(promise_resolver_1.promise());
- promise_resolver_1.Resolve(123);
-
- RunLoop run_loop;
- p.ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(1000, result);
- return promise_resolver_2.promise();
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CurriedIntPromiseChain2) {
- Promise<int> p1 = Promise<int>::CreateResolved(FROM_HERE, 1000);
- Promise<int> p2 = Promise<int>::CreateResolved(FROM_HERE, 789);
- Promise<int> then2;
-
- {
- Promise<int> then1 =
- Promise<int>::CreateResolved(FROM_HERE, 789)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&]() { return p2; }));
- then2 = Promise<int>::CreateResolved(FROM_HERE, 789)
- .ThenHere(
- FROM_HERE,
- BindOnce([&](Promise<int> then1) { return then1; }, then1));
- }
-
- RunLoop run_loop;
- p1.ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(1000, result);
- return then2;
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(789, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CurriedIntPromiseChainThenAddedAfterInitialResolve) {
- ManualPromiseResolver<int> promise_resolver_1(FROM_HERE);
- ManualPromiseResolver<int> promise_resolver_2(FROM_HERE);
- ManualPromiseResolver<int> promise_resolver_3(FROM_HERE);
- promise_resolver_2.Resolve(promise_resolver_1.promise());
- promise_resolver_3.Resolve(promise_resolver_2.promise());
-
- RunLoop run_loop;
- promise_resolver_3.promise().ThenHere(FROM_HERE,
- BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- BindLambdaForTesting([&]() { promise_resolver_1.Resolve(123); }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CurriedVoidPromiseModified) {
- for (size_t i = 0; i < 1000; ++i) {
- Promise<void> p = Promise<void>::CreateResolved(FROM_HERE);
- std::unique_ptr<ManualPromiseResolver<int>> promise_resolver =
- std::make_unique<ManualPromiseResolver<int>>(FROM_HERE);
- RunLoop run_loop;
- p.ThenHere(FROM_HERE, BindOnce([](Promise<int> promise) { return promise; },
- promise_resolver->promise()))
- .ThenHere(FROM_HERE, base::BindOnce([](int v) { EXPECT_EQ(v, 42); }))
- .ThenHere(FROM_HERE, run_loop.QuitClosure());
- PostTask(FROM_HERE, {ThreadPool()}, BindLambdaForTesting([&]() {
- promise_resolver->Resolve(42);
- promise_resolver.reset();
- }));
- run_loop.Run();
- task_environment_.RunUntilIdle();
- }
-}
-
-TEST_F(PromiseTest, PromiseResultReturningAPromise) {
- Promise<int> p = Promise<int>::CreateResolved(FROM_HERE, 1000);
- ManualPromiseResolver<int> promise_resolver(FROM_HERE);
-
- RunLoop run_loop;
- p.ThenHere(FROM_HERE,
- BindLambdaForTesting([&](int result) -> PromiseResult<int> {
- EXPECT_EQ(1000, result);
- return promise_resolver.promise();
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
- RunLoop().RunUntilIdle();
-
- promise_resolver.Resolve(123);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveToDisambiguateThenReturnValue) {
- ManualPromiseResolver<int> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](int i) -> PromiseResult<Value, Value> {
- if ((i % 2) == 1)
- return Resolved<Value>("Success it was odd.");
- return Rejected<Value>("Failure it was even.");
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](Value result) {
- EXPECT_EQ("Success it was odd.", result.GetString());
- run_loop.Quit();
- }),
- BindLambdaForTesting([&](Value err) {
- run_loop.Quit();
- FAIL() << "We shouldn't get here, the promise was resolved!";
- }));
-
- p.Resolve(1);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectedToDisambiguateThenReturnValue) {
- ManualPromiseResolver<int, int> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([]() -> PromiseResult<int, int> {
- return Rejected<int>(123);
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- run_loop.Quit();
- FAIL() << "We shouldn't get here, the promise was rejected!";
- }),
- BindLambdaForTesting([&](int err) {
- run_loop.Quit();
- EXPECT_EQ(123, err);
- }));
-
- p.Resolve();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, NestedPromises) {
- ManualPromiseResolver<int> p(FROM_HERE);
- p.Resolve(100);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](int result) {
- ManualPromiseResolver<int> p2(FROM_HERE);
- p2.Resolve(200);
- return p2.promise().ThenHere(
- FROM_HERE, BindOnce([](int result) {
- ManualPromiseResolver<int> p3(FROM_HERE);
- p3.Resolve(300);
- return p3.promise().ThenHere(
- FROM_HERE,
- BindOnce([](int result) { return result; }));
- }));
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(300, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, Catch) {
- ManualPromiseResolver<int, std::string> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result; }))
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result; }))
- .ThenHere(FROM_HERE, BindOnce([](int result) { return result; }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](const std::string& err) {
- EXPECT_EQ("Whoops!", err);
- run_loop.Quit();
- return -1;
- }));
-
- p.Reject("Whoops!");
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, BranchedThenChainExecutionOrder) {
- std::vector<int> run_order;
-
- ManualPromiseResolver<void> promise_a(FROM_HERE);
- Promise<void> promise_b =
- promise_a.promise()
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 0))
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 1));
-
- Promise<void> promise_c =
- promise_a.promise()
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 2))
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 3));
-
- Promise<void> promise_d =
- promise_a.promise()
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 4))
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 5));
-
- promise_a.Resolve();
- RunLoop().RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(0, 2, 4, 1, 3, 5));
-}
-
-TEST_F(PromiseTest, BranchedThenChainWithCatchExecutionOrder) {
- std::vector<int> run_order;
-
- ManualPromiseResolver<void, void> promise_a(FROM_HERE);
- Promise<void> promise_b =
- promise_a.promise()
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 0))
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 1))
- .CatchHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 2));
-
- Promise<void> promise_c =
- promise_a.promise()
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 3))
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 4))
- .CatchHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 5));
-
- Promise<void> promise_d =
- promise_a.promise()
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 6))
- .ThenHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 7))
- .CatchHere(FROM_HERE, BindOnce(&RecordOrder, &run_order, 8));
-
- promise_a.Reject();
- RunLoop().RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(2, 5, 8));
-}
-
-TEST_F(PromiseTest, CatchRejectInThenChain) {
- ManualPromiseResolver<int> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindOnce([](int result) -> PromiseResult<int, std::string> {
- return std::string("Whoops!");
- }))
- .ThenHere(FROM_HERE, BindOnce([](int result) {
- CHECK(false) << "Shouldn't get here";
- return result;
- }))
- .ThenHere(FROM_HERE, BindOnce([](int result) {
- CHECK(false) << "Shouldn't get here";
- return result;
- }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](const std::string& err) {
- EXPECT_EQ("Whoops!", err);
- run_loop.Quit();
- return -1;
- }));
-
- p.Resolve(123);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CatchThenVoid) {
- ManualPromiseResolver<int, void> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .CatchHere(FROM_HERE, BindOnce([]() { return 123; }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- p.Reject();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CatchThenInt) {
- ManualPromiseResolver<int, int> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .CatchHere(FROM_HERE, BindOnce([](int err) { return err + 1; }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int result) {
- EXPECT_EQ(124, result);
- run_loop.Quit();
- }));
-
- p.Reject(123);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, SettledTaskFinally) {
- int result = 0;
- ManualPromiseResolver<int> p(FROM_HERE);
- p.Resolve(123);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](int value) { result = value; }))
- .FinallyHere(FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, SettledTaskFinallyThen) {
- int result = 0;
- ManualPromiseResolver<int> p(FROM_HERE);
- p.Resolve(123);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](int value) { result = value; }))
- .FinallyHere(FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_EQ(123, result);
- return std::string("hi");
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](const std::string& value) {
- EXPECT_EQ("hi", value);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, SettledTaskFinallyCatch) {
- int result = 0;
- ManualPromiseResolver<int> p(FROM_HERE);
- p.Resolve(123);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](int value) { result = value; }))
- .FinallyHere(FROM_HERE, BindLambdaForTesting(
- [&]() -> PromiseResult<void, std::string> {
- EXPECT_EQ(123, result);
- return std::string("Oh no");
- }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](const std::string& value) {
- EXPECT_EQ("Oh no", value);
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, ResolveFinally) {
- int result = 0;
- ManualPromiseResolver<int> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&](int value) { result = value; }));
- p.promise().FinallyHere(FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_EQ(123, result);
- run_loop.Quit();
- }));
- p.Resolve(123);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectFinally) {
- int result = 0;
- ManualPromiseResolver<int, void> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE,
- BindLambdaForTesting([&](int value) { result = value; }),
- BindLambdaForTesting([&]() { result = -1; }));
- p.promise().FinallyHere(FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_EQ(-1, result);
- run_loop.Quit();
- }));
- p.Reject();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, RejectFinallySkipsThens) {
- ManualPromiseResolver<void> p(FROM_HERE);
-
- RunLoop run_loop;
- p.promise()
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { return Rejected<int>(123); }))
- .ThenHere(FROM_HERE, BindLambdaForTesting(
- [&]() { FAIL() << "Promise was rejected"; }))
- .ThenHere(FROM_HERE, BindLambdaForTesting(
- [&]() { FAIL() << "Promise was rejected"; }))
- .FinallyHere(FROM_HERE, run_loop.QuitClosure());
- p.Resolve();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, CancelViaWeakPtr) {
- std::vector<std::string> log;
- ManualPromiseResolver<void, std::string> mpr(FROM_HERE,
- RejectPolicy::kCatchNotRequired);
- Promise<void, std::string> p1 = mpr.promise();
- {
- Cancelable cancelable;
- Promise<void, std::string> p2 = p1.ThenHere(
- FROM_HERE,
- BindOnce(&Cancelable::LogTask, cancelable.weak_ptr_factory.GetWeakPtr(),
- &log, "Then #1"));
- p2.ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() -> PromiseResult<void, std::string> {
- log.push_back("Then #2 (reject)");
- return std::string("Whoops!");
- }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { log.push_back("Then #3"); }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { log.push_back("Then #4"); }))
- .CatchHere(FROM_HERE, BindLambdaForTesting([&](const std::string& err) {
- log.push_back("Caught " + err);
- }));
-
- p2.FinallyHere(FROM_HERE,
- BindLambdaForTesting([&]() { log.push_back("Finally"); }));
- p2.ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { log.push_back("Then #5"); }));
- p2.ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { log.push_back("Then #6"); }));
- }
-
- mpr.Resolve();
- RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(log.empty());
-}
-
-TEST_F(PromiseTest, CancelPropagation) {
- ManualPromiseResolver<void> p1(FROM_HERE);
- ManualPromiseResolver<void> p2(FROM_HERE);
- Promise<void> p3;
- Promise<std::tuple<Void, Void>> pAll;
-
- RunLoop run_loop;
- {
- Cancelable cancelable;
-
- p3 = p2.promise().ThenHere(
- FROM_HERE, BindOnce(&Cancelable::NopTask,
- cancelable.weak_ptr_factory.GetWeakPtr()));
-
- pAll = Promises::All(FROM_HERE, p1.promise(), p3);
-
- p1.Resolve();
- p2.Resolve();
- EXPECT_FALSE(pAll.IsCancelledForTesting());
- }
-
- run_loop.RunUntilIdle();
- EXPECT_TRUE(pAll.IsCancelledForTesting());
-}
-
-TEST_F(PromiseTest, CancelPropagationLongerChain) {
- ManualPromiseResolver<void> p1(FROM_HERE);
- ManualPromiseResolver<void> p2(FROM_HERE);
- Promise<void> p3;
- Promise<std::tuple<Void, Void>> pAll;
-
- RunLoop run_loop;
- {
- Cancelable cancelable;
-
- p3 = p2.promise()
- .ThenHere(FROM_HERE,
- BindOnce(&Cancelable::NopTask,
- cancelable.weak_ptr_factory.GetWeakPtr()))
- .ThenHere(FROM_HERE, BindOnce([]() {}))
- .ThenHere(FROM_HERE, BindOnce([]() {}));
-
- pAll = Promises::All(FROM_HERE, p1.promise(), p3);
-
- p1.Resolve();
- p2.Resolve();
- EXPECT_FALSE(pAll.IsCancelledForTesting());
- }
-
- run_loop.RunUntilIdle();
- EXPECT_TRUE(pAll.IsCancelledForTesting());
-}
-
-TEST_F(PromiseTest, CatchNotRequired) {
- ManualPromiseResolver<bool, int> p(FROM_HERE,
- RejectPolicy::kCatchNotRequired);
-
- RunLoop run_loop;
- p.promise().ThenHere(FROM_HERE, run_loop.QuitClosure());
-
- // Note this doesn't DCHECK even though we haven't specified a Catch.
- p.Resolve();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, MoveOnlyTypeMultipleThensNotAllowed) {
-#if DCHECK_IS_ON()
- Promise<std::unique_ptr<int>> p =
- Promise<std::unique_ptr<int>>::CreateResolved(FROM_HERE,
- std::make_unique<int>(123));
-
- p.ThenHere(FROM_HERE,
- BindOnce([](std::unique_ptr<int> i) { EXPECT_EQ(123, *i); }));
-
- EXPECT_DCHECK_DEATH({
- p.ThenHere(FROM_HERE,
- BindOnce([](std::unique_ptr<int> i) { EXPECT_EQ(123, *i); }));
- });
-#endif
-}
-
-TEST_F(PromiseTest, MoveOnlyTypeMultipleCatchesNotAllowed) {
-#if DCHECK_IS_ON()
- auto p = Promise<void, std::unique_ptr<int>>::CreateRejected(
- FROM_HERE, std::make_unique<int>(123));
-
- auto r = p.CatchHere(
- FROM_HERE, BindOnce([](std::unique_ptr<int> i) { EXPECT_EQ(123, *i); }));
-
- EXPECT_DCHECK_DEATH({
- p.CatchHere(FROM_HERE,
- BindOnce([](std::unique_ptr<int> i) { EXPECT_EQ(123, *i); }));
- });
-
- // TODO(alexclarke): Temporary, remove when SequenceManager handles promises
- // natively.
- r.GetScopedRefptrForTesting()->OnCanceled();
-#endif
-}
-
-TEST_F(PromiseTest, UnhandledRejection) {
-#if DCHECK_IS_ON()
- Promise<void, int> p = Promise<void, int>::CreateRejected(FROM_HERE).ThenHere(
- FROM_HERE, BindOnce([]() {}));
-
- RunLoop().RunUntilIdle();
-
- Promise<void, int> null_promise;
- EXPECT_DCHECK_DEATH({ p = null_promise; });
-
- // EXPECT_DCHECK_DEATH uses fork under the hood so we still have to tidy up.
- p.IgnoreUncaughtCatchForTesting();
-#endif
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverPotentialUnhandledRejection) {
-#if DCHECK_IS_ON()
- ManualPromiseResolver<void, void> promise_resolver(FROM_HERE);
-
- // |promise_resolver| could reject but there's no catch.
- Promise<void, void> p =
- promise_resolver.promise().ThenHere(FROM_HERE, BindOnce([]() {}));
-
- promise_resolver.Resolve();
- RunLoop().RunUntilIdle();
-
- Promise<void, void> null_promise;
- EXPECT_DCHECK_DEATH({ p = null_promise; });
-
- // EXPECT_DCHECK_DEATH uses fork under the hood so we still have to tidy up.
- p.IgnoreUncaughtCatchForTesting();
-#endif
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverResolveCalledTwice) {
-#if DCHECK_IS_ON()
- ManualPromiseResolver<void> promise_resolver(FROM_HERE);
-
- promise_resolver.Resolve();
-
- EXPECT_DCHECK_DEATH({ promise_resolver.Resolve(); });
-#endif
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverRejectCalledTwice) {
-#if DCHECK_IS_ON()
- ManualPromiseResolver<void, void> promise_resolver(
- FROM_HERE, RejectPolicy::kCatchNotRequired);
-
- promise_resolver.Reject();
-
- EXPECT_DCHECK_DEATH({ promise_resolver.Reject(); });
-#endif
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverResolveCalledAfterReject) {
-#if DCHECK_IS_ON()
- ManualPromiseResolver<void, void> promise_resolver(
- FROM_HERE, RejectPolicy::kCatchNotRequired);
-
- promise_resolver.Reject();
-
- EXPECT_DCHECK_DEATH({ promise_resolver.Resolve(); });
-#endif
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverRepeatingResolveCallbackCalledTwice) {
-#if DCHECK_IS_ON()
- ManualPromiseResolver<void, void> promise_resolver(
- FROM_HERE, RejectPolicy::kCatchNotRequired);
- RepeatingCallback<void()> resolve =
- promise_resolver.GetRepeatingResolveCallback();
-
- resolve.Run();
-
- EXPECT_DCHECK_DEATH({ resolve.Run(); });
-#endif
-}
-
-TEST_F(PromiseTest, ManualPromiseResolverRepeatingRejectCallbackCalledTwice) {
-#if DCHECK_IS_ON()
- ManualPromiseResolver<void, void> promise_resolver(
- FROM_HERE, RejectPolicy::kCatchNotRequired);
- RepeatingCallback<void()> resolve =
- promise_resolver.GetRepeatingRejectCallback();
-
- resolve.Run();
-
- EXPECT_DCHECK_DEATH({ resolve.Run(); });
-#endif
-}
-
-class MultiThreadedPromiseTest : public PromiseTest {
- public:
- void SetUp() override {
- thread_a_.reset(new Thread("MultiThreadPromiseTest_Thread_A"));
- thread_b_.reset(new Thread("MultiThreadPromiseTest_Thread_B"));
- thread_c_.reset(new Thread("MultiThreadPromiseTest_Thread_C"));
- thread_a_->Start();
- thread_b_->Start();
- thread_c_->Start();
- }
-
- void TearDown() override {
- thread_a_->Stop();
- thread_b_->Stop();
- thread_c_->Stop();
- }
-
- std::unique_ptr<Thread> thread_a_;
- std::unique_ptr<Thread> thread_b_;
- std::unique_ptr<Thread> thread_c_;
-};
-
-TEST_F(MultiThreadedPromiseTest, SimpleThreadHopping) {
- ManualPromiseResolver<void> promise_resolver(FROM_HERE);
-
- RunLoop run_loop;
- promise_resolver.promise()
- .ThenOn(
- thread_a_->task_runner(), FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_TRUE(thread_a_->task_runner()->RunsTasksInCurrentSequence());
- }))
- .ThenOn(
- thread_b_->task_runner(), FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_TRUE(thread_b_->task_runner()->RunsTasksInCurrentSequence());
- }))
- .ThenOn(
- thread_c_->task_runner(), FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_TRUE(thread_c_->task_runner()->RunsTasksInCurrentSequence());
- }))
- .ThenHere(FROM_HERE, BindLambdaForTesting([&]() {
- EXPECT_FALSE(
- thread_a_->task_runner()->RunsTasksInCurrentSequence());
- EXPECT_FALSE(
- thread_b_->task_runner()->RunsTasksInCurrentSequence());
- EXPECT_FALSE(
- thread_c_->task_runner()->RunsTasksInCurrentSequence());
- run_loop.Quit();
- }));
-
- promise_resolver.Resolve();
- run_loop.Run();
-}
-
-TEST_F(MultiThreadedPromiseTest, CrossThreadThens) {
- ManualPromiseResolver<void> promise_resolver(FROM_HERE);
-
- auto resolve_task =
- BindLambdaForTesting([&]() { promise_resolver.Resolve(); });
-
- RunLoop run_loop;
-
- // Rolling our own thread-unsafe BarrierClosure to ensure atomics aren't
- // necessary for this test to resolve all Thens on |thread_c_|.
- int thens_remaining = 1000;
- auto then_task = BindLambdaForTesting([&]() {
- --thens_remaining;
- if (!thens_remaining)
- run_loop.Quit();
- });
-
- thread_a_->task_runner()->PostTask(
- FROM_HERE, BindLambdaForTesting([&]() {
- // Post 500 thens.
- for (int i = 0; i < 500; i++) {
- promise_resolver.promise().ThenOn(thread_c_->task_runner(), FROM_HERE,
- then_task);
- }
- // Post a task onto the main thread to resolve |promise_resolver|.
- // This should run at an undefined time yet all the thens should run.
- thread_b_->task_runner()->PostTask(FROM_HERE, resolve_task);
-
- // Post another 500 thens.
- for (int i = 0; i < 500; i++) {
- promise_resolver.promise().ThenOn(thread_c_->task_runner(), FROM_HERE,
- then_task);
- }
- }));
-
- run_loop.Run();
-}
-
-TEST_F(MultiThreadedPromiseTest, CrossThreadThensOrdering) {
- constexpr int kNumThenTasks = 1000;
- constexpr int kNumRepetitions = 25;
- for (int repetition = 0; repetition < kNumRepetitions; ++repetition) {
- RunLoop run_loop;
-
- std::vector<int> order;
- std::vector<OnceCallback<void()>> then_tasks;
-
- for (int i = 0; i < kNumThenTasks; ++i) {
- then_tasks.push_back(
- BindOnce(BindLambdaForTesting([&order, &run_loop, i]() {
- order.push_back(i);
- if (i == (kNumThenTasks - 1)) {
- run_loop.Quit();
- }
- })));
- }
-
- ManualPromiseResolver<void> promise_resolver(FROM_HERE);
- auto resolve_callback = promise_resolver.GetResolveCallback();
-
- thread_a_->task_runner()->PostTask(
- FROM_HERE, BindLambdaForTesting([&]() {
- // Post 500 thens.
- for (int i = 0; i < kNumThenTasks / 2; ++i) {
- promise_resolver.promise().ThenOn(
- thread_c_->task_runner(), FROM_HERE, std::move(then_tasks[i]));
- }
-
- // Post a task onto |thread_b| to resolve |promise_resolver|.
- // This should run at an undefined time yet all the thens should run.
- thread_b_->task_runner()->PostTask(FROM_HERE,
- std::move(resolve_callback));
-
- // Post another 500 thens.
- for (int i = kNumThenTasks / 2; i < kNumThenTasks; ++i) {
- promise_resolver.promise().ThenOn(
- thread_c_->task_runner(), FROM_HERE, std::move(then_tasks[i]));
- }
- }));
-
- run_loop.Run();
- for (int i = 0; i < kNumThenTasks; ++i) {
- EXPECT_EQ(order[i], i);
- }
- }
-}
-
-TEST_F(PromiseTest, ThreadPoolThenChain) {
- ManualPromiseResolver<std::vector<size_t>> p(FROM_HERE);
- auto main_sequence = SequencedTaskRunnerHandle::Get();
-
- RunLoop run_loop;
- p.promise()
- .ThenOn({ThreadPool(), TaskPriority::USER_BLOCKING}, FROM_HERE,
- BindLambdaForTesting([&](std::vector<size_t> result) {
- EXPECT_FALSE(main_sequence->RunsTasksInCurrentSequence());
- result.push_back(1);
- return result;
- }))
- .ThenOn({ThreadPool(), TaskPriority::USER_BLOCKING}, FROM_HERE,
- BindLambdaForTesting([&](std::vector<size_t> result) {
- EXPECT_FALSE(main_sequence->RunsTasksInCurrentSequence());
- result.push_back(2);
- return result;
- }))
- .ThenOn({ThreadPool(), TaskPriority::USER_BLOCKING}, FROM_HERE,
- BindLambdaForTesting([&](std::vector<size_t> result) {
- EXPECT_FALSE(main_sequence->RunsTasksInCurrentSequence());
- result.push_back(3);
- return result;
- }))
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](std::vector<size_t> result) {
- EXPECT_TRUE(main_sequence->RunsTasksInCurrentSequence());
- EXPECT_THAT(result, ElementsAre(0u, 1u, 2u, 3u));
- run_loop.Quit();
- }));
-
- p.Resolve(std::vector<size_t>{0});
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, All) {
- ManualPromiseResolver<float> p1(FROM_HERE);
- ManualPromiseResolver<int> p2(FROM_HERE);
- ManualPromiseResolver<bool> p3(FROM_HERE);
- Promise<std::tuple<float, int, bool>> p =
- Promises::All(FROM_HERE, p1.promise(), p2.promise(), p3.promise());
-
- RunLoop run_loop;
- p.ThenHere(FROM_HERE, BindLambdaForTesting(
- [&](const std::tuple<float, int, bool>& result) {
- EXPECT_EQ(1.234f, std::get<0>(result));
- EXPECT_EQ(1234, std::get<1>(result));
- EXPECT_TRUE(std::get<2>(result));
- run_loop.Quit();
- }));
-
- p1.Resolve(1.234f);
- p2.Resolve(1234);
- p3.Resolve(true);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllWithCurriedPromises) {
- ManualPromiseResolver<float> a1(FROM_HERE);
- ManualPromiseResolver<int> a2(FROM_HERE);
- ManualPromiseResolver<bool> a3(FROM_HERE);
- ManualPromiseResolver<void> p(FROM_HERE);
-
- Promise<float> p1 = p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&]() { return a1.promise(); }));
- Promise<int> p2 = p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&]() { return a2.promise(); }));
- Promise<bool> p3 = p.promise().ThenHere(
- FROM_HERE, BindLambdaForTesting([&]() { return a3.promise(); }));
-
- Promise<std::tuple<float, int, bool>> all =
- Promises::All(FROM_HERE, p1, p2, p3);
-
- RunLoop run_loop;
- all.ThenHere(FROM_HERE, BindLambdaForTesting(
- [&](const std::tuple<float, int, bool>& result) {
- EXPECT_EQ(1.234f, std::get<0>(result));
- EXPECT_EQ(1234, std::get<1>(result));
- EXPECT_TRUE(std::get<2>(result));
- run_loop.Quit();
- }));
-
- p.Resolve();
- a1.Resolve(1.234f);
- a2.Resolve(1234);
- a3.Resolve(true);
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllUnpackTuple) {
- ManualPromiseResolver<float> p1(FROM_HERE);
- ManualPromiseResolver<int> p2(FROM_HERE);
- ManualPromiseResolver<bool> p3(FROM_HERE);
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, p1.promise(), p2.promise(), p3.promise())
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](float a, int b, bool c) {
- EXPECT_EQ(1.234f, a);
- EXPECT_EQ(1234, b);
- EXPECT_TRUE(c);
- run_loop.Quit();
- }));
-
- p1.Resolve(1.234f);
- p2.Resolve(1234);
- p3.Resolve(true);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllRejectString) {
- ManualPromiseResolver<float, std::string> p1(FROM_HERE);
- ManualPromiseResolver<int, std::string> p2(FROM_HERE);
- ManualPromiseResolver<bool, std::string> p3(FROM_HERE);
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, p1.promise(), p2.promise(), p3.promise())
- .ThenHere(
- FROM_HERE,
- BindLambdaForTesting([&](const std::tuple<float, int, bool>& result) {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- BindLambdaForTesting([&](const std::string& err) {
- EXPECT_EQ("Whoops!", err);
- run_loop.Quit();
- }));
-
- p1.Reject("Whoops!");
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllWithSingleValue) {
- ManualPromiseResolver<int> p1(FROM_HERE);
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, p1.promise())
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](int value1) {
- EXPECT_EQ(value1, 1);
- run_loop.Quit();
- }));
-
- p1.Resolve(1);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllIntVoid) {
- ManualPromiseResolver<int> p1(FROM_HERE);
- ManualPromiseResolver<void> p2(FROM_HERE);
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, p1.promise(), p2.promise())
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&](const std::tuple<int, Void>& result) {
- EXPECT_EQ(1234, std::get<0>(result));
- run_loop.Quit();
- }));
-
- p1.Resolve(1234);
- p2.Resolve();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllMoveOnlyType) {
- ManualPromiseResolver<std::unique_ptr<float>> p1(FROM_HERE);
- ManualPromiseResolver<std::unique_ptr<int>> p2(FROM_HERE);
- ManualPromiseResolver<std::unique_ptr<bool>> p3(FROM_HERE);
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, p1.promise(), p2.promise(), p3.promise())
- .ThenHere(FROM_HERE,
- BindLambdaForTesting(
- [&](std::tuple<std::unique_ptr<float>, std::unique_ptr<int>,
- std::unique_ptr<bool>> result) {
- EXPECT_EQ(1.234f, *std::get<0>(result));
- EXPECT_EQ(1234, *std::get<1>(result));
- EXPECT_TRUE(*std::get<2>(result));
- run_loop.Quit();
- }));
-
- p1.Resolve(std::make_unique<float>(1.234f));
- p2.Resolve(std::make_unique<int>(1234));
- p3.Resolve(std::make_unique<bool>(true));
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllIntWithVoidThen) {
- ManualPromiseResolver<int> p1(FROM_HERE);
- ManualPromiseResolver<int> p2(FROM_HERE);
- ManualPromiseResolver<int> p3(FROM_HERE);
-
- // You can choose to ignore the result.
- RunLoop run_loop;
- Promises::All(FROM_HERE, p1.promise(), p2.promise(), p3.promise())
- .ThenHere(FROM_HERE, run_loop.QuitClosure());
-
- p1.Resolve(1);
- p2.Resolve(2);
- p3.Resolve(3);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllIntContainer) {
- ManualPromiseResolver<int> mpr1(FROM_HERE);
- ManualPromiseResolver<int> mpr2(FROM_HERE);
- ManualPromiseResolver<int> mpr3(FROM_HERE);
- ManualPromiseResolver<int> mpr4(FROM_HERE);
-
- std::vector<Promise<int>> promises;
- promises.push_back(mpr1.promise());
- promises.push_back(mpr2.promise());
- promises.push_back(mpr3.promise());
- promises.push_back(mpr4.promise());
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](std::vector<int> result) {
- EXPECT_THAT(result, ElementsAre(10, 20, 30, 40));
- run_loop.Quit();
- }));
-
- mpr1.Resolve(10);
- mpr2.Resolve(20);
- mpr3.Resolve(30);
- mpr4.Resolve(40);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllEmptyIntContainer) {
- std::vector<Promise<int>> promises;
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](std::vector<int> result) {
- EXPECT_TRUE(result.empty());
- run_loop.Quit();
- }));
-
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllIntStringContainerReject) {
- ManualPromiseResolver<int, std::string> mpr1(FROM_HERE);
- ManualPromiseResolver<int, std::string> mpr2(FROM_HERE);
- ManualPromiseResolver<int, std::string> mpr3(FROM_HERE);
- ManualPromiseResolver<int, std::string> mpr4(FROM_HERE);
-
- std::vector<Promise<int, std::string>> promises;
- promises.push_back(mpr1.promise());
- promises.push_back(mpr2.promise());
- promises.push_back(mpr3.promise());
- promises.push_back(mpr4.promise());
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&](std::vector<int> result) {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- BindLambdaForTesting([&](const std::string& err) {
- EXPECT_EQ("Oh dear", err);
- run_loop.Quit();
- }));
-
- mpr2.Reject("Oh dear");
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllVoidContainer) {
- ManualPromiseResolver<void> mpr1(FROM_HERE);
- ManualPromiseResolver<void> mpr2(FROM_HERE);
- ManualPromiseResolver<void> mpr3(FROM_HERE);
- ManualPromiseResolver<void> mpr4(FROM_HERE);
-
- std::vector<Promise<void>> promises;
- promises.push_back(mpr1.promise());
- promises.push_back(mpr2.promise());
- promises.push_back(mpr3.promise());
- promises.push_back(mpr4.promise());
-
- RunLoop run_loop;
- Promise<void> result =
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE,
- BindLambdaForTesting([&]() { run_loop.Quit(); }));
-
- mpr1.Resolve();
- mpr2.Resolve();
- mpr3.Resolve();
- RunLoop().RunUntilIdle();
- EXPECT_FALSE(result.IsResolvedForTesting());
-
- mpr4.Resolve();
- run_loop.Run();
- EXPECT_TRUE(result.IsResolvedForTesting());
-}
-
-TEST_F(PromiseTest, AllVoidIntContainerReject) {
- ManualPromiseResolver<void, int> mpr1(FROM_HERE);
- ManualPromiseResolver<void, int> mpr2(FROM_HERE);
- ManualPromiseResolver<void, int> mpr3(FROM_HERE);
- ManualPromiseResolver<void, int> mpr4(FROM_HERE);
-
- std::vector<Promise<void, int>> promises;
- promises.push_back(mpr1.promise());
- promises.push_back(mpr2.promise());
- promises.push_back(mpr3.promise());
- promises.push_back(mpr4.promise());
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&]() {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- BindLambdaForTesting([&](int err) {
- EXPECT_EQ(-1, err);
- run_loop.Quit();
- }));
-
- mpr1.Reject(-1);
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllVoidContainerReject) {
- ManualPromiseResolver<void, void> mpr1(FROM_HERE);
- ManualPromiseResolver<void, void> mpr2(FROM_HERE);
- ManualPromiseResolver<void, void> mpr3(FROM_HERE);
- ManualPromiseResolver<void, void> mpr4(FROM_HERE);
-
- std::vector<Promise<void, void>> promises;
- promises.push_back(mpr1.promise());
- promises.push_back(mpr2.promise());
- promises.push_back(mpr3.promise());
- promises.push_back(mpr4.promise());
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&]() {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- run_loop.QuitClosure());
-
- mpr4.Reject();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllVoidContainerMultipleRejectsBeforeExecute) {
- ManualPromiseResolver<void, void> mpr1(FROM_HERE);
- ManualPromiseResolver<void, void> mpr2(FROM_HERE);
- ManualPromiseResolver<void, void> mpr3(FROM_HERE);
- ManualPromiseResolver<void, void> mpr4(FROM_HERE);
-
- std::vector<Promise<void, void>> promises;
- promises.push_back(mpr1.promise());
- promises.push_back(mpr2.promise());
- promises.push_back(mpr3.promise());
- promises.push_back(mpr4.promise());
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&]() {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- run_loop.QuitClosure());
-
- mpr1.Reject();
- mpr2.Reject();
- mpr4.Reject();
- run_loop.Run();
-}
-
-TEST_F(PromiseTest, AllVoidContainerMultipleRejectsAfterExecute) {
- ManualPromiseResolver<void, void> mpr1(FROM_HERE);
- ManualPromiseResolver<void, void> mpr2(FROM_HERE);
- ManualPromiseResolver<void, void> mpr3(FROM_HERE);
- ManualPromiseResolver<void, void> mpr4(FROM_HERE);
-
- std::vector<Promise<void, void>> promises;
- promises.push_back(mpr1.promise());
- promises.push_back(mpr2.promise());
- promises.push_back(mpr3.promise());
- promises.push_back(mpr4.promise());
-
- RunLoop run_loop;
- Promises::All(FROM_HERE, promises)
- .ThenHere(FROM_HERE, BindLambdaForTesting([&]() {
- FAIL() << "We shouldn't get here, the promise was rejected!";
- run_loop.Quit();
- }),
- run_loop.QuitClosure());
-
- mpr1.Reject();
- run_loop.Run();
- mpr2.Reject();
- mpr4.Reject();
-}
-
-TEST_F(PromiseTest, TakeResolveValueForTesting) {
- ManualPromiseResolver<void> p1(FROM_HERE);
-
- Promise<int> p2 =
- p1.promise().ThenHere(FROM_HERE, BindOnce([]() { return 123; }));
-
- p1.Resolve();
-
- EXPECT_EQ(123, p2.TakeResolveValueForTesting());
-}
-
-TEST_F(PromiseTest, TakeResolveValueForTestingMoveOnlyType) {
- ManualPromiseResolver<void> p1(FROM_HERE);
-
- Promise<std::unique_ptr<int>> p2 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return std::make_unique<int>(123); }));
-
- p1.Resolve();
-
- EXPECT_EQ(123, *p2.TakeResolveValueForTesting());
-}
-
-TEST_F(PromiseTest, TakeResolveValueForTestingNotResolved) {
- ManualPromiseResolver<int, int> p1(FROM_HERE,
- RejectPolicy::kCatchNotRequired);
-
- p1.Reject(123);
-
- EXPECT_DCHECK_DEATH({ p1.promise().TakeResolveValueForTesting(); });
-}
-
-TEST_F(PromiseTest, TakeRejectedValueForTesting) {
- ManualPromiseResolver<void, void> p1(FROM_HERE);
-
- Promise<int, int> p2 = p1.promise().ThenHere(
- FROM_HERE, BindOnce([]() { return Resolved<int>(123); }),
- BindOnce([]() { return Rejected<int>(456); }));
-
- p1.Reject();
-
- EXPECT_EQ(456, p2.TakeRejectValueForTesting());
-}
-
-TEST_F(PromiseTest, TakeRejectedValueForTestingMoveOnlyType) {
- ManualPromiseResolver<void, std::unique_ptr<int>> p1(FROM_HERE);
-
- p1.Reject(std::make_unique<int>(456));
-
- EXPECT_EQ(456, *p1.promise().TakeRejectValueForTesting());
-}
-
-TEST_F(PromiseTest, TakeRejectedValueForTestingNotRejected) {
- ManualPromiseResolver<int, int> p1(FROM_HERE,
- RejectPolicy::kCatchNotRequired);
-
- p1.Resolve(123);
-
- EXPECT_DCHECK_DEATH({ p1.promise().TakeRejectValueForTesting(); });
-}
-
-} // namespace base
diff --git a/task/promise/promise_unittest.nc b/task/promise/promise_unittest.nc
deleted file mode 100644
index dca01e0..0000000
--- a/task/promise/promise_unittest.nc
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// This is a "No Compile Test" suite.
-// http://dev.chromium.org/developers/testing/no-compile-tests
-
-#include "base/task_runner.h"
-#include "base/task/promise/promise.h"
-#include "base/task/promise/promise_result.h"
-
-namespace base {
-
-#if defined(NCTEST_METHOD_CANT_CATCH_NOREJECT_PROMISE) // [r"fatal error: static_assert failed .*\"Can't catch a NoReject promise\."]
-void WontCompile() {
- Promise<int> p;
- p.CatchHere(FROM_HERE, BindOnce([]() {}));
-}
-#elif defined(NCTEST_METHOD_CANT_CATCH_NOREJECT_PROMISE_TYPE_TWO) // [r"fatal error: static_assert failed .*\"Can't catch a NoReject promise\."]
-void WontCompile() {
- Promise<int> p;
- p.ThenHere(FROM_HERE, BindOnce([](int) {}), BindOnce([]() {}));
-}
-#elif defined(NCTEST_METHOD_RESOLVE_CALLBACK_TYPE_MISSMATCH) // [r"fatal error: static_assert failed .*\"|on_resolve| callback must accept Promise::ResolveType or void\."]
-void WontCompile() {
- Promise<int, void> p;
- p.ThenHere(FROM_HERE, BindOnce([](std::string) { }));
-}
-#elif defined(NCTEST_METHOD_REJECT_CALLBACK_TYPE_MISSMATCH) // [r"fatal error: static_assert failed .*\"|on_reject| callback must accept Promise::ResolveType or void\."]
-void WontCompile() {
- Promise<int, void> p;
- p.CatchHere(FROM_HERE, BindOnce([](bool) { }));
-}
-#elif defined(NCTEST_METHOD_REJECT_CALLBACK_TYPE_MISSMATCH_TYPE_TWO) // [r"fatal error: static_assert failed .*\"|on_reject| callback must accept Promise::ResolveType or void\."]
-void WontCompile() {
- Promise<int, void> p;
- p.ThenHere(FROM_HERE, BindOnce([](int) { }), BindOnce([](bool) { }));
-}
-#elif defined(NCTEST_METHOD_INCOMPATIBLE_RETURN_TYPES) // [r"fatal error: static_assert failed .*\"|on_resolve| callback and |on_resolve| callback must return compatible types\."]
-void WontCompile() {
- Promise<void> p;
- p.ThenHere(
- FROM_HERE,
- BindOnce([]() -> PromiseResult<int, std::string> { return 123; }),
- BindOnce([](int err) -> Rejected<bool> { return "123"; }));
-}
-#elif defined(NCTEST_METHOD_INCOMPATIBLE_RETURN_TYPES2) // [r"fatal error: static_assert failed .*\"|on_resolve| callback and |on_resolve| callback must return compatible types\."]
-void WontCompile() {
- Promise<void> p;
- p.ThenHere(
- FROM_HERE,
- BindOnce([]() -> PromiseResult<int, std::string> { return 123; }),
- BindOnce([](int err) -> Resolved<std::string> { return "123"; }));
-}
-#elif defined(NCTEST_METHOD_INCOMPATIBLE_RETURN_TYPES3) // [r"fatal error: static_assert failed .*\"|on_resolve| callback and |on_resolve| callback must return compatible types\."]
-void WontCompile() {
- Promise<int, void> p;
- p.ThenHere(FROM_HERE, BindOnce([](int) { return true; }),
- BindOnce([](int) { return 123.0; }));
-}
-#elif defined(NCTEST_METHOD_AMBIGUOUS_CONSTRUCTOR) // [r"fatal error: static_assert failed .*\"Ambiguous because ResolveType and RejectType are the same"]
-void WontCompile() {
- PromiseResult<void, void> pr;
-}
-#elif defined(NCTEST_METHOD_AMBIGUOUS_CONSTRUCTOR2) // [r"fatal error: static_assert failed .*\"Ambiguous because ResolveType and RejectType are the same"]
-void WontCompile() {
- PromiseResult<int, int> pr(123);
-}
-#elif defined(NCTEST_METHOD_REJECTED_NOREJECT) // [r"fatal error: static_assert failed .*\"Can't have Rejected<NoReject>"]
-void WontCompile() {
- Rejected<NoReject>();
-}
-#elif defined(NCTEST_METHOD_ARGUMENT_DOESNT_MATCH) // [r"fatal error: static_assert failed .*\"Argument matches neither resolve nor reject type\."]
-void WontCompile() {
- PromiseResult<int, float> pr("invalid");
-}
-#elif defined(NCTEST_METHOD_ARGUMENT_DOESNT_MATCH2) // [r"fatal error: static_assert failed .*\"Promise resolve types don't match"]
-void WontCompile() {
- Promise<void> p;
- PromiseResult<int, float> pr(p);
-}
-#elif defined(NCTEST_METHOD_UNRELATED_RESOLVE) // [r"fatal error: static_assert failed .*\"T in Resolved<T> is not ResolveType"]
-void WontCompile() {
- struct Unrelated{};
- PromiseResult<int, void> pr(Resolved<Unrelated>{});
-}
-#elif defined(NCTEST_METHOD_UNRELATED_REJECT) // [r"fatal error: static_assert failed .*\"T in Rejected<T> is not RejectType"]
-void WontCompile() {
- struct Unrelated{};
- PromiseResult<int, void> pr(Rejected<Unrelated>{});
-}
-#elif defined(NCTEST_METHOD_AMBIGUOUS_REJECT_TYPE) // [r"fatal error: static_assert failed .*\"Ambiguous promise reject type"]
-void WontCompile() {
- Promise<int, void> p1;
- // If supported |p2| would have type Promise<NoReject, variant<void, bool>>.
- auto p2 = p1.ThenHere(FROM_HERE, BindOnce([]() { return Rejected<bool>(true); }));
-}
-#elif defined(NCTEST_METHOD_AMBIGUOUS_RESOLVE_TYPE) // [r"fatal error: static_assert failed .*\"Ambiguous promise resolve type"]
-void WontCompile() {
- Promise<int, void> p1;
- // If supported |p2| would have type Promise<variant<int, bool>, NoReject>.
- auto p2 = p1.CatchHere(FROM_HERE, BindOnce([](int) { return Resolved<bool>(true); }));
-}
-#elif defined(NCTEST_METHOD_NON_CONST_REFERENCE) // [r"fatal error: static_assert failed .*\"Google C.. Style: References in function parameters must be const\."]
-void WontCompile() {
- Promise<std::unique_ptr<int>> p;
- p.ThenHere(FROM_HERE, BindOnce([](std::unique_ptr<int>& result) {}));
-}
-#elif defined(NCTEST_METHOD_NON_CONST_REFERENCE2) // [r"fatal error: static_assert failed .*\"Google C.. Style: References in function parameters must be const\."]
-void WontCompile() {
- Promise<int&> p;
-}
-#elif defined(NCTEST_METHOD_NON_CONST_REFERENCE3) // [r"fatal error: static_assert failed .*\"Google C.. Style: References in function parameters must be const\."]
-void WontCompile() {
- Promise<void, int&> p;
-}
-#endif
-
-} // namespace base
diff --git a/task/promise/promise_value.cc b/task/promise/promise_value.cc
deleted file mode 100644
index 23d501b..0000000
--- a/task/promise/promise_value.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/promise_value.h"
-
-#include "base/task/promise/abstract_promise.h"
-
-namespace base {
-namespace internal {
-
-// static
-void PromiseValueInternal::NopMove(PromiseValueInternal* src,
- PromiseValueInternal* dest) {}
-
-// static
-void PromiseValueInternal::NopDelete(PromiseValueInternal* src) {}
-
-constexpr PromiseValueInternal::TypeOps PromiseValueInternal::null_type_;
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/promise_value.h b/task/promise/promise_value.h
deleted file mode 100644
index 3b1cfc4..0000000
--- a/task/promise/promise_value.h
+++ /dev/null
@@ -1,525 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_PROMISE_VALUE_H_
-#define BASE_TASK_PROMISE_PROMISE_VALUE_H_
-
-#include "base/base_export.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/parameter_pack.h"
-
-namespace base {
-
-namespace internal {
-class AbstractPromise;
-} // namespace internal
-
-// std::variant, std::tuple and other templates can't contain void but they can
-// contain the empty type Void. This is the same idea as std::monospace.
-struct Void {};
-
-// Signals that a promise doesn't resolve. E.g. Promise<NoResolve, int>
-struct NoResolve {};
-
-// Signals that a promise doesn't reject. E.g. Promise<int, NoReject>
-struct NoReject {};
-
-// Internally Resolved<> is used to store the result of a promise callback that
-// resolved. This lets us disambiguate promises with the same resolve and reject
-// type.
-template <typename T>
-struct Resolved {
- using Type = T;
-
- static_assert(!std::is_same<T, NoReject>::value,
- "Can't have Resolved<NoReject>");
-
- Resolved() {
- static_assert(!std::is_same<T, NoResolve>::value,
- "Can't have Resolved<NoResolve>");
- }
-
- // Conversion constructor accepts any arguments except Resolved<T>.
- template <
- typename... Args,
- std::enable_if_t<!all_of(
- {std::is_same<Resolved, std::decay_t<Args>>::value...})>* = nullptr>
- Resolved(Args&&... args) noexcept : value(std::forward<Args>(args)...) {}
-
- T value;
-};
-
-template <>
-struct Resolved<void> {
- using Type = void;
- Void value;
-};
-
-// Internally Rejected<> is used to store the result of a promise callback that
-// rejected. This lets us disambiguate promises with the same resolve and reject
-// type.
-template <typename T>
-struct Rejected {
- using Type = T;
- T value;
-
- static_assert(!std::is_same<T, NoResolve>::value,
- "Can't have Rejected<NoResolve>");
-
- Rejected() {
- static_assert(!std::is_same<T, NoReject>::value,
- "Can't have Rejected<NoReject>");
- }
-
- // Conversion constructor accepts any arguments except Rejected<T>.
- template <
- typename... Args,
- std::enable_if_t<!all_of(
- {std::is_same<Rejected, std::decay_t<Args>>::value...})>* = nullptr>
- Rejected(Args&&... args) noexcept : value(std::forward<Args>(args)...) {
- static_assert(!std::is_same<T, NoReject>::value,
- "Can't have Rejected<NoReject>");
- }
-};
-
-template <>
-struct Rejected<void> {
- using Type = void;
- Void value;
-};
-
-namespace internal {
-
-class PromiseExecutor;
-
-struct BASE_EXPORT PromiseValueInternal {
- // The state is stored in the bottom three bits of the TypeOps pointer, see
- // TaggedTypeOpsPtr.
- enum State {
- EMPTY,
- PROMISE_EXECUTOR,
- CURRIED_PROMISE,
- RESOLVED,
- REJECTED,
-
- // This value is never stored and is used internally for error checking.
- INVALID
- };
-
- // Where possible we use the small object allocation optimization to avoid
- // heap allocations.
- struct OutlineAlloc {
- void* value; // Holds a T
-
- template <typename T>
- T& value_as() {
- return *static_cast<T*>(value);
- }
-
- template <typename T>
- const T& value_as() const {
- return *static_cast<const T*>(value);
- }
- };
-
- struct alignas(sizeof(void*)) InlineAlloc {
- // Holds a T if small. Tweaked to hold a promise executor inline.
- char bytes[sizeof(void*) * 3];
-
- template <typename T>
- T& value_as() {
- return *reinterpret_cast<T*>(bytes);
- }
-
- template <typename T>
- const T& value_as() const {
- return *reinterpret_cast<const T*>(bytes);
- }
- };
-
- template <typename T>
- struct InlineStorageHelper {
- static constexpr bool kUseInlineStorage =
- (sizeof(T) <= sizeof(InlineAlloc));
-
- static_assert(
- std::alignment_of<T>::value <= sizeof(T),
- "Type T has alignment requirements that preclude it's storage inline.");
- };
-
- template <typename T>
- constexpr T* GetStorage() {
- return static_cast<T*>(
- GetStorageHelper<InlineStorageHelper<T>::kUseInlineStorage>::GetStorage(
- *this));
- }
-
- template <typename T>
- constexpr const T* GetStorage() const {
- return static_cast<const T*>(
- GetStorageHelper<InlineStorageHelper<T>::kUseInlineStorage>::GetStorage(
- *this));
- }
-
- template <typename T, bool UseInlineStorage>
- struct ConstructHelper;
-
- template <bool UseInlineStorage>
- struct GetStorageHelper;
-
- template <typename T, bool UseInlineStorage, bool HasMoveConstructor>
- struct MoveHelper;
-
- template <typename T, bool UseInlineStorage>
- struct DeleteHelper;
-
- template <typename T>
- struct TypeToStateHelper;
-
- using MoveFunctionPtr = void (*)(PromiseValueInternal* src,
- PromiseValueInternal* dest);
- using DeleteFunctionPtr = void (*)(PromiseValueInternal* object);
-
- // Similar to a virtual function but we don't need a dynamic memory
- // allocation. One possible design alternative would be to fold these methods
- // into T and use T in InlineAlloc (which would now have to
- // be bigger to accommodate the vtable pointer).
- // Eight byte alignment specified to allow TaggedTypeOpsPtr to store the state
- // in the low bits of the pointer.
- struct alignas(8) TypeOps {
-#if DCHECK_IS_ON()
- const char* type_name;
-#endif
- MoveFunctionPtr move_fn_ptr;
- DeleteFunctionPtr delete_fn_ptr;
- };
-
- template <typename T>
- struct TypeOpsHelper {
- static constexpr const char* TypeName() { return PRETTY_FUNCTION; }
-
- static constexpr TypeOps type_ops = {
-#if DCHECK_IS_ON()
- TypeName(),
-#endif
- &MoveHelper<T,
- InlineStorageHelper<T>::kUseInlineStorage,
- std::is_move_constructible<T>::value>::Move,
- &DeleteHelper<T, InlineStorageHelper<T>::kUseInlineStorage>::Delete};
- };
-
- static void NopMove(PromiseValueInternal* src, PromiseValueInternal* dest);
- static void NopDelete(PromiseValueInternal* src);
-
- static constexpr TypeOps null_type_ = {
-#if DCHECK_IS_ON()
- "EMPTY!",
-#endif
- &NopMove, &NopDelete};
-
- union {
- OutlineAlloc outline_alloc;
- InlineAlloc inline_alloc;
- } union_;
-};
-
-// static
-template <typename T>
-const PromiseValueInternal::TypeOps
- PromiseValueInternal::TypeOpsHelper<T>::type_ops;
-
-template <typename T>
-struct PromiseValueInternal::ConstructHelper<T, /* UseInlineStorage */ true> {
- template <typename... Args>
- static void Construct(PromiseValueInternal* dest, Args&&... args) noexcept {
- new (&dest->union_.inline_alloc.bytes) T(std::forward<Args>(args)...);
- }
-};
-
-template <typename T>
-struct PromiseValueInternal::ConstructHelper<T, /* UseInlineStorage */ false> {
- template <typename... Args>
- static void Construct(PromiseValueInternal* dest, Args&&... args) noexcept {
- dest->union_.outline_alloc.value = new T(std::forward<Args>(args)...);
- }
-};
-
-template <>
-struct PromiseValueInternal::GetStorageHelper</* UseInlineStorage */ true> {
- static void* GetStorage(PromiseValueInternal& any) {
- return &any.union_.inline_alloc.bytes;
- }
-
- static const void* GetStorage(const PromiseValueInternal& any) {
- return &any.union_.inline_alloc.bytes;
- }
-};
-
-template <>
-struct PromiseValueInternal::GetStorageHelper</* UseInlineStorage */ false> {
- static void* GetStorage(PromiseValueInternal& any) {
- return any.union_.outline_alloc.value;
- }
-
- static const void* GetStorage(const PromiseValueInternal& any) {
- return any.union_.outline_alloc.value;
- }
-};
-
-template <typename T>
-struct PromiseValueInternal::
- MoveHelper<T, /* UseInlineStorage */ true, /* HasMoveConstructor */ true> {
- static void Move(PromiseValueInternal* src, PromiseValueInternal* dest) {
- DCHECK_NE(src, dest);
- new (&dest->union_.inline_alloc.bytes)
- T(std::move(src->union_.inline_alloc.value_as<T>()));
- }
-};
-
-template <typename T>
-struct PromiseValueInternal::
- MoveHelper<T, /* UseInlineStorage */ true, /* HasMoveConstructor */ false> {
- static void Move(PromiseValueInternal* src, PromiseValueInternal* dest) {
- DCHECK_NE(src, dest);
- // Fall back to the copy constructor.
- new (&dest->union_.inline_alloc.bytes)
- T(src->union_.inline_alloc.value_as<T>());
- }
-};
-
-template <typename T, bool HasMoveConstructor>
-struct PromiseValueInternal::
- MoveHelper<T, /* UseInlineStorage */ false, HasMoveConstructor> {
- static void Move(PromiseValueInternal* src, PromiseValueInternal* dest) {
- DCHECK_NE(src, dest);
- dest->union_.outline_alloc.value = src->union_.outline_alloc.value;
- src->union_.outline_alloc.value = nullptr;
- }
-};
-
-template <typename T>
-struct PromiseValueInternal::DeleteHelper<T, /* UseInlineStorage */ true> {
- static void Delete(PromiseValueInternal* any) {
- reinterpret_cast<T*>(&any->union_.inline_alloc.bytes)->~T();
- }
-};
-
-template <typename T>
-struct PromiseValueInternal::DeleteHelper<T, /* UseInlineStorage */ false> {
- static void Delete(PromiseValueInternal* any) {
- delete static_cast<T*>(any->union_.outline_alloc.value);
- }
-};
-
-template <typename T>
-struct PromiseValueInternal::TypeToStateHelper {
- static constexpr State state = State::INVALID;
-};
-
-template <>
-struct PromiseValueInternal::TypeToStateHelper<PromiseExecutor> {
- static constexpr State state = State::PROMISE_EXECUTOR;
-};
-
-template <>
-struct PromiseValueInternal::TypeToStateHelper<scoped_refptr<AbstractPromise>> {
- static constexpr State state = State::CURRIED_PROMISE;
-};
-
-template <typename T>
-struct PromiseValueInternal::TypeToStateHelper<Resolved<T>> {
- static constexpr State state = State::RESOLVED;
-};
-
-template <typename T>
-struct PromiseValueInternal::TypeToStateHelper<Rejected<T>> {
- static constexpr State state = State::REJECTED;
-};
-
-class TaggedTypeOpsPtr {
- public:
- using State = PromiseValueInternal::State;
- using TypeOps = PromiseValueInternal::TypeOps;
-
- static_assert(static_cast<int>(State::INVALID) <= alignof(TypeOps),
- "The state enum must fit in the low bits of the TypeOps "
- "address");
-
- void Set(const TypeOps* type_ops, PromiseValueInternal::State state) {
- DCHECK_EQ(reinterpret_cast<uintptr_t>(type_ops) & kStateMask, 0u)
- << type_ops;
- type_ops_ =
- reinterpret_cast<uintptr_t>(type_ops) | static_cast<uintptr_t>(state);
- }
-
- TypeOps* get() const {
- return reinterpret_cast<TypeOps*>(type_ops_ & ~kStateMask);
- }
-
- TypeOps* operator->() const { return get(); }
-
- State GetState() const { return static_cast<State>(type_ops_ & kStateMask); }
-
- private:
- static constexpr uintptr_t kStateMask = alignof(TypeOps) - 1;
-
- uintptr_t type_ops_;
-};
-
-// Inspired by std::any<> this container is used to hold a Promise's value which
-// can be one of: Empty, PromiseExecutor, scoped_refptr<AbstractPromise>,
-// Resolved<> or Rejected<>. Unlike std::any PromiseValue can hold move only
-// types and it doesn't require exceptions.
-class BASE_EXPORT PromiseValue {
- private:
- using State = PromiseValueInternal::State;
- using TypeOps = PromiseValueInternal::TypeOps;
-
- template <typename T>
- using TypeOpsHelper = PromiseValueInternal::TypeOpsHelper<T>;
-
- template <typename T>
- using Construct = PromiseValueInternal::ConstructHelper<
- T,
- PromiseValueInternal::InlineStorageHelper<T>::kUseInlineStorage>;
-
- public:
- PromiseValue() noexcept { MarkAsEmpty(); }
-
- // Constructs a PromiseValue containing |value| as long as |VT| isn't INVALID
- // according to TypeToStateHelper.
- // E.g. base::PromiseValue a(Resolved<int>(123));
- template <typename T,
- typename VT = std::decay_t<T>,
- State state = PromiseValueInternal::TypeToStateHelper<VT>::state,
- std::enable_if_t<state != State::INVALID>* = nullptr>
- explicit PromiseValue(T&& value) noexcept {
- Construct<VT>::Construct(&value_, std::move(value));
- type_ops_.Set(&TypeOpsHelper<VT>::type_ops, state);
- }
-
- // Constructs a PromiseValue containing an object of type T which is
- // initialized by std::forward<Args>(args). E.g.
- // base::unique_any a(base::in_place_type_t<Resolved<int>>(), 123);
- template <typename T,
- typename... Args,
- State state = PromiseValueInternal::TypeToStateHelper<T>::state,
- std::enable_if_t<state != State::INVALID>* = nullptr>
- explicit PromiseValue(in_place_type_t<T> /*tag*/, Args&&... args) noexcept {
- Construct<T>::Construct(&value_, std::forward<Args>(args)...);
- type_ops_.Set(&TypeOpsHelper<T>::type_ops, state);
- }
-
- // Constructs a PromiseValue with the value contained by |other| moved into
- // it.
- PromiseValue(PromiseValue&& other) noexcept {
- other.type_ops_->move_fn_ptr(&other.value_, &value_);
- type_ops_ = other.type_ops_;
- other.MarkAsEmpty();
- }
-
- ~PromiseValue() { reset(); }
-
- void reset() {
- type_ops_->delete_fn_ptr(&value_);
- MarkAsEmpty();
- }
-
- bool has_value() const noexcept {
- return type_ops_.GetState() != State::EMPTY;
- }
-
- // Clears the existing value and constructs a an object of type T which is
- // initialized by std::forward<Args>(args).
- template <typename T,
- typename... Args,
- typename VT = std::decay_t<T>,
- State state = PromiseValueInternal::TypeToStateHelper<VT>::state,
- std::enable_if_t<state != State::INVALID>* = nullptr>
- void emplace(in_place_type_t<T> /*tag*/, Args&&... args) noexcept {
- type_ops_->delete_fn_ptr(&value_);
- Construct<VT>::Construct(&value_, std::forward<Args>(args)...);
- type_ops_.Set(&TypeOpsHelper<VT>::type_ops, state);
- }
-
- // Assigns |t| as long as |VT| isn't INVALID according to TypeToStateHelper.
- template <typename T,
- typename VT = std::decay_t<T>,
- State state = PromiseValueInternal::TypeToStateHelper<VT>::state,
- std::enable_if_t<state != State::INVALID>* = nullptr>
- void operator=(T&& t) noexcept {
- type_ops_->delete_fn_ptr(&value_);
- Construct<VT>::Construct(&value_, std::forward<T>(t));
- type_ops_.Set(&TypeOpsHelper<VT>::type_ops, state);
- }
-
- void operator=(PromiseValue&& other) noexcept {
- DCHECK_NE(this, &other);
- type_ops_->delete_fn_ptr(&value_);
- other.type_ops_->move_fn_ptr(&other.value_, &value_);
- type_ops_ = other.type_ops_;
- other.MarkAsEmpty();
- }
-
- bool ContainsPromiseExecutor() const {
- return type_ops_.GetState() == State::PROMISE_EXECUTOR;
- }
-
- bool ContainsCurriedPromise() const {
- return type_ops_.GetState() == State::CURRIED_PROMISE;
- }
-
- bool ContainsResolved() const {
- return type_ops_.GetState() == State::RESOLVED;
- }
-
- bool ContainsRejected() const {
- return type_ops_.GetState() == State::REJECTED;
- }
-
- template <typename T,
- typename VT = std::decay_t<T>,
- State state = PromiseValueInternal::TypeToStateHelper<VT>::state,
- std::enable_if_t<state != State::INVALID>* = nullptr>
- T* Get() noexcept {
- DCHECK_EQ(state, type_ops_.GetState());
- // Unfortunately we can't rely on the addresses of the TypeOps being the
- // same across .so boundaries unless every part of |VT| is exported so we
- // do a string comparison instead to check the right type is used.
-#if DCHECK_IS_ON()
- DCHECK_EQ(type_ops_->type_name,
- std::string(TypeOpsHelper<VT>::type_ops.type_name));
-#endif
- return static_cast<T*>(value_.GetStorage<VT>());
- }
-
- template <typename T,
- typename VT = std::decay_t<T>,
- State state = PromiseValueInternal::TypeToStateHelper<VT>::state,
- std::enable_if_t<state != State::INVALID>* = nullptr>
- const T* Get() const noexcept {
- DCHECK_EQ(state, type_ops_.GetState());
- // Unfortunately we can't rely on the addresses of the TypeOps being the
- // same across .so boundaries unless every part of |VT| is exported so we
- // do a string comparison instead to check the right type is used.
-#if DCHECK_IS_ON()
- DCHECK_EQ(type_ops_->type_name,
- std::string(TypeOpsHelper<VT>::type_ops.type_name));
-#endif
- return static_cast<const T*>(value_.GetStorage<VT>());
- }
-
- private:
- void MarkAsEmpty() {
- type_ops_.Set(&PromiseValueInternal::null_type_, State::EMPTY);
- }
-
- PromiseValueInternal value_;
- TaggedTypeOpsPtr type_ops_;
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_PROMISE_VALUE_H_
diff --git a/task/promise/promise_value_unittest.cc b/task/promise/promise_value_unittest.cc
deleted file mode 100644
index 1b90fa2..0000000
--- a/task/promise/promise_value_unittest.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/promise_value.h"
-
-#include "base/task/promise/no_op_promise_executor.h"
-#include "base/test/copy_only_int.h"
-#include "base/test/do_nothing_promise.h"
-#include "base/test/move_only_int.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace internal {
-
-namespace {
-
-struct IntMoveOnlyCopyOnlyInt {
- IntMoveOnlyCopyOnlyInt(int value,
- MoveOnlyInt /*move_only*/,
- CopyOnlyInt /*copy_only*/)
- : value(value) {}
-
- int value;
-};
-
-class DestructDetector {
- public:
- explicit DestructDetector(bool* destructor_called)
- : destructor_called_(destructor_called) {}
-
- ~DestructDetector() { *destructor_called_ = true; }
-
- private:
- bool* destructor_called_; // NOT OWNED
-};
-
-} // namespace
-
-TEST(PromiseValueTest, Noexcept) {
- static_assert(std::is_nothrow_default_constructible<PromiseValue>(), "");
- static_assert(std::is_nothrow_move_constructible<PromiseValue>(), "");
- static_assert(std::is_nothrow_move_assignable<PromiseValue>(), "");
- static_assert(noexcept(std::declval<PromiseValue&>().has_value()), "");
- static_assert(noexcept(std::declval<PromiseValue&>().Get<Resolved<int>>()),
- "");
-}
-
-TEST(PromiseValueTest, HasValue) {
- PromiseValue o;
- EXPECT_FALSE(o.has_value());
- o = Resolved<int>();
- EXPECT_TRUE(o.has_value());
- o.reset();
- EXPECT_FALSE(o.has_value());
-}
-
-TEST(PromiseValueTest, Construction) {
- PromiseValue value(in_place_type_t<PromiseExecutor>(),
- PromiseExecutor::Data(
- in_place_type_t<NoOpPromiseExecutor>(), true, true));
-
- EXPECT_TRUE(value.has_value());
- EXPECT_TRUE(value.ContainsPromiseExecutor());
- EXPECT_FALSE(value.ContainsCurriedPromise());
- EXPECT_FALSE(value.ContainsResolved());
- EXPECT_FALSE(value.ContainsRejected());
-}
-
-TEST(PromiseValueTest, InPlaceConstruction) {
- const CopyOnlyInt copy_only{};
- PromiseValue o(in_place_type_t<Resolved<IntMoveOnlyCopyOnlyInt>>(), 5,
- MoveOnlyInt(), copy_only);
- IntMoveOnlyCopyOnlyInt& v = o.Get<Resolved<IntMoveOnlyCopyOnlyInt>>()->value;
- EXPECT_EQ(5, v.value);
-}
-
-TEST(PromiseValueTest, EmplaceInplaceType) {
- PromiseValue value;
- EXPECT_FALSE(value.has_value());
-
- value.emplace(in_place_type_t<Rejected<int>>(), 123);
- EXPECT_TRUE(value.has_value());
- EXPECT_FALSE(value.ContainsPromiseExecutor());
- EXPECT_FALSE(value.ContainsCurriedPromise());
- EXPECT_FALSE(value.ContainsResolved());
- EXPECT_TRUE(value.ContainsRejected());
- EXPECT_EQ(123, value.template Get<Rejected<int>>()->value);
-}
-
-TEST(PromiseValueTest, Reset) {
- PromiseValue value(in_place_type_t<PromiseExecutor>(),
- PromiseExecutor::Data(
- in_place_type_t<NoOpPromiseExecutor>(), true, true));
-
- EXPECT_TRUE(value.has_value());
- value.reset();
-
- EXPECT_FALSE(value.has_value());
- EXPECT_FALSE(value.ContainsPromiseExecutor());
- EXPECT_FALSE(value.ContainsCurriedPromise());
- EXPECT_FALSE(value.ContainsResolved());
- EXPECT_FALSE(value.ContainsRejected());
-}
-
-TEST(PromiseValueTest, AssignCurriedPromise) {
- PromiseValue value(in_place_type_t<PromiseExecutor>(),
- PromiseExecutor::Data(
- in_place_type_t<NoOpPromiseExecutor>(), true, true));
- scoped_refptr<AbstractPromise> promise = DoNothingPromiseBuilder(FROM_HERE);
-
- EXPECT_FALSE(value.ContainsCurriedPromise());
- value = promise;
-
- EXPECT_TRUE(value.ContainsCurriedPromise());
- EXPECT_EQ(promise, *value.Get<scoped_refptr<AbstractPromise>>());
-}
-
-TEST(PromiseValueTest, AssignResolvedValue) {
- PromiseValue value(in_place_type_t<PromiseExecutor>(),
- PromiseExecutor::Data(
- in_place_type_t<NoOpPromiseExecutor>(), true, true));
-
- EXPECT_FALSE(value.ContainsResolved());
- value = base::Resolved<int>(123);
-
- EXPECT_TRUE(value.ContainsResolved());
- EXPECT_EQ(123, value.Get<Resolved<int>>()->value);
-}
-
-TEST(PromiseValueTest, AssignRejectedValue) {
- PromiseValue value(in_place_type_t<PromiseExecutor>(),
- PromiseExecutor::Data(
- in_place_type_t<NoOpPromiseExecutor>(), true, true));
-
- EXPECT_FALSE(value.ContainsRejected());
- value = base::Rejected<int>(123);
-
- EXPECT_TRUE(value.ContainsRejected());
- EXPECT_EQ(123, value.Get<Rejected<int>>()->value);
-}
-
-TEST(PromiseValueTest, EmplaceRejectedTuple) {
- PromiseValue value(in_place_type_t<PromiseExecutor>(),
- PromiseExecutor::Data(
- in_place_type_t<NoOpPromiseExecutor>(), true, true));
-
- EXPECT_FALSE(value.ContainsRejected());
- value.emplace(in_place_type_t<base::Rejected<std::tuple<int, std::string>>>(),
- 123, "Hello");
-
- EXPECT_TRUE(value.ContainsRejected());
- EXPECT_EQ(
- 123,
- std::get<0>(value.Get<Rejected<std::tuple<int, std::string>>>()->value));
- EXPECT_EQ(
- "Hello",
- std::get<1>(value.Get<Rejected<std::tuple<int, std::string>>>()->value));
-}
-
-TEST(PromiseValueTest, ConversionConstruction) {
- {
- PromiseValue o(Rejected<int>(3));
- EXPECT_EQ(3, o.Get<Rejected<int>>()->value);
- }
-
- {
- const CopyOnlyInt copy_only(5);
- PromiseValue o = PromiseValue(Resolved<CopyOnlyInt>(copy_only));
- EXPECT_EQ(5, o.Get<Resolved<CopyOnlyInt>>()->value.data());
- }
-
- {
- MoveOnlyInt i{123};
- PromiseValue o(Rejected<MoveOnlyInt>(std::move(i)));
- EXPECT_EQ(123, o.Get<Rejected<MoveOnlyInt>>()->value.data());
- }
-}
-
-TEST(PromiseValueTest, ConversionAssignment) {
- {
- PromiseValue o;
- o = Rejected<int>(3);
- EXPECT_EQ(3, o.Get<Rejected<int>>()->value);
- }
-
- {
- const CopyOnlyInt copy_only(5);
- PromiseValue o;
- o = Resolved<CopyOnlyInt>(copy_only);
- EXPECT_EQ(5, o.Get<Resolved<CopyOnlyInt>>()->value.data());
- }
-
- {
- MoveOnlyInt i{123};
- PromiseValue o;
- o = Rejected<MoveOnlyInt>(std::move(i));
- EXPECT_EQ(123, o.Get<Rejected<MoveOnlyInt>>()->value.data());
- }
-}
-
-TEST(PromiseValueTest, DestructorCalled) {
- bool destructor_called = false;
-
- {
- PromiseValue a;
- a.emplace(in_place_type_t<Resolved<DestructDetector>>(),
- &destructor_called);
- EXPECT_FALSE(destructor_called);
- }
-
- EXPECT_TRUE(destructor_called);
-}
-
-TEST(PromiseValueTest, DestructorCalledOnAssignment) {
- bool destructor_called = false;
-
- PromiseValue a;
- a.emplace(in_place_type_t<Rejected<DestructDetector>>(), &destructor_called);
-
- EXPECT_FALSE(destructor_called);
- a = Resolved<int>(123);
- EXPECT_TRUE(destructor_called);
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/then_and_catch_executor.cc b/task/promise/then_and_catch_executor.cc
deleted file mode 100644
index 5eb38e9..0000000
--- a/task/promise/then_and_catch_executor.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/task/promise/then_and_catch_executor.h"
-
-namespace base {
-namespace internal {
-
-bool ThenAndCatchExecutorCommon::IsCancelled() const {
- if (!then_callback_.is_null()) {
- // If there is both a resolve and a reject executor they must be canceled
- // at the same time.
- DCHECK(catch_callback_.is_null() ||
- catch_callback_.IsCancelled() == then_callback_.IsCancelled());
- return then_callback_.IsCancelled();
- }
- return catch_callback_.IsCancelled();
-}
-
-void ThenAndCatchExecutorCommon::Execute(AbstractPromise* promise,
- ExecuteCallback execute_then,
- ExecuteCallback execute_catch) {
- AbstractPromise* prerequisite = promise->GetOnlyPrerequisite();
- if (prerequisite->IsResolved()) {
- if (ProcessNullCallback(then_callback_, prerequisite, promise))
- return;
-
- execute_then(prerequisite, promise, &then_callback_);
- } else {
- DCHECK(prerequisite->IsRejected());
- if (ProcessNullCallback(catch_callback_, prerequisite, promise))
- return;
-
- execute_catch(prerequisite, promise, &catch_callback_);
- }
-}
-
-// static
-bool ThenAndCatchExecutorCommon::ProcessNullCallback(
- const CallbackBase& callback,
- AbstractPromise* arg,
- AbstractPromise* result) {
- if (callback.is_null()) {
- // A curried promise is used to forward the result through null callbacks.
- result->emplace(scoped_refptr<AbstractPromise>(arg));
- DCHECK(result->IsResolvedWithPromise());
- return true;
- }
-
- return false;
-}
-
-} // namespace internal
-} // namespace base
diff --git a/task/promise/then_and_catch_executor.h b/task/promise/then_and_catch_executor.h
deleted file mode 100644
index 7668fc1..0000000
--- a/task/promise/then_and_catch_executor.h
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_PROMISE_THEN_AND_CATCH_EXECUTOR_H_
-#define BASE_TASK_PROMISE_THEN_AND_CATCH_EXECUTOR_H_
-
-#include <type_traits>
-
-#include "base/callback.h"
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/helpers.h"
-
-namespace base {
-namespace internal {
-
-// Exists to reduce template bloat.
-class BASE_EXPORT ThenAndCatchExecutorCommon {
- public:
- ThenAndCatchExecutorCommon(internal::CallbackBase&& then_callback,
- internal::CallbackBase&& catch_callback) noexcept
- : then_callback_(std::move(then_callback)),
- catch_callback_(std::move(catch_callback)) {
- DCHECK(!then_callback_.is_null() || !catch_callback_.is_null());
- }
-
- ~ThenAndCatchExecutorCommon() = default;
-
- // PromiseExecutor:
- bool IsCancelled() const;
- PromiseExecutor::PrerequisitePolicy GetPrerequisitePolicy() const;
-
- using ExecuteCallback = void (*)(AbstractPromise* prerequisite,
- AbstractPromise* promise,
- CallbackBase* callback);
-
- void Execute(AbstractPromise* promise,
- ExecuteCallback execute_then,
- ExecuteCallback execute_catch);
-
- // If |executor| is null then the value of |arg| is moved or copied into
- // |result| and true is returned. Otherwise false is returned.
- static bool ProcessNullCallback(const CallbackBase& executor,
- AbstractPromise* arg,
- AbstractPromise* result);
-
- CallbackBase then_callback_;
- CallbackBase catch_callback_;
-};
-
-// Tag signals no callback which is used to eliminate dead code.
-struct NoCallback {};
-
-template <typename ThenOnceCallback,
- typename CatchOnceCallback,
- typename ArgResolve,
- typename ArgReject,
- typename ResolveStorage,
- typename RejectStorage>
-class ThenAndCatchExecutor {
- public:
- using ThenReturnT = typename CallbackTraits<ThenOnceCallback>::ReturnType;
- using CatchReturnT = typename CallbackTraits<CatchOnceCallback>::ReturnType;
- using PrerequisiteCouldResolve =
- std::integral_constant<bool,
- !std::is_same<ArgResolve, NoCallback>::value>;
- using PrerequisiteCouldReject =
- std::integral_constant<bool, !std::is_same<ArgReject, NoCallback>::value>;
-
- ThenAndCatchExecutor(CallbackBase&& resolve_callback,
- CallbackBase&& catch_callback) noexcept
- : common_(std::move(resolve_callback), std::move(catch_callback)) {}
-
- bool IsCancelled() const { return common_.IsCancelled(); }
-
- static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
- PromiseExecutor::PrerequisitePolicy::kAll;
-
- using ExecuteCallback = ThenAndCatchExecutorCommon::ExecuteCallback;
-
- void Execute(AbstractPromise* promise) {
- return common_.Execute(promise, &ExecuteThen, &ExecuteCatch);
- }
-
-#if DCHECK_IS_ON()
- PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const {
- return common_.then_callback_.is_null()
- ? PromiseExecutor::ArgumentPassingType::kNoCallback
- : CallbackTraits<ThenOnceCallback>::argument_passing_type;
- }
-
- PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const {
- return common_.catch_callback_.is_null()
- ? PromiseExecutor::ArgumentPassingType::kNoCallback
- : CallbackTraits<CatchOnceCallback>::argument_passing_type;
- }
-
- bool CanResolve() const {
- return (!common_.then_callback_.is_null() &&
- PromiseCallbackTraits<ThenReturnT>::could_resolve) ||
- (!common_.catch_callback_.is_null() &&
- PromiseCallbackTraits<CatchReturnT>::could_resolve);
- }
-
- bool CanReject() const {
- return (!common_.then_callback_.is_null() &&
- PromiseCallbackTraits<ThenReturnT>::could_reject) ||
- (!common_.catch_callback_.is_null() &&
- PromiseCallbackTraits<CatchReturnT>::could_reject);
- }
-#endif
-
- private:
- static void ExecuteThen(AbstractPromise* prerequisite,
- AbstractPromise* promise,
- CallbackBase* resolve_callback) {
- ExecuteThenInternal(prerequisite, promise, resolve_callback,
- PrerequisiteCouldResolve());
- }
-
- static void ExecuteCatch(AbstractPromise* prerequisite,
- AbstractPromise* promise,
- CallbackBase* catch_callback) {
- ExecuteCatchInternal(prerequisite, promise, catch_callback,
- PrerequisiteCouldReject());
- }
-
- static void ExecuteThenInternal(AbstractPromise* prerequisite,
- AbstractPromise* promise,
- CallbackBase* resolve_callback,
- std::true_type can_resolve) {
- // Internally RunHelper uses const RepeatingCallback<>& to avoid the
- // binary size overhead of moving a scoped_refptr<> about. We respect
- // the onceness of the callback and RunHelper will overwrite the callback
- // with the result.
- using RepeatingThenCB =
- typename ToRepeatingCallback<ThenOnceCallback>::value;
- RunHelper<
- RepeatingThenCB, Resolved<ArgResolve>, ResolveStorage,
- RejectStorage>::Run(*static_cast<RepeatingThenCB*>(resolve_callback),
- prerequisite, promise);
- }
-
- static void ExecuteThenInternal(AbstractPromise* prerequisite,
- AbstractPromise* promise,
- CallbackBase* resolve_callback,
- std::false_type can_resolve) {
- // |prerequisite| can't resolve so don't generate dead code.
- }
-
- static void ExecuteCatchInternal(AbstractPromise* prerequisite,
- AbstractPromise* promise,
- CallbackBase* catch_callback,
- std::true_type can_reject) {
- // Internally RunHelper uses const RepeatingCallback<>& to avoid the
- // binary size overhead of moving a scoped_refptr<> about. We respect
- // the onceness of the callback and RunHelper will overwrite the callback
- // with the result.
- using RepeatingCatchCB =
- typename ToRepeatingCallback<CatchOnceCallback>::value;
- RunHelper<
- RepeatingCatchCB, Rejected<ArgReject>, ResolveStorage,
- RejectStorage>::Run(*static_cast<RepeatingCatchCB*>(catch_callback),
- prerequisite, promise);
- }
-
- static void ExecuteCatchInternal(AbstractPromise* prerequisite,
- AbstractPromise* promise,
- CallbackBase* catch_callback,
- std::false_type can_reject) {
- // |prerequisite| can't reject so don't generate dead code.
- }
-
- ThenAndCatchExecutorCommon common_;
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_TASK_PROMISE_THEN_AND_CATCH_EXECUTOR_H_
diff --git a/task/thread_pool/thread_pool_impl.cc b/task/thread_pool/thread_pool_impl.cc
index 473fa40..57546e8 100644
--- a/task/thread_pool/thread_pool_impl.cc
+++ b/task/thread_pool/thread_pool_impl.cc
@@ -16,6 +16,7 @@
#include "base/feature_list.h"
#include "base/message_loop/message_pump_type.h"
#include "base/metrics/field_trial_params.h"
+#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/task/scoped_set_task_priority_for_current_thread.h"
diff --git a/task_runner.cc b/task_runner.cc
index 06aca8a..77726b9 100644
--- a/task_runner.cc
+++ b/task_runner.cc
@@ -9,8 +9,6 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
-#include "base/task/promise/abstract_promise.h"
-#include "base/task/promise/helpers.h"
#include "base/threading/post_task_and_reply_impl.h"
namespace base {
@@ -54,16 +52,6 @@
from_here, std::move(task), std::move(reply));
}
-bool TaskRunner::PostPromiseInternal(WrappedPromise promise,
- base::TimeDelta delay) {
- Location from_here = promise.from_here();
- return PostDelayedTask(
- from_here,
- BindOnce([](WrappedPromise promise) { promise.Execute(); },
- std::move(promise)),
- delay);
-}
-
TaskRunner::TaskRunner() = default;
TaskRunner::~TaskRunner() = default;
diff --git a/task_runner.h b/task_runner.h
index 2bd5d4e..8c2e5d1 100644
--- a/task_runner.h
+++ b/task_runner.h
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/task/promise/abstract_promise.h"
#include "base/time/time.h"
namespace base {
@@ -134,10 +133,6 @@
OnceClosure task,
OnceClosure reply);
- // TODO(alexclarke): This should become pure virtual and replace
- // PostDelayedTask. NB passing by reference to reduce binary size.
- bool PostPromiseInternal(WrappedPromise promise, base::TimeDelta delay);
-
protected:
friend struct TaskRunnerTraits;
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 791c440..76e8549 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -51,8 +51,6 @@
"bind_test_util.h",
"copy_only_int.cc",
"copy_only_int.h",
- "do_nothing_promise.cc",
- "do_nothing_promise.h",
"gmock_callback_support.h",
"gtest_util.cc",
"gtest_util.h",
diff --git a/test/do_nothing_promise.cc b/test/do_nothing_promise.cc
deleted file mode 100644
index f2834ca..0000000
--- a/test/do_nothing_promise.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/test/do_nothing_promise.h"
-
-namespace base {
-
-DoNothingPromiseBuilder::operator WrappedPromise() const {
- return WrappedPromise(internal::NoOpPromiseExecutor::Create(
- from_here, can_resolve, can_reject, reject_policy));
-}
-
-DoNothingPromiseBuilder::operator scoped_refptr<internal::AbstractPromise>()
- const {
- return WrappedPromise(internal::NoOpPromiseExecutor::Create(
- from_here, can_resolve, can_reject, reject_policy))
- .TakeForTesting();
-}
-
-} // namespace base
diff --git a/test/do_nothing_promise.h b/test/do_nothing_promise.h
deleted file mode 100644
index 6c8f4ec..0000000
--- a/test/do_nothing_promise.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TEST_DO_NOTHING_PROMISE_H_
-#define BASE_TEST_DO_NOTHING_PROMISE_H_
-
-#include "base/task/promise/no_op_promise_executor.h"
-
-namespace base {
-
-// Creates a promise whose executor doesn't do anything.
-struct DoNothingPromiseBuilder {
- explicit DoNothingPromiseBuilder(Location from_here) : from_here(from_here) {}
-
- const Location from_here;
- bool can_resolve = false;
- bool can_reject = false;
- RejectPolicy reject_policy = RejectPolicy::kMustCatchRejection;
-
- DoNothingPromiseBuilder& SetCanResolve(bool can_resolve_v) {
- can_resolve = can_resolve_v;
- return *this;
- }
-
- DoNothingPromiseBuilder& SetCanReject(bool can_reject_v) {
- can_reject = can_reject_v;
- return *this;
- }
-
- DoNothingPromiseBuilder& SetRejectPolicy(RejectPolicy reject_policy_v) {
- reject_policy = reject_policy_v;
- return *this;
- }
-
- operator WrappedPromise() const;
-
- operator scoped_refptr<internal::AbstractPromise>() const;
-};
-
-} // namespace base
-
-#endif // BASE_TEST_DO_NOTHING_PROMISE_H_