ImmediateFuture: allow implicit conversion from Future

Summary:
Future can be implicitly converted to SemiFuture, because it's a safe
operation in general. SemiFuture is a weaker interface.

The same reason allows us to implicitly convert SemiFuture to
ImmediateFuture.

Therefore, allow an implicit conversion from Future to
ImmediateFuture.

Reviewed By: xavierd

Differential Revision: D42086161

fbshipit-source-id: ef185101728755c099c87c2b5c15c2fe28e88b83
This commit is contained in:
Chad Austin 2022-12-19 13:11:02 -08:00 committed by Facebook GitHub Bot
parent 35db05f424
commit ea87aa398e
3 changed files with 43 additions and 1 deletions

View File

@ -16,6 +16,7 @@ template <typename T>
class ImmediateFuture;
namespace detail {
template <typename T>
struct isImmediateFuture : std::false_type {};
@ -30,7 +31,7 @@ struct continuation_result_impl {
template <typename T>
struct continuation_result_impl<
T,
typename std::enable_if_t<folly::isSemiFuture<T>::value>> {
typename std::enable_if_t<folly::isFutureOrSemiFuture<T>::value>> {
using type = typename T::value_type;
};

View File

@ -102,6 +102,14 @@ class ImmediateFuture {
/* implicit */ ImmediateFuture(folly::SemiFuture<T>&& fut) noexcept
: ImmediateFuture{std::move(fut), SemiFutureReadiness::EagerSemiFuture} {}
/**
* Construct an ImmediateFuture with a Future.
*
* This constructor has the same semantics as ImmediateFuture{future.semi()}.
*/
/* implicit */ ImmediateFuture(folly::Future<T>&& fut) noexcept
: ImmediateFuture{std::move(fut).semi()} {}
~ImmediateFuture();
ImmediateFuture(const ImmediateFuture&) = delete;

View File

@ -687,4 +687,37 @@ TEST(ImmediateFuture, in_place_construction_multiple_arguments) {
EXPECT_EQ("world", *result.second);
}
TEST(ImmediateFuture, conversion_from_ready_Future) {
auto fut = folly::makeFuture<int>(10);
// use = to ensure we can implicitly convert
ImmediateFuture<int> imm = std::move(fut);
EXPECT_FALSE(fut.valid());
EXPECT_TRUE(imm.valid());
EXPECT_NE(imm.isReady(), detail::kImmediateFutureAlwaysDefer);
EXPECT_EQ(10, std::move(imm).get());
}
TEST(ImmediateFuture, conversion_from_nonready_Future) {
folly::Promise<int> p;
auto fut = p.getFuture();
// use = to ensure we can implicitly convert
ImmediateFuture<int> imm = std::move(fut);
EXPECT_FALSE(fut.valid());
EXPECT_TRUE(imm.valid());
EXPECT_FALSE(imm.isReady());
p.setValue(10);
EXPECT_NE(imm.isReady(), detail::kImmediateFutureAlwaysDefer);
EXPECT_EQ(10, std::move(imm).get());
}
TEST(ImmediateFuture, then_with_Future) {
ImmediateFuture<int> imm = 10;
auto result = std::move(imm).thenValue([](int i) {
// It's funny to std::move() an int, but it's required to match makeFuture's
// type signature.
return folly::makeFuture<int>(std::move(i));
});
EXPECT_EQ(10, std::move(result).get());
}
} // namespace