Commit 634c47ea authored by Lee Howes's avatar Lee Howes Committed by Facebook Github Bot

toUnsafeFuture to avoid propagating InlineExecutor through caller code during transition.

Summary: toUnsafeFuture is intended to return a future that is the same as .via(&folly::InlineExecutor::instance()) without propagating InlineExecutor throughout future-using code during a transition to SemiFuture. This will highlight call sites better and encourage either fixing, or making clear that this non-deterministic behaviour is the intent.

Reviewed By: yfeldblum

Differential Revision: D7162989

fbshipit-source-id: c7092a53560e05d463d9170be254a50d23cc6ef7
parent 7e012aea
...@@ -711,6 +711,11 @@ inline Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && { ...@@ -711,6 +711,11 @@ inline Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && {
return newFuture; return newFuture;
} }
template <class T>
inline Future<T> SemiFuture<T>::toUnsafeFuture() && {
return std::move(*this).via(&folly::InlineExecutor::instance());
}
template <class T> template <class T>
template <typename F> template <typename F>
SemiFuture<typename futures::detail::callableResult<T, F>::Return::value_type> SemiFuture<typename futures::detail::callableResult<T, F>::Return::value_type>
......
...@@ -326,6 +326,15 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -326,6 +326,15 @@ class SemiFuture : private futures::detail::FutureBase<T> {
SemiFuture<typename futures::detail::callableResult<T, F>::Return::value_type> SemiFuture<typename futures::detail::callableResult<T, F>::Return::value_type>
defer(F&& func) &&; defer(F&& func) &&;
/// Return a future that completes inline, as if the future had no executor.
/// Intended for porting legacy code without behavioural change, and for rare
/// cases where this is really the intended behaviour.
/// Future is unsafe in the sense that the executor it completes on is
/// non-deterministic in the standard case.
/// For new code, or to update code that temporarily uses this, please
/// use via and pass a meaningful executor.
inline Future<T> toUnsafeFuture() &&;
private: private:
friend class Promise<T>; friend class Promise<T>;
template <class> template <class>
......
...@@ -365,7 +365,7 @@ TEST(SemiFuture, SimpleResultThrow) { ...@@ -365,7 +365,7 @@ TEST(SemiFuture, SimpleResultThrow) {
TEST(SemiFuture, SimpleDefer) { TEST(SemiFuture, SimpleDefer) {
std::atomic<int> innerResult{0}; std::atomic<int> innerResult{0};
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { innerResult = 17; }); auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
p.setValue(); p.setValue();
// Run "F" here inline in the calling thread // Run "F" here inline in the calling thread
...@@ -376,7 +376,7 @@ TEST(SemiFuture, SimpleDefer) { ...@@ -376,7 +376,7 @@ TEST(SemiFuture, SimpleDefer) {
TEST(SemiFuture, DeferWithDelayedSetValue) { TEST(SemiFuture, DeferWithDelayedSetValue) {
EventBase e2; EventBase e2;
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { return 17; }); auto sf = std::move(f).semi().defer([&]() { return 17; });
// Start thread and have it blocking in the semifuture before we satisfy the // Start thread and have it blocking in the semifuture before we satisfy the
...@@ -396,7 +396,7 @@ TEST(SemiFuture, DeferWithDelayedSetValue) { ...@@ -396,7 +396,7 @@ TEST(SemiFuture, DeferWithDelayedSetValue) {
TEST(SemiFuture, DeferWithViaAndDelayedSetValue) { TEST(SemiFuture, DeferWithViaAndDelayedSetValue) {
EventBase e2; EventBase e2;
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { return 17; }).via(&e2); auto sf = std::move(f).semi().defer([&]() { return 17; }).via(&e2);
// Start thread and have it blocking in the semifuture before we satisfy the // Start thread and have it blocking in the semifuture before we satisfy the
// promise. // promise.
...@@ -417,7 +417,7 @@ TEST(SemiFuture, DeferWithViaAndDelayedSetValue) { ...@@ -417,7 +417,7 @@ TEST(SemiFuture, DeferWithViaAndDelayedSetValue) {
TEST(SemiFuture, DeferWithGetTimedGet) { TEST(SemiFuture, DeferWithGetTimedGet) {
std::atomic<int> innerResult{0}; std::atomic<int> innerResult{0};
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { innerResult = 17; }); auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
EXPECT_THROW(std::move(sf).get(std::chrono::milliseconds(100)), TimedOut); EXPECT_THROW(std::move(sf).get(std::chrono::milliseconds(100)), TimedOut);
ASSERT_EQ(innerResult, 0); ASSERT_EQ(innerResult, 0);
...@@ -425,7 +425,7 @@ TEST(SemiFuture, DeferWithGetTimedGet) { ...@@ -425,7 +425,7 @@ TEST(SemiFuture, DeferWithGetTimedGet) {
TEST(SemiFuture, DeferWithGetTimedWait) { TEST(SemiFuture, DeferWithGetTimedWait) {
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { return 17; }); auto sf = std::move(f).semi().defer([&]() { return 17; });
ASSERT_FALSE(sf.isReady()); ASSERT_FALSE(sf.isReady());
sf.wait(std::chrono::milliseconds(100)); sf.wait(std::chrono::milliseconds(100));
...@@ -436,7 +436,7 @@ TEST(SemiFuture, DeferWithGetTimedWait) { ...@@ -436,7 +436,7 @@ TEST(SemiFuture, DeferWithGetTimedWait) {
TEST(SemiFuture, DeferWithGetMultipleTimedWait) { TEST(SemiFuture, DeferWithGetMultipleTimedWait) {
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { return 17; }); auto sf = std::move(f).semi().defer([&]() { return 17; });
sf.wait(std::chrono::milliseconds(100)); sf.wait(std::chrono::milliseconds(100));
sf.wait(std::chrono::milliseconds(100)); sf.wait(std::chrono::milliseconds(100));
...@@ -450,7 +450,7 @@ TEST(SemiFuture, DeferWithVia) { ...@@ -450,7 +450,7 @@ TEST(SemiFuture, DeferWithVia) {
std::atomic<int> innerResult{0}; std::atomic<int> innerResult{0};
EventBase e2; EventBase e2;
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { innerResult = 17; }); auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
// Run "F" here inline in the calling thread // Run "F" here inline in the calling thread
auto tf = std::move(sf).via(&e2); auto tf = std::move(sf).via(&e2);
...@@ -464,7 +464,7 @@ TEST(SemiFuture, ChainingDefertoThen) { ...@@ -464,7 +464,7 @@ TEST(SemiFuture, ChainingDefertoThen) {
std::atomic<int> result{0}; std::atomic<int> result{0};
EventBase e2; EventBase e2;
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { innerResult = 17; }); auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
// Run "F" here inline in a task running on the eventbase // Run "F" here inline in a task running on the eventbase
auto tf = std::move(sf).via(&e2).then([&]() { result = 42; }); auto tf = std::move(sf).via(&e2).then([&]() { result = 42; });
...@@ -477,7 +477,7 @@ TEST(SemiFuture, ChainingDefertoThen) { ...@@ -477,7 +477,7 @@ TEST(SemiFuture, ChainingDefertoThen) {
TEST(SemiFuture, SimpleDeferWithValue) { TEST(SemiFuture, SimpleDeferWithValue) {
std::atomic<int> innerResult{0}; std::atomic<int> innerResult{0};
Promise<int> p; Promise<int> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&](int a) { innerResult = a; }); auto sf = std::move(f).semi().defer([&](int a) { innerResult = a; });
p.setValue(7); p.setValue(7);
// Run "F" here inline in the calling thread // Run "F" here inline in the calling thread
...@@ -490,7 +490,7 @@ TEST(SemiFuture, ChainingDefertoThenWithValue) { ...@@ -490,7 +490,7 @@ TEST(SemiFuture, ChainingDefertoThenWithValue) {
std::atomic<int> result{0}; std::atomic<int> result{0};
EventBase e2; EventBase e2;
Promise<int> p; Promise<int> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&](int a) { auto sf = std::move(f).semi().defer([&](int a) {
innerResult = a; innerResult = a;
return a; return a;
...@@ -505,7 +505,7 @@ TEST(SemiFuture, ChainingDefertoThenWithValue) { ...@@ -505,7 +505,7 @@ TEST(SemiFuture, ChainingDefertoThenWithValue) {
TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) { TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) {
Promise<int> p; Promise<int> p;
auto f = p.getFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&](Try<int> t) { auto sf = std::move(f).semi().defer([&](Try<int> t) {
if (auto err = t.tryGetExceptionObject<std::logic_error>()) { if (auto err = t.tryGetExceptionObject<std::logic_error>()) {
return Try<std::string>(err->what()); return Try<std::string>(err->what());
......
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