/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Future(Future&&) noexcept;
Future& operator=(Future&&) noexcept;
- // conversion constructors
+ // converting move
template <
- class U,
- typename = typename std::enable_if<std::is_convertible<U, T>::value &&
- sizeof(U) == sizeof(T)>::type>
- /* implicit */ Future(Future<U>&&) noexcept;
+ class T2,
+ typename std::enable_if<
+ !std::is_same<T, typename std::decay<T2>::type>::value &&
+ std::is_constructible<T, T2&&>::value &&
+ std::is_convertible<T2&&, T>::value,
+ int>::type = 0>
+ /* implicit */ Future(Future<T2>&&);
template <
- class U,
- typename = typename std::enable_if<std::is_convertible<U, T>::value &&
- sizeof(U) == sizeof(T)>::type>
- /* implicit */ Future& operator=(Future<U>&&) noexcept;
+ class T2,
+ typename std::enable_if<
+ !std::is_same<T, typename std::decay<T2>::type>::value &&
+ std::is_constructible<T, T2&&>::value &&
+ !std::is_convertible<T2&&, T>::value,
+ int>::type = 0>
+ explicit Future(Future<T2>&&);
+ template <
+ class T2,
+ typename std::enable_if<
+ !std::is_same<T, typename std::decay<T2>::type>::value &&
+ std::is_constructible<T, T2&&>::value,
+ int>::type = 0>
+ Future& operator=(Future<T2>&&);
/// Construct a Future from a value (perfect forwarding)
template <class T2 = T, typename =
/** A reference to the Try of the value */
Try<T>& getTry();
+ /// 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);
+
/// If the promise has been fulfilled, return an Optional with the Try<T>.
/// Otherwise return an empty Optional.
/// Note that this moves the Try<T> out.
/// In the former both b and c execute via x. In the latter, only b executes
/// via x, and c executes via the same executor (if any) that f had.
template <class Executor, class Arg, class... Args>
- auto then(Executor* x, Arg&& arg, Args&&... args)
- -> decltype(this->then(std::forward<Arg>(arg),
- std::forward<Args>(args)...));
+ auto then(Executor* x, Arg&& arg, Args&&... args) {
+ auto oldX = getExecutor();
+ setExecutor(x);
+ return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...)
+ .via(oldX);
+ }
/// Convenience method for ignoring the value and creating a Future<Unit>.
/// Exceptions still propagate.
///
/// f.thenMulti(a, b, c);
template <class Callback, class... Callbacks>
- auto thenMulti(Callback&& fn, Callbacks&&... fns)
- -> decltype(this->then(std::forward<Callback>(fn)).
- thenMulti(std::forward<Callbacks>(fns)...));
+ auto thenMulti(Callback&& fn, Callbacks&&... fns) {
+ // thenMulti with two callbacks is just then(a).thenMulti(b, ...)
+ return then(std::forward<Callback>(fn))
+ .thenMulti(std::forward<Callbacks>(fns)...);
+ }
- // Nothing to see here, just thenMulti's base case
template <class Callback>
- auto thenMulti(Callback&& fn)
- -> decltype(this->then(std::forward<Callback>(fn)));
+ auto thenMulti(Callback&& fn) {
+ // thenMulti with one callback is just a then
+ return then(std::forward<Callback>(fn));
+ }
/// Create a Future chain from a sequence of callbacks. i.e.
///
///
/// f.thenMultiWithExecutor(executor, a, b, c);
template <class Callback, class... Callbacks>
- auto thenMultiWithExecutor(Executor* x, Callback&& fn, Callbacks&&... fns)
- -> decltype(this->then(std::forward<Callback>(fn)).
- thenMulti(std::forward<Callbacks>(fns)...));
+ auto thenMultiWithExecutor(Executor* x, Callback&& fn, Callbacks&&... fns) {
+ // thenMultiExecutor with two callbacks is
+ // via(x).then(a).thenMulti(b, ...).via(oldX)
+ auto oldX = getExecutor();
+ setExecutor(x);
+ return then(std::forward<Callback>(fn))
+ .thenMulti(std::forward<Callbacks>(fns)...)
+ .via(oldX);
+ }
- // Nothing to see here, just thenMultiWithExecutor's base case
template <class Callback>
- auto thenMultiWithExecutor(Executor* x, Callback&& fn)
- -> decltype(this->then(std::forward<Callback>(fn)));
+ auto thenMultiWithExecutor(Executor* x, Callback&& fn) {
+ // thenMulti with one callback is just a then with an executor
+ return then(x, std::forward<Callback>(fn));
+ }
/// Discard a result, but propagate an exception.
Future<Unit> unit() {