1/*
2 * Copyright 2017-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <folly/functional/Invoke.h>
20#include <folly/futures/Future.h>
21
22namespace folly {
23
24template <typename ExecutorImpl>
25class FutureExecutor : public ExecutorImpl {
26 public:
27 template <typename... Args>
28 explicit FutureExecutor(Args&&... args)
29 : ExecutorImpl(std::forward<Args>(args)...) {}
30
31 /*
32 * Given a function func that returns a Future<T>, adds that function to the
33 * contained Executor and returns a Future<T> which will be fulfilled with
34 * func's result once it has been executed.
35 *
36 * For example: auto f = futureExecutor.addFuture([](){
37 * return doAsyncWorkAndReturnAFuture();
38 * });
39 */
40 template <typename F>
41 typename std::enable_if<
42 folly::isFuture<invoke_result_t<F>>::value,
43 invoke_result_t<F>>::type
44 addFuture(F func) {
45 using T = typename invoke_result_t<F>::value_type;
46 folly::Promise<T> promise;
47 auto future = promise.getFuture();
48 ExecutorImpl::add([promise = std::move(promise),
49 func = std::move(func)]() mutable {
50 func().then([promise = std::move(promise)](folly::Try<T>&& t) mutable {
51 promise.setTry(std::move(t));
52 });
53 });
54 return future;
55 }
56
57 /*
58 * Similar to addFuture above, but takes a func that returns some non-Future
59 * type T.
60 *
61 * For example: auto f = futureExecutor.addFuture([]() {
62 * return 42;
63 * });
64 */
65 template <typename F>
66 typename std::enable_if<
67 !folly::isFuture<invoke_result_t<F>>::value,
68 folly::Future<folly::lift_unit_t<invoke_result_t<F>>>>::type
69 addFuture(F func) {
70 using T = folly::lift_unit_t<invoke_result_t<F>>;
71 folly::Promise<T> promise;
72 auto future = promise.getFuture();
73 ExecutorImpl::add(
74 [promise = std::move(promise), func = std::move(func)]() mutable {
75 promise.setWith(std::move(func));
76 });
77 return future;
78 }
79};
80
81} // namespace folly
82