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