Commit 3597c587 authored by Dylan Yudaken's avatar Dylan Yudaken Committed by Facebook Github Bot

Allow awaiting on a folly::Optional that returns a move-only type

Summary:
await_resume is only called once, so this allows it to move the value out.
At the same time remove a redundant clear (but keep the existing requirement that the promise type is an OptionalPromise), and clean up the tests.
Also add a test to make sure the coroutine is cleaned up

Reviewed By: ericniebler

Differential Revision: D5834861

fbshipit-source-id: 7ad487e818969cdf6fe27c9e82931aa247daf4e4
parent 481365ef
...@@ -598,13 +598,14 @@ struct OptionalAwaitable { ...@@ -598,13 +598,14 @@ struct OptionalAwaitable {
return o_.hasValue(); return o_.hasValue();
} }
Value await_resume() { Value await_resume() {
return o_.value(); return std::move(o_.value());
} }
template <typename CoroHandle>
void await_suspend(CoroHandle h) const { // Explicitly only allow suspension into an OptionalPromise
// make sure the coroutine returns an empty Optional: template <typename U>
h.promise().value_->clear(); void await_suspend(
// Abort the rest of the coroutine: std::experimental::coroutine_handle<OptionalPromise<U>> h) const {
// Abort the rest of the coroutine. resume() is not going to be called
h.destroy(); h.destroy();
} }
}; };
...@@ -617,7 +618,7 @@ detail::OptionalAwaitable<Value> ...@@ -617,7 +618,7 @@ detail::OptionalAwaitable<Value>
} }
} // namespace folly } // namespace folly
// This makes std::optional<Value> useable as a coroutine return type.. // This makes folly::Optional<Value> useable as a coroutine return type..
FOLLY_NAMESPACE_STD_BEGIN FOLLY_NAMESPACE_STD_BEGIN
namespace experimental { namespace experimental {
template <typename Value, typename... Args> template <typename Value, typename... Args>
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <folly/Optional.h> #include <folly/Optional.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/ScopeGuard.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#if FOLLY_HAS_COROUTINES #if FOLLY_HAS_COROUTINES
...@@ -27,8 +28,10 @@ Optional<int> f1() { ...@@ -27,8 +28,10 @@ Optional<int> f1() {
Optional<double> f2(int x) { Optional<double> f2(int x) {
return 2.0 * x; return 2.0 * x;
} }
Optional<int> f3(int x, double y) {
return (int)(x + y); // move-only type
Optional<std::unique_ptr<int>> f3(int x, double y) {
return std::make_unique<int>((int)(x + y));
} }
TEST(Optional, CoroutineSuccess) { TEST(Optional, CoroutineSuccess) {
...@@ -38,8 +41,8 @@ TEST(Optional, CoroutineSuccess) { ...@@ -38,8 +41,8 @@ TEST(Optional, CoroutineSuccess) {
auto y = co_await f2(x); auto y = co_await f2(x);
EXPECT_EQ(2.0 * 7, y); EXPECT_EQ(2.0 * 7, y);
auto z = co_await f3(x, y); auto z = co_await f3(x, y);
EXPECT_EQ((int)(2.0 * 7 + 7), z); EXPECT_EQ((int)(2.0 * 7 + 7), *z);
co_return z; co_return* z;
}(); }();
EXPECT_TRUE(r0.hasValue()); EXPECT_TRUE(r0.hasValue());
EXPECT_EQ(21, *r0); EXPECT_EQ(21, *r0);
...@@ -54,7 +57,7 @@ TEST(Optional, CoroutineFailure) { ...@@ -54,7 +57,7 @@ TEST(Optional, CoroutineFailure) {
auto x = co_await f1(); auto x = co_await f1();
auto y = co_await f2(x); auto y = co_await f2(x);
auto z = co_await f4(x, y); auto z = co_await f4(x, y);
EXPECT_FALSE(true); ADD_FAILURE();
co_return z; co_return z;
}(); }();
EXPECT_TRUE(!r1.hasValue()); EXPECT_TRUE(!r1.hasValue());
...@@ -68,14 +71,30 @@ TEST(Optional, CoroutineException) { ...@@ -68,14 +71,30 @@ TEST(Optional, CoroutineException) {
try { try {
auto r2 = []() -> Optional<int> { auto r2 = []() -> Optional<int> {
auto x = co_await throws(); auto x = co_await throws();
EXPECT_FALSE(true); ADD_FAILURE();
co_return x; co_return x;
}(); }();
EXPECT_FALSE(true); ADD_FAILURE();
} catch (/* nolint */ int i) { } catch (/* nolint */ int i) {
EXPECT_EQ(42, i); EXPECT_EQ(42, i);
} catch (...) { } catch (...) {
EXPECT_FALSE(true); ADD_FAILURE();
} }
} }
// this test makes sure that the coroutine is destroyed properly
TEST(Optional, CoroutineCleanedUp) {
int count_dest = 0;
auto r = [&]() -> Optional<int> {
SCOPE_EXIT {
++count_dest;
};
auto x = co_await folly::Optional<int>();
ADD_FAILURE() << "Should not be resuming";
co_return x;
}();
EXPECT_FALSE(r.hasValue());
EXPECT_EQ(1, count_dest);
}
#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