Creating a flatten() method to get the inner Future<T> value out of a Future<Future...
authorDor Gross <dor@fb.com>
Sat, 28 Feb 2015 01:17:18 +0000 (17:17 -0800)
committerAlecs King <int@fb.com>
Tue, 3 Mar 2015 03:31:01 +0000 (19:31 -0800)
Summary: Method will only be applicable for types of the form Future<Future<T>>, calling flatten() on a Future<T> where <T> != Future<R> for any <R> 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

folly/futures/Future-inl.h
folly/futures/Future.h
folly/futures/test/FutureTest.cpp

index 6dd7a15514aca089c5244dd7d4af6f1395095732..12dbabb949331aae8c212b618c116051c04537b5 100644 (file)
@@ -98,6 +98,20 @@ void Future<T>::setCallback_(F&& func) {
   core_->setCallback(std::move(func));
 }
 
+// unwrap
+
+template <class T>
+template <class F>
+typename std::enable_if<isFuture<F>::value,
+                        Future<typename isFuture<T>::Inner>>::type
+Future<T>::unwrap() {
+  return then([](Future<typename isFuture<T>::Inner> internal_future) {
+      return internal_future;
+  });
+}
+
+// then
+
 // Variant: returns a value
 // e.g. f.then([](Try<T>&& t){ return t.value(); });
 template <class T>
index 7021f4f20edace260fde27d502889746021e7541..5ebaed276aef9f907ff7868f48e84808b2854751 100644 (file)
@@ -267,6 +267,13 @@ class Future {
   /// value (moved out), or throws the exception.
   T getVia(DrivableExecutor* e);
 
+  /// Unwraps the case of a Future<Future<T>> instance, and returns a simple
+  /// Future<T> instance.
+  template <class F = T>
+  typename std::enable_if<isFuture<F>::value,
+                          Future<typename isFuture<T>::Inner>>::type
+  unwrap();
+
   /** When this Future has completed, execute func which is a function that
     takes one of:
       (const) Try<T>&&
index ed696f9a65c497313212bbb716f063a6a6358970..e757e405270319a1c9bd89f595cbb844a67c473b 100644 (file)
@@ -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<int> encapsulated_future = makeFuture(5484);
+  Future<Future<int>> 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<int>> 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<T> becomes ready once the promise
+// is fulfilled.
+TEST(Future, Unwrap_FutureNotReady) {
+  Promise<Future<int>> p;
+  Future<Future<int>> future = p.getFuture();
+  Future<int> 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());
+}