#pragma once
+#include <folly/wangle/Deprecated.h>
#include <folly/wangle/Executor.h>
#include <folly/wangle/Future.h>
#include <folly/Optional.h>
template <typename T> struct isLater;
/*
- * Since wangle primitives (promise/future) are not thread safe, it is difficult
- * to build complex asynchronous workflows. A Later allows you to build such a
- * workflow before actually launching it so that callbacks can be set in a
- * threadsafe manner.
+ * Later is like a cold Future, but makes it easier to avoid triggering until
+ * later, because it must be triggered explicitly. An equivalence example will
+ * help differentiate:
*
- * The interface to add additional work is the same as future: a then() method
- * that takes a function that can return either a type T, a Future<T>, or a
- * Later<T>
+ * Later<Foo> later =
+ * Later<Foo>(std::move(foo))
+ * .then(cb1)
+ * .via(ex1)
+ * .then(cb2)
+ * .then(cb3)
+ * .via(ex2)
+ * .then(cb4)
+ * .then(cb5);
+ * ...
+ * later.launch();
*
- * Thread transitions are done by using executors and calling the via() method.
+ * Future<Foo> coldFuture = makeFuture(std::move(foo));
+ * coldFuture.deactivate();
+ * coldFuture
+ * .then(cb1)
+ * .via(ex1)
+ * .then(cb2)
+ * .then(cb3)
+ * .via(ex2)
+ * .then(cb4)
+ * .then(cb5);
+ * ...
+ * coldFuture.activate();
+ *
+ * Using a Later means you don't have to grab a handle to the first Future and
+ * deactivate it.
+ *
+ * Later used to be a workaround to the thread-unsafe nature of Future
+ * chaining, but that has changed and there is no need to use Later if your
+ * only goal is to traverse thread boundaries with executors. In that case,
+ * just use Future::via().
*
* Here is an example of a workflow:
*
* .via(serverExecutor)
* .then([=]Try<DiskResponse>&& t) { return sendClientResponse(t.value()); })
* .launch();
- *
- * Although this workflow traverses many threads, we are able to string
- * continuations together in a threadsafe manner.
- *
- * Laters can also be used to wrap preexisting asynchronous modules that were
- * not built with wangle in mind. You can create a Later with a function that
- * takes a callback as input. The function will not actually be called until
- * launch(), allowing you to string then() statements on top of the callback.
*/
+// DEPRECATED. Just use Future::via() to accomplish the same thing. If it's
+// not obvious how, feel free to reach out.
template <class T>
-class Later {
+class DEPRECATED Later {
public:
typedef T value_type;
class = typename std::enable_if<std::is_same<T, U>::value>::type>
explicit Later(U&& input);
+ /*
+ * This constructor is used to build an asynchronous workflow that takes an
+ * exception_ptr as input, and throws it on completion.
+ */
+ explicit Later(std::exception_ptr const&);
+
+ /*
+ * This constructor is used to build an asynchronous workflow that takes an
+ * exception as input, and throws it on completion.
+ */
+ template <class E,
+ class = typename std::enable_if<
+ std::is_base_of<std::exception, E>::value>::type>
+ explicit Later(E const& e);
+
/*
* This constructor is used to wrap a pre-existing cob-style asynchronous api
- * so that it can be used in wangle in a threadsafe manner. wangle provides
- * the callback to this pre-existing api, and this callback will fulfill a
- * promise so as to incorporate this api into the workflow.
+ * so that it can be used in wangle. wangle provides the callback to this
+ * pre-existing api, and this callback will fulfill a promise so as to
+ * incorporate this api into the workflow.
*
* Example usage:
*
* addAsync(1, 2, std::move(fn));
* });
*/
+ // TODO we should implement a makeFuture-ish with this pattern too, now.
template <class U,
class = typename std::enable_if<!std::is_void<U>::value>::type,
class = typename std::enable_if<std::is_same<T, U>::value>::type>
* be chained to the new Later before launching the new Later.
*
* This can be used to build asynchronous modules that can be called from a
- * user thread and completed in a callback thread. Callbacks can be set up
- * ahead of time without thread safety issues.
+ * user thread and completed in a callback thread.
*
* Using the Later(std::function<void(std::function<void(T&&)>)>&& fn)
* constructor, you can wrap existing asynchronous modules with a Later and
Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
then(F&& fn);
+
+ /// Variant where func is an ordinary function (static method, method)
+ /// Must return a Later
+ template <class R>
+ typename std::enable_if<isLater<R>::value, R>::type
+ inline then(R(*func)(Try<T>&&)) {
+ return then([func](Try<T>&& t) {
+ return (*func)(std::move(t));
+ });
+ }
+
+ /// Variant where func is an member function
+ /// Must return a Later
+ template <class R, class Caller>
+ typename std::enable_if<isLater<R>::value, R>::type
+ inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
+ return then([instance, func](Try<T>&& t) {
+ return (instance->*func)(std::move(t));
+ });
+ }
+
/*
* Resets the executor - all then() calls made after the call to via() will be
* made in the new executor. The Executor must outlive.
* called in the executor provided in the constructor. Subsequent then()
* calls will be made, potentially changing threads if a via() call is made.
* The future returned will be fulfilled in the last executor.
- *
- * Thread safety issues of Futures still apply. If you want to wait on the
- * Future, it must be done in the thread that will fulfil it.
*/
Future<T> launch();
- /*
- * Same as launch, only no Future is returned. This guarantees thread safe
- * cleanup of the internal Futures, even if the Later completes in a different
- * thread than the thread that calls fireAndForget().
- *
- * Deprecated. Use launch()
- */
- void fireAndForget() { launch(); }
-
private:
Promise<void> starter_;
folly::Optional<Future<T>> future_;
friend class Later;
};
+// See Future.whenAll
+template <class T>
+Later<std::vector<Try<T>>> whenAllLater(std::vector<Later<T>>&& laters);
+
}}
-#include "Later-inl.h"
+#include <folly/wangle/Later-inl.h>