return f;
}
-template <class T>
-Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
- return waitVia(e).getTry();
-}
-
template <class Func>
auto via(Executor* x, Func&& func)
-> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner> {
assert(f.isReady());
}
+template <class T>
+void waitViaImpl(SemiFuture<T>& f, DrivableExecutor* e) {
+ // Set callback so to ensure that the via executor has something on it
+ // so that once the preceding future triggers this callback, drive will
+ // always have a callback to satisfy it
+ if (f.isReady()) {
+ return;
+ }
+ f = std::move(f).via(e).then([](T&& t) { return std::move(t); });
+ while (!f.isReady()) {
+ e->drive();
+ }
+ assert(f.isReady());
+}
+
} // namespace detail
} // namespace futures
return std::move(*this);
}
+template <class T>
+SemiFuture<T>& SemiFuture<T>::waitVia(DrivableExecutor* e) & {
+ futures::detail::waitViaImpl(*this, e);
+ return *this;
+}
+
+template <class T>
+SemiFuture<T>&& SemiFuture<T>::waitVia(DrivableExecutor* e) && {
+ futures::detail::waitViaImpl(*this, e);
+ return std::move(*this);
+}
+
template <class T>
T SemiFuture<T>::get() && {
return std::move(wait().value());
return std::move(this->core_->getTry());
}
+template <class T>
+T SemiFuture<T>::getVia(DrivableExecutor* e) && {
+ return std::move(waitVia(e).value());
+}
+
+template <class T>
+Try<T> SemiFuture<T>::getTryVia(DrivableExecutor* e) && {
+ waitVia(e);
+ return std::move(this->core_->getTry());
+}
+
template <class T>
Future<T>& Future<T>::wait() & {
futures::detail::waitImpl(*this);
return std::move(waitVia(e).value());
}
+template <class T>
+Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
+ return waitVia(e).getTry();
+}
+
namespace futures {
namespace detail {
template <class T>
/// Try of the value (moved out).
Try<T> getTry() &&;
+ /// Call e->drive() repeatedly until the future is fulfilled. Examples
+ /// of DrivableExecutor include EventBase and ManualExecutor. Returns the
+ /// value (moved out), or throws the exception.
+ T getVia(DrivableExecutor* e) &&;
+
+ /// Call e->drive() repeatedly until the future is fulfilled. Examples
+ /// of DrivableExecutor include EventBase and ManualExecutor. Returns the
+ /// Try of the value (moved out).
+ Try<T> getTryVia(DrivableExecutor* e) &&;
+
/// Block until this Future is complete. Returns a reference to this Future.
SemiFuture<T>& wait() &;
/// Overload of wait(Duration) for rvalue Futures
SemiFuture<T>&& wait(Duration) &&;
+ /// Call e->drive() repeatedly until the future is fulfilled. Examples
+ /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
+ /// reference to this SemiFuture so that you can chain calls if desired.
+ /// value (moved out), or throws the exception.
+ SemiFuture<T>& waitVia(DrivableExecutor* e) &;
+
+ /// Overload of waitVia() for rvalue Futures
+ SemiFuture<T>&& waitVia(DrivableExecutor* e) &&;
+
/// Returns an inactive Future which will call back on the other side of
/// executor (when it is activated).
///
// movable
Future& operator=(Future&&) noexcept;
- /// Call e->drive() repeatedly until the future is fulfilled. Examples
- /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
- /// reference to the Try of the value.
- Try<T>& getTryVia(DrivableExecutor* e);
-
/// Call e->drive() repeatedly until the future is fulfilled. Examples
/// of DrivableExecutor include EventBase and ManualExecutor. Returns the
/// value (moved out), or throws the exception.
T getVia(DrivableExecutor* e);
+ /// Call e->drive() repeatedly until the future is fulfilled. Examples
+ /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
+ /// reference to the Try of the value.
+ Try<T>& getTryVia(DrivableExecutor* e);
+
/// Unwraps the case of a Future<Future<T>> instance, and returns a simple
/// Future<T> instance.
template <class F = T>
ASSERT_EQ(innerResult, 17);
}
+TEST(SemiFuture, DeferWithGetVia) {
+ std::atomic<int> innerResult{0};
+ EventBase e2;
+ Promise<folly::Unit> p;
+ auto f = p.getFuture();
+ auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
+ p.setValue();
+ std::move(sf).getVia(&e2);
+ ASSERT_EQ(innerResult, 17);
+}
+
TEST(SemiFuture, DeferWithVia) {
std::atomic<int> innerResult{0};
EventBase e2;