From: Dor Gross Date: Sat, 28 Feb 2015 01:17:18 +0000 (-0800) Subject: Creating a flatten() method to get the inner Future value out of a Future value out of a Future>. Summary: Method will only be applicable for types of the form Future>, calling flatten() on a Future where != Future for any will result with a compile time error. Test Plan: Added tests in FutureTest.cpp. Reviewed By: hans@fb.com Subscribers: ldbrandy, trunkagent, folly-diffs@, jsedgwick, yfeldblum, icanadi FB internal diff: D1843581 Tasks: 6166903 Signature: t1:1843581:1424399517:7146924db3c238b77dd309f1d5916e44a7e81968 --- diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index 6dd7a155..12dbabb9 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -98,6 +98,20 @@ void Future::setCallback_(F&& func) { core_->setCallback(std::move(func)); } +// unwrap + +template +template +typename std::enable_if::value, + Future::Inner>>::type +Future::unwrap() { + return then([](Future::Inner> internal_future) { + return internal_future; + }); +} + +// then + // Variant: returns a value // e.g. f.then([](Try&& t){ return t.value(); }); template diff --git a/folly/futures/Future.h b/folly/futures/Future.h index 7021f4f2..5ebaed27 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -267,6 +267,13 @@ class Future { /// value (moved out), or throws the exception. T getVia(DrivableExecutor* e); + /// Unwraps the case of a Future> instance, and returns a simple + /// Future instance. + template + typename std::enable_if::value, + Future::Inner>>::type + unwrap(); + /** When this Future has completed, execute func which is a function that takes one of: (const) Try&& diff --git a/folly/futures/test/FutureTest.cpp b/folly/futures/test/FutureTest.cpp index ed696f9a..e757e405 100644 --- a/folly/futures/test/FutureTest.cpp +++ b/folly/futures/test/FutureTest.cpp @@ -1410,3 +1410,35 @@ TEST(Future, willEqual) { EXPECT_FALSE(f3.get()); } } + +// Unwrap tests. + +// A simple scenario for the unwrap call, when the promise was fulfilled +// before calling to unwrap. +TEST(Future, Unwrap_SimpleScenario) { + Future encapsulated_future = makeFuture(5484); + Future> future = makeFuture(std::move(encapsulated_future)); + EXPECT_EQ(5484, future.unwrap().value()); +} + +// Makes sure that unwrap() works when chaning Future's commands. +TEST(Future, Unwrap_ChainCommands) { + Future> future = makeFuture(makeFuture(5484)); + auto unwrapped = future.unwrap().then([](int i){ return i; }); + EXPECT_EQ(5484, unwrapped.value()); +} + +// Makes sure that the unwrap call also works when the promise was not yet +// fulfilled, and that the returned Future becomes ready once the promise +// is fulfilled. +TEST(Future, Unwrap_FutureNotReady) { + Promise> p; + Future> future = p.getFuture(); + Future unwrapped = future.unwrap(); + // Sanity - should not be ready before the promise is fulfilled. + ASSERT_FALSE(unwrapped.isReady()); + // Fulfill the promise and make sure the unwrapped future is now ready. + p.setValue(makeFuture(5484)); + ASSERT_TRUE(unwrapped.isReady()); + EXPECT_EQ(5484, unwrapped.value()); +}