94f2883c75d34a77a6e72427a0f5418f6eeb82f4
[folly.git] / folly / wangle / Later.h
1 /*
2  * Copyright 2014 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/wangle/Executor.h>
20 #include <folly/wangle/Future.h>
21 #include <folly/Optional.h>
22
23 namespace folly { namespace wangle {
24
25 template <typename T> struct isLaterOrFuture;
26 template <typename T> struct isLater;
27
28 /*
29  * Later is like a cold Future, but makes it easier to avoid triggering until
30  * later, because it must be triggered explicitly. An equivalence example will
31  * help differentiate:
32  *
33  *   Later<Foo> later =
34  *     Later<Foo>(std::move(foo))
35  *     .then(cb1)
36  *     .via(ex1)
37  *     .then(cb2)
38  *     .then(cb3)
39  *     .via(ex2)
40  *     .then(cb4)
41  *     .then(cb5);
42  *   ...
43  *   later.launch();
44  *
45  *   Future<Foo> coldFuture = makeFuture(std::move(foo));
46  *   coldFuture.deactivate();
47  *   coldFuture
48  *     .then(cb1)
49  *     .via(ex1)
50  *     .then(cb2)
51  *     .then(cb3)
52  *     .via(ex2)
53  *     .then(cb4)
54  *     .then(cb5);
55  *   ...
56  *   coldFuture.activate();
57  *
58  * Using a Later means you don't have to grab a handle to the first Future and
59  * deactivate it.
60  *
61  * Later used to be a workaround to the thread-unsafe nature of Future
62  * chaining, but that has changed and there is no need to use Later if your
63  * only goal is to traverse thread boundaries with executors. In that case,
64  * just use Future::via().
65  *
66  * Here is an example of a workflow:
67  *
68  * Later<ClientRequest> later(std::move(request));
69  *
70  * auto future = later.
71  *   .via(cpuExecutor)
72  *   .then([=](Try<ClientRequest>&& t) { return doCpuWork(t.value()); })
73  *   .via(diskExecutor)
74  *   .then([=](Try<CpuResponse>&& t) { return doDiskWork(t.value()); })
75  *   .via(serverExecutor)
76  *   .then([=]Try<DiskResponse>&& t) { return sendClientResponse(t.value()); })
77  *   .launch();
78  */
79 template <class T>
80 class Later {
81  public:
82   typedef T value_type;
83
84   /*
85    * This default constructor is used to build an asynchronous workflow that
86    * takes no input.
87    */
88   template <class U = void,
89             class = typename std::enable_if<std::is_void<U>::value>::type,
90             class = typename std::enable_if<std::is_same<T, U>::value>::type>
91   Later();
92
93   /*
94    * Lift a Future into a Later
95    */
96   /* implicit */ Later(Future<T>&& f);
97
98   /*
99    * This constructor is used to build an asynchronous workflow that takes a
100    * value as input, and that value is passed in.
101    */
102   template <class U,
103             class = typename std::enable_if<!std::is_void<U>::value>::type,
104             class = typename std::enable_if<std::is_same<T, U>::value>::type>
105   explicit Later(U&& input);
106
107   /*
108    * This constructor is used to build an asynchronous workflow that takes an
109    * exception_ptr as input, and throws it on completion.
110    */
111   explicit Later(std::exception_ptr const&);
112
113   /*
114    * This constructor is used to build an asynchronous workflow that takes an
115    * exception as input, and throws it on completion.
116    */
117   template <class E,
118             class = typename std::enable_if<
119                 std::is_base_of<std::exception, E>::value>::type>
120   explicit Later(E const& e);
121
122   /*
123    * This constructor is used to wrap a pre-existing cob-style asynchronous api
124    * so that it can be used in wangle. wangle provides the callback to this
125    * pre-existing api, and this callback will fulfill a promise so as to
126    * incorporate this api into the workflow.
127    *
128    * Example usage:
129    *
130    * // This adds two ints asynchronously. cob is called in another thread.
131    * void addAsync(int a, int b, std::function<void(int&&)>&& cob);
132    *
133    * Later<int> asyncWrapper([=](std::function<void(int&&)>&& fn) {
134    *   addAsync(1, 2, std::move(fn));
135    * });
136    */
137   // TODO we should implement a makeFuture-ish with this pattern too, now.
138   template <class U,
139             class = typename std::enable_if<!std::is_void<U>::value>::type,
140             class = typename std::enable_if<std::is_same<T, U>::value>::type>
141   explicit Later(std::function<void(std::function<void(U&&)>&&)>&& fn);
142
143   /*
144    * then() adds additional work to the end of the workflow. If the lambda
145    * provided to then() returns a future, that future must be fulfilled in the
146    * same thread of the last set executor (either at constructor or from a call
147    * to via()).
148    */
149   template <class F>
150   typename std::enable_if<
151     !isLaterOrFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
152     Later<typename std::result_of<F(Try<T>&&)>::type> >::type
153   then(F&& fn);
154
155   template <class F>
156   typename std::enable_if<
157     isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
158     Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
159   then(F&& fn);
160
161   /*
162    * If the function passed to then() returns a Later<T>, calls to then() will
163    * be chained to the new Later before launching the new Later.
164    *
165    * This can be used to build asynchronous modules that can be called from a
166    * user thread and completed in a callback thread.
167    *
168    * Using the Later(std::function<void(std::function<void(T&&)>)>&& fn)
169    * constructor, you can wrap existing asynchronous modules with a Later and
170    * can chain it to wangle asynchronous workflows via this call.
171    */
172   template <class F>
173   typename std::enable_if<
174     isLater<typename std::result_of<F(Try<T>&&)>::type>::value,
175     Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
176   then(F&& fn);
177
178
179   /// Variant where func is an ordinary function (static method, method)
180   /// Must return a Later
181   template <class R>
182   typename std::enable_if<isLater<R>::value, R>::type
183   inline then(R(*func)(Try<T>&&)) {
184     return then([func](Try<T>&& t) {
185       return (*func)(std::move(t));
186     });
187   }
188
189   /// Variant where func is an member function
190   /// Must return a Later
191   template <class R, class Caller>
192   typename std::enable_if<isLater<R>::value, R>::type
193   inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
194     return then([instance, func](Try<T>&& t) {
195       return (instance->*func)(std::move(t));
196     });
197   }
198
199   /*
200    * Resets the executor - all then() calls made after the call to via() will be
201    * made in the new executor. The Executor must outlive.
202    */
203   Later<T> via(Executor* executor);
204
205   /*
206    * Starts the workflow. The function provided in the constructor will be
207    * called in the executor provided in the constructor. Subsequent then()
208    * calls will be made, potentially changing threads if a via() call is made.
209    * The future returned will be fulfilled in the last executor.
210    */
211   Future<T> launch();
212
213  private:
214   Promise<void> starter_;
215   folly::Optional<Future<T>> future_;
216
217   struct hide { };
218
219   explicit Later(Promise<void>&& starter);
220
221   template <class U>
222   friend class Later;
223 };
224
225 // See Future.whenAll
226 template <class T>
227 Later<std::vector<Try<T>>> whenAllLater(std::vector<Later<T>>&& laters);
228
229 }}
230
231 #include <folly/wangle/Later-inl.h>