+} // namespace detail
+} // namespace futures
+
+template <class T>
+SemiFuture<typename std::decay<T>::type> makeSemiFuture(T&& t) {
+ return makeSemiFuture(Try<typename std::decay<T>::type>(std::forward<T>(t)));
+}
+
+// makeSemiFutureWith(SemiFuture<T>()) -> SemiFuture<T>
+template <class F>
+typename std::enable_if<
+ isSemiFuture<typename std::result_of<F()>::type>::value,
+ typename std::result_of<F()>::type>::type
+makeSemiFutureWith(F&& func) {
+ using InnerType =
+ typename isSemiFuture<typename std::result_of<F()>::type>::Inner;
+ try {
+ return std::forward<F>(func)();
+ } catch (std::exception& e) {
+ return makeSemiFuture<InnerType>(
+ exception_wrapper(std::current_exception(), e));
+ } catch (...) {
+ return makeSemiFuture<InnerType>(
+ exception_wrapper(std::current_exception()));
+ }
+}
+
+// makeSemiFutureWith(T()) -> SemiFuture<T>
+// makeSemiFutureWith(void()) -> SemiFuture<Unit>
+template <class F>
+typename std::enable_if<
+ !(isSemiFuture<typename std::result_of<F()>::type>::value),
+ SemiFuture<Unit::LiftT<typename std::result_of<F()>::type>>>::type
+makeSemiFutureWith(F&& func) {
+ using LiftedResult = Unit::LiftT<typename std::result_of<F()>::type>;
+ return makeSemiFuture<LiftedResult>(
+ makeTryWith([&func]() mutable { return std::forward<F>(func)(); }));
+}
+
+template <class T>
+SemiFuture<T> makeSemiFuture(std::exception_ptr const& e) {
+ return makeSemiFuture(Try<T>(e));
+}
+
+template <class T>
+SemiFuture<T> makeSemiFuture(exception_wrapper ew) {
+ return makeSemiFuture(Try<T>(std::move(ew)));
+}
+
+template <class T, class E>
+typename std::
+ enable_if<std::is_base_of<std::exception, E>::value, SemiFuture<T>>::type
+ makeSemiFuture(E const& e) {
+ return makeSemiFuture(Try<T>(make_exception_wrapper<E>(e)));
+}
+
+template <class T>
+SemiFuture<T> makeSemiFuture(Try<T>&& t) {
+ return SemiFuture<T>(new futures::detail::Core<T>(std::move(t)));
+}
+
+// This must be defined after the constructors to avoid a bug in MSVC
+// https://connect.microsoft.com/VisualStudio/feedback/details/3142777/out-of-line-constructor-definition-after-implicit-reference-causes-incorrect-c2244
+inline SemiFuture<Unit> makeSemiFuture() {
+ return makeSemiFuture(Unit{});
+}
+
+template <class T>
+SemiFuture<T> SemiFuture<T>::makeEmpty() {
+ return SemiFuture<T>(futures::detail::EmptyConstruct{});
+}
+
+template <class T>
+SemiFuture<T>::SemiFuture(SemiFuture<T>&& other) noexcept
+ : futures::detail::FutureBase<T>(std::move(other)) {}
+
+template <class T>
+SemiFuture<T>::SemiFuture(Future<T>&& other) noexcept
+ : futures::detail::FutureBase<T>(std::move(other)) {
+ // SemiFuture should not have an executor on construction
+ if (this->core_) {
+ this->setExecutor(nullptr);
+ }
+}
+
+template <class T>
+SemiFuture<T>& SemiFuture<T>::operator=(SemiFuture<T>&& other) noexcept {
+ this->assign(other);
+ return *this;
+}
+
+template <class T>
+SemiFuture<T>& SemiFuture<T>::operator=(Future<T>&& other) noexcept {
+ this->assign(other);
+ // SemiFuture should not have an executor on construction
+ if (this->core_) {
+ this->setExecutor(nullptr);
+ }
+ return *this;
+}
+
+template <class T>
+void SemiFuture<T>::boost_() {
+ // If a SemiFuture has an executor it should be deferred, so boost it
+ if (auto e = this->getExecutor()) {
+ // We know in a SemiFuture that if we have an executor it should be
+ // DeferredExecutor. Verify this in debug mode.
+ DCHECK(nullptr != dynamic_cast<DeferredExecutor*>(e));
+
+ auto ka = static_cast<DeferredExecutor*>(e)->getKeepAliveToken();
+ static_cast<DeferredExecutor*>(e)->boost();
+ }
+}
+
+template <class T>
+inline Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && {
+ throwIfInvalid();
+ if (!executor) {
+ throwNoExecutor();
+ }
+
+ // If current executor is deferred, boost block to ensure that work
+ // progresses and is run on the new executor.
+ auto oldExecutor = this->getExecutor();
+ if (oldExecutor && executor && (executor != oldExecutor)) {
+ // We know in a SemiFuture that if we have an executor it should be
+ // DeferredExecutor. Verify this in debug mode.
+ DCHECK(nullptr != dynamic_cast<DeferredExecutor*>(this->getExecutor()));
+ if (static_cast<DeferredExecutor*>(oldExecutor)) {
+ executor->add([oldExecutorKA = oldExecutor->getKeepAliveToken()]() {
+ static_cast<DeferredExecutor*>(oldExecutorKA.get())->boost();
+ });
+ }
+ }
+
+ this->setExecutor(executor, priority);
+
+ auto newFuture = Future<T>(this->core_);
+ this->core_ = nullptr;
+ return newFuture;
+}
+
+template <class T>
+template <typename F>
+SemiFuture<typename futures::detail::callableResult<T, F>::Return::value_type>
+SemiFuture<T>::defer(F&& func) && {
+ // If we already have a deferred executor, use it, otherwise create one
+ auto defKeepAlive = this->getExecutor()
+ ? this->getExecutor()->getKeepAliveToken()
+ : DeferredExecutor::create();
+ auto e = defKeepAlive.get();
+ // We know in a SemiFuture that if we have an executor it should be
+ // DeferredExecutor (either it was that way before, or we just created it).
+ // Verify this in debug mode.
+ DCHECK(nullptr != dynamic_cast<DeferredExecutor*>(e));
+ // Convert to a folly::future with a deferred executor
+ // Will be low-cost if this is not a new executor as via optimises for that
+ // case
+ auto sf =
+ std::move(*this)
+ .via(e)
+ // Then add the work, with a wrapper function that captures the
+ // keepAlive so the executor is destroyed at the right time.
+ .then(
+ DeferredExecutor::wrap(std::move(defKeepAlive), std::move(func)))
+ // Finally, convert back o a folly::SemiFuture to hide the executor
+ .semi();
+ // Carry deferred executor through chain as constructor from Future will
+ // nullify it
+ sf.setExecutor(e);
+ return sf;
+}
+
+template <class T>
+Future<T> Future<T>::makeEmpty() {
+ return Future<T>(futures::detail::EmptyConstruct{});
+}
+
+template <class T>
+Future<T>::Future(Future<T>&& other) noexcept
+ : futures::detail::FutureBase<T>(std::move(other)) {}
+
+template <class T>
+Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
+ this->assign(other);
+ return *this;
+}
+
+template <class T>
+template <
+ 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>
+Future<T>::Future(Future<T2>&& other)
+ : Future(std::move(other).then([](T2&& v) { return T(std::move(v)); })) {}
+
+template <class T>
+template <
+ 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>
+Future<T>::Future(Future<T2>&& other)
+ : Future(std::move(other).then([](T2&& v) { return T(std::move(v)); })) {}
+
+template <class T>
+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>
+Future<T>& Future<T>::operator=(Future<T2>&& other) {
+ return operator=(
+ std::move(other).then([](T2&& v) { return T(std::move(v)); }));
+}
+
+// unwrap
+
+template <class T>
+template <class F>
+typename std::
+ enable_if<isFuture<F>::value, Future<typename isFuture<T>::Inner>>::type
+ Future<T>::unwrap() {
+ return then([](Future<typename isFuture<T>::Inner> internal_future) {
+ return internal_future;
+ });
+}
+
+template <class T>
+inline Future<T> Future<T>::via(Executor* executor, int8_t priority) && {
+ this->throwIfInvalid();
+
+ this->setExecutor(executor, priority);
+
+ auto newFuture = Future<T>(this->core_);
+ this->core_ = nullptr;
+ return newFuture;
+}
+
+template <class T>
+inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & {
+ this->throwIfInvalid();
+ Promise<T> p;
+ auto f = p.getFuture();
+ auto func = [p = std::move(p)](Try<T>&& t) mutable {
+ p.setTry(std::move(t));
+ };
+ using R = futures::detail::callableResult<T, decltype(func)>;
+ this->template thenImplementation<decltype(func), R>(
+ std::move(func), typename R::Arg());
+ return std::move(f).via(executor, priority);
+}