Commit d7f3085a authored by Lewis Baker's avatar Lewis Baker Committed by Facebook Github Bot

Make folly::coro::blockingWait() work with all SemiAwaitables

Summary: This allows using blockingWait() with folly::SemiFuture.

Reviewed By: andriigrynenko

Differential Revision: D14658875

fbshipit-source-id: a99505bee3a9947d5fe89760ab495fce5679a0a1
parent 381a2d39
...@@ -63,7 +63,10 @@ class BlockingWaitPromiseBase { ...@@ -63,7 +63,10 @@ class BlockingWaitPromiseBase {
return {}; return {};
} }
protected: bool done() const noexcept {
return baton_.ready();
}
void wait() noexcept { void wait() noexcept {
baton_.wait(); baton_.wait();
} }
...@@ -94,18 +97,8 @@ class BlockingWaitPromise final : public BlockingWaitPromiseBase { ...@@ -94,18 +97,8 @@ class BlockingWaitPromise final : public BlockingWaitPromiseBase {
result_->emplace(static_cast<U&&>(value)); result_->emplace(static_cast<U&&>(value));
} }
folly::Try<T> getAsTry() { void setTry(folly::Try<T>* result) noexcept {
folly::Try<T> result;
result_ = &result; result_ = &result;
std::experimental::coroutine_handle<BlockingWaitPromise<T>>::from_promise(
*this)
.resume();
this->wait();
return result;
}
T get() {
return getAsTry().value();
} }
private: private:
...@@ -150,18 +143,8 @@ class BlockingWaitPromise<T&> final : public BlockingWaitPromiseBase { ...@@ -150,18 +143,8 @@ class BlockingWaitPromise<T&> final : public BlockingWaitPromiseBase {
std::abort(); std::abort();
} }
folly::Try<std::reference_wrapper<T>> getAsTry() { void setTry(folly::Try<std::reference_wrapper<T>>* result) noexcept {
folly::Try<std::reference_wrapper<T>> result; result_ = result;
result_ = &result;
std::experimental::coroutine_handle<BlockingWaitPromise<T&>>::from_promise(
*this)
.resume();
this->wait();
return result;
}
T& get() {
return getAsTry().value();
} }
private: private:
...@@ -182,18 +165,8 @@ class BlockingWaitPromise<void> final : public BlockingWaitPromiseBase { ...@@ -182,18 +165,8 @@ class BlockingWaitPromise<void> final : public BlockingWaitPromiseBase {
exception_wrapper::from_exception_ptr(std::current_exception())); exception_wrapper::from_exception_ptr(std::current_exception()));
} }
folly::Try<void> getAsTry() { void setTry(folly::Try<void>* result) noexcept {
folly::Try<void> result; result_ = result;
result_ = &result;
std::experimental::coroutine_handle<
BlockingWaitPromise<void>>::from_promise(*this)
.resume();
this->wait();
return result;
}
void get() {
return getAsTry().value();
} }
private: private:
...@@ -219,12 +192,28 @@ class BlockingWaitTask { ...@@ -219,12 +192,28 @@ class BlockingWaitTask {
} }
} }
decltype(auto) getAsTry() && { folly::Try<detail::lift_lvalue_reference_t<T>> getAsTry() && {
return coro_.promise().getAsTry(); folly::Try<detail::lift_lvalue_reference_t<T>> result;
auto& promise = coro_.promise();
promise.setTry(&result);
coro_.resume();
promise.wait();
return result;
} }
decltype(auto) get() && { T get() && {
return coro_.promise().get(); return std::move(*this).getAsTry().value();
}
T getVia(folly::DrivableExecutor* executor) && {
folly::Try<detail::lift_lvalue_reference_t<T>> result;
auto& promise = coro_.promise();
promise.setTry(&result);
coro_.resume();
while (!promise.done()) {
executor->drive();
}
return std::move(result).value();
} }
private: private:
...@@ -310,22 +299,19 @@ auto blockingWait(Awaitable&& awaitable) ...@@ -310,22 +299,19 @@ auto blockingWait(Awaitable&& awaitable)
.get()); .get());
} }
template <typename T> template <
T blockingWait(Task<T>&& task) { typename SemiAwaitable,
using StorageType = detail::lift_lvalue_reference_t<T>; std::enable_if_t<!is_awaitable_v<SemiAwaitable>, int> = 0>
auto blockingWait(SemiAwaitable&& awaitable)
-> detail::decay_rvalue_reference_t<semi_await_result_t<SemiAwaitable>> {
folly::ManualExecutor executor; folly::ManualExecutor executor;
Try<StorageType> ret; return static_cast<
bool done{false}; std::add_rvalue_reference_t<semi_await_result_t<SemiAwaitable>>>(
detail::makeRefBlockingWaitTask(
std::move(task).scheduleOn(&executor).start([&](Try<StorageType>&& result) { folly::coro::co_viaIfAsync(
ret = std::move(result); folly::getKeepAliveToken(executor),
done = true; static_cast<SemiAwaitable&&>(awaitable)))
}); .getVia(&executor));
while (!done) {
executor.drive();
}
return std::move(ret).value();
} }
} // namespace coro } // namespace coro
......
...@@ -244,4 +244,9 @@ TEST(BlockingWait, WaitInFiber) { ...@@ -244,4 +244,9 @@ TEST(BlockingWait, WaitInFiber) {
EXPECT_EQ(42, std::move(future).get()); EXPECT_EQ(42, std::move(future).get());
} }
TEST(BlockingWait, WaitOnSemiFuture) {
int result = folly::coro::blockingWait(folly::makeSemiFuture(123));
CHECK_EQ(result, 123);
}
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment