cbf4123a92db710b0fe15e59ef9e90ab95534657
[folly.git] / folly / wangle / concurrent / FutureExecutor.h
1 /*
2  * Copyright 2015 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 #include <folly/futures/Future.h>
19
20 namespace folly { namespace wangle {
21
22 template <typename ExecutorImpl>
23 class FutureExecutor : public ExecutorImpl {
24  public:
25   template <typename... Args>
26   explicit FutureExecutor(Args&&... args)
27     : ExecutorImpl(std::forward<Args>(args)...) {}
28
29   /*
30    * Given a function func that returns a Future<T>, adds that function to the
31    * contained Executor and returns a Future<T> which will be fulfilled with
32    * func's result once it has been executed.
33    *
34    * For example: auto f = futureExecutor.addFuture([](){
35    *                return doAsyncWorkAndReturnAFuture();
36    *              });
37    */
38   template <typename F>
39   typename std::enable_if<isFuture<typename std::result_of<F()>::type>::value,
40                           typename std::result_of<F()>::type>::type
41   addFuture(F func) {
42     typedef typename std::result_of<F()>::type::value_type T;
43     Promise<T> promise;
44     auto future = promise.getFuture();
45     auto movePromise = folly::makeMoveWrapper(std::move(promise));
46     auto moveFunc = folly::makeMoveWrapper(std::move(func));
47     ExecutorImpl::add([movePromise, moveFunc] () mutable {
48       (*moveFunc)().then([movePromise] (Try<T>&& t) mutable {
49         movePromise->setTry(std::move(t));
50       });
51     });
52     return future;
53   }
54
55   /*
56    * Similar to addFuture above, but takes a func that returns some non-Future
57    * type T.
58    *
59    * For example: auto f = futureExecutor.addFuture([]() {
60    *                return 42;
61    *              });
62    */
63   template <typename F>
64   typename std::enable_if<!isFuture<typename std::result_of<F()>::type>::value,
65                           Future<typename std::result_of<F()>::type>>::type
66   addFuture(F func) {
67     typedef typename std::result_of<F()>::type T;
68     Promise<T> promise;
69     auto future = promise.getFuture();
70     auto movePromise = folly::makeMoveWrapper(std::move(promise));
71     auto moveFunc = folly::makeMoveWrapper(std::move(func));
72     ExecutorImpl::add([movePromise, moveFunc] () mutable {
73       movePromise->setWith(std::move(*moveFunc));
74     });
75     return future;
76   }
77 };
78
79 }}