2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <folly/wangle/Deprecated.h>
20 #include <folly/wangle/Executor.h>
21 #include <folly/wangle/Future.h>
22 #include <folly/Optional.h>
24 namespace folly { namespace wangle {
26 template <typename T> struct isLaterOrFuture;
27 template <typename T> struct isLater;
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
35 * Later<Foo>(std::move(foo))
46 * Future<Foo> coldFuture = makeFuture(std::move(foo));
47 * coldFuture.deactivate();
57 * coldFuture.activate();
59 * Using a Later means you don't have to grab a handle to the first Future and
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().
67 * Here is an example of a workflow:
69 * Later<ClientRequest> later(std::move(request));
71 * auto future = later.
73 * .then([=](Try<ClientRequest>&& t) { return doCpuWork(t.value()); })
75 * .then([=](Try<CpuResponse>&& t) { return doDiskWork(t.value()); })
76 * .via(serverExecutor)
77 * .then([=]Try<DiskResponse>&& t) { return sendClientResponse(t.value()); })
80 // DEPRECATED. Just use Future::via() to accomplish the same thing. If it's
81 // not obvious how, feel free to reach out.
83 class DEPRECATED Later {
88 * This default constructor is used to build an asynchronous workflow that
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>
97 * Lift a Future into a Later
99 /* implicit */ Later(Future<T>&& f);
102 * This constructor is used to build an asynchronous workflow that takes a
103 * value as input, and that value is passed in.
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);
111 * This constructor is used to build an asynchronous workflow that takes an
112 * exception_ptr as input, and throws it on completion.
114 explicit Later(std::exception_ptr const&);
117 * This constructor is used to build an asynchronous workflow that takes an
118 * exception as input, and throws it on completion.
121 class = typename std::enable_if<
122 std::is_base_of<std::exception, E>::value>::type>
123 explicit Later(E const& e);
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.
133 * // This adds two ints asynchronously. cob is called in another thread.
134 * void addAsync(int a, int b, std::function<void(int&&)>&& cob);
136 * Later<int> asyncWrapper([=](std::function<void(int&&)>&& fn) {
137 * addAsync(1, 2, std::move(fn));
140 // TODO we should implement a makeFuture-ish with this pattern too, now.
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);
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
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
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
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.
168 * This can be used to build asynchronous modules that can be called from a
169 * user thread and completed in a callback thread.
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.
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
182 /// Variant where func is an ordinary function (static method, method)
183 /// Must return a Later
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));
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));
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.
206 Later<T> via(Executor* executor);
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.
217 Promise<void> starter_;
218 folly::Optional<Future<T>> future_;
222 explicit Later(Promise<void>&& starter);
228 // See Future.whenAll
230 Later<std::vector<Try<T>>> whenAllLater(std::vector<Later<T>>&& laters);
234 #include <folly/wangle/Later-inl.h>