Summary:
`futures::chain<A,Z>(a, b, c, d, e, f, ..., z)` where `a` is a callback suitable for `Future<A>::then` and `z` is a callback suitable for `Future<Y>::then<Z>`.
This will be important, at least in the background, for the new `via`. It will probably also be useful to some user sometime.
I imagine this will be tweaked over time if people find magic ways to get it to deduce the types better. But this works and it's not *too* much trouble to specify A and Z.
Test Plan: unit
Reviewed By: davejwatson@fb.com
Subscribers: trunkagent, exa, folly-diffs@, yfeldblum, jsedgwick
FB internal diff:
D1831073
Tasks:
6048744
Signature: t1:
1831073:
1423259292:
711be0e047a2acb706fd74e529d5d5fb6abda566
return std::move(*this);
}
+namespace futures {
+
+ namespace {
+ template <class Z, class F, class... Callbacks>
+ Future<Z> chainHelper(F, Callbacks...);
+
+ template <class Z>
+ Future<Z> chainHelper(Future<Z> f) {
+ return f;
+ }
+
+ template <class Z, class F, class Fn, class... Callbacks>
+ Future<Z> chainHelper(F f, Fn fn, Callbacks... fns) {
+ return chainHelper<Z>(f.then(fn), fns...);
+ }
+ }
+
+ template <class A, class Z, class... Callbacks>
+ std::function<Future<Z>(Try<A>)>
+ chain(Callbacks... fns) {
+ MoveWrapper<Promise<A>> pw;
+ MoveWrapper<Future<Z>> fw(chainHelper<Z>(pw->getFuture(), fns...));
+ return [=](Try<A> t) mutable {
+ pw->fulfilTry(std::move(t));
+ return std::move(*fw);
+ };
+ }
+
}
+} // namespace folly
+
// I haven't included a Future<T&> specialization because I don't forsee us
// using it, however it is not difficult to add when needed. Refer to
// Future<void> for guidance. std::future and boost::future code would also be
/// needed. If your program never uses any timeouts or other time-based
/// Futures you will pay no Timekeeper thread overhead.
Future<void> sleep(Duration, Timekeeper* = nullptr);
+
+ /// Create a Future chain from a sequence of callbacks. i.e.
+ ///
+ /// f.then(a).then(b).then(c);
+ ///
+ /// where f is a Future<A> and the result of the chain is a Future<Z>
+ /// becomes
+ ///
+ /// f.then(chain<A,Z>(a, b, c));
+ // If anyone figures how to get chain to deduce A and Z, I'll buy you a drink.
+ template <class A, class Z, class... Callbacks>
+ std::function<Future<Z>(Try<A>)>
+ chain(Callbacks... fns);
}
template <class T>
// via()&
auto f2 = f.via(eastExecutor.get());
}
+
+TEST(Via, chain1) {
+ EXPECT_EQ(42,
+ makeFuture()
+ .then(futures::chain<void, int>([] { return 42; }))
+ .get());
+}
+
+TEST(Via, chain3) {
+ int count = 0;
+ auto f = makeFuture().then(futures::chain<void, int>(
+ [&]{ count++; return 3.14159; },
+ [&](double) { count++; return std::string("hello"); },
+ [&]{ count++; return makeFuture(42); }));
+ EXPECT_EQ(42, f.get());
+ EXPECT_EQ(3, count);
+}