Commit 4008ab21 authored by Jacob Lacouture's avatar Jacob Lacouture Committed by Facebook Github Bot

Future<Try<T>> -> Future<T>

Summary:
future.then([] -> T)  currently returns Future<T>
future.then([] -> Try<T>)  currently returns Future<Try<T>>

This changes that behavior, such that future.then([] -> Try<T>) will
return Future<T>.

This is a more desirable interface for futures. It also simplifies
implementation of a separate task (propagating exceptions more
efficiently through chained callbacks) because it enables us to internally
substitute lambdas returning T with lambdas returning Try<T>.

Reviewed By: yfeldblum, ryantimwilson

Differential Revision: D14318624

fbshipit-source-id: 51363e82ceb86bfecf87ae661188be9ca3dd8002
parent d10d3f04
...@@ -219,7 +219,8 @@ void Try<void>::throwIfFailed() const { ...@@ -219,7 +219,8 @@ void Try<void>::throwIfFailed() const {
template <typename F> template <typename F>
typename std::enable_if< typename std::enable_if<
!std::is_same<invoke_result_t<F>, void>::value, !std::is_same<invoke_result_t<F>, void>::value &&
!isTry<invoke_result_t<F>>::value,
Try<invoke_result_t<F>>>::type Try<invoke_result_t<F>>>::type
makeTryWith(F&& f) { makeTryWith(F&& f) {
using ResultType = invoke_result_t<F>; using ResultType = invoke_result_t<F>;
...@@ -246,6 +247,20 @@ typename std:: ...@@ -246,6 +247,20 @@ typename std::
} }
} }
template <typename F>
typename std::enable_if<isTry<invoke_result_t<F>>::value, invoke_result_t<F>>::
type
makeTryWith(F&& f) {
using ResultType = invoke_result_t<F>;
try {
return f();
} catch (std::exception& e) {
return ResultType(exception_wrapper(std::current_exception(), e));
} catch (...) {
return ResultType(exception_wrapper(std::current_exception()));
}
}
template <typename T, typename... Args> template <typename T, typename... Args>
T* tryEmplace(Try<T>& t, Args&&... args) noexcept { T* tryEmplace(Try<T>& t, Args&&... args) noexcept {
try { try {
......
...@@ -585,6 +585,12 @@ class Try<void> { ...@@ -585,6 +585,12 @@ class Try<void> {
}; };
}; };
template <typename T>
struct isTry : std::false_type {};
template <typename T>
struct isTry<Try<T>> : std::true_type {};
/* /*
* @param f a function to execute and capture the result of (value or exception) * @param f a function to execute and capture the result of (value or exception)
* *
...@@ -592,7 +598,8 @@ class Try<void> { ...@@ -592,7 +598,8 @@ class Try<void> {
*/ */
template <typename F> template <typename F>
typename std::enable_if< typename std::enable_if<
!std::is_same<invoke_result_t<F>, void>::value, !std::is_same<invoke_result_t<F>, void>::value &&
!isTry<invoke_result_t<F>>::value,
Try<invoke_result_t<F>>>::type Try<invoke_result_t<F>>>::type
makeTryWith(F&& f); makeTryWith(F&& f);
...@@ -608,6 +615,20 @@ typename std:: ...@@ -608,6 +615,20 @@ typename std::
enable_if<std::is_same<invoke_result_t<F>, void>::value, Try<void>>::type enable_if<std::is_same<invoke_result_t<F>, void>::value, Try<void>>::type
makeTryWith(F&& f); makeTryWith(F&& f);
/*
* Specialization of makeTryWith for functions that return Try<T>
* Causes makeTryWith to not double-wrap the try.
*
* @param f a function to execute and capture the result of
*
* @returns result of f if f did not throw. Otherwise Try<T> containing
* exception
*/
template <typename F>
typename std::enable_if<isTry<invoke_result_t<F>>::value, invoke_result_t<F>>::
type
makeTryWith(F&& f);
/* /*
* Try to in-place construct a new value from the specified arguments. * Try to in-place construct a new value from the specified arguments.
* *
......
...@@ -51,6 +51,12 @@ struct isFutureOrSemiFuture : std::false_type { ...@@ -51,6 +51,12 @@ struct isFutureOrSemiFuture : std::false_type {
using Return = Inner; using Return = Inner;
}; };
template <typename T>
struct isFutureOrSemiFuture<Try<T>> : std::false_type {
using Inner = lift_unit_t<T>;
using Return = Inner;
};
template <typename T> template <typename T>
struct isFutureOrSemiFuture<Future<T>> : std::true_type { struct isFutureOrSemiFuture<Future<T>> : std::true_type {
typedef T Inner; typedef T Inner;
...@@ -58,16 +64,22 @@ struct isFutureOrSemiFuture<Future<T>> : std::true_type { ...@@ -58,16 +64,22 @@ struct isFutureOrSemiFuture<Future<T>> : std::true_type {
}; };
template <typename T> template <typename T>
struct isFutureOrSemiFuture<SemiFuture<T>> : std::true_type { struct isFutureOrSemiFuture<Future<Try<T>>> : std::true_type {
typedef T Inner; typedef T Inner;
using Return = SemiFuture<Inner>; using Return = Future<Inner>;
}; };
template <typename T> template <typename T>
struct isTry : std::false_type {}; struct isFutureOrSemiFuture<SemiFuture<T>> : std::true_type {
typedef T Inner;
using Return = SemiFuture<Inner>;
};
template <typename T> template <typename T>
struct isTry<Try<T>> : std::true_type {}; struct isFutureOrSemiFuture<SemiFuture<Try<T>>> : std::true_type {
typedef T Inner;
using Return = SemiFuture<Inner>;
};
namespace futures { namespace futures {
namespace detail { namespace detail {
......
...@@ -34,7 +34,7 @@ namespace folly { ...@@ -34,7 +34,7 @@ namespace folly {
* callbacks on the same Future (which is indefinitely unsupported), consider * callbacks on the same Future (which is indefinitely unsupported), consider
* refactoring to use SharedPromise to "split" the Future. * refactoring to use SharedPromise to "split" the Future.
* *
* The ShardPromise must be kept alive manually. Consider FutureSplitter for * The SharedPromise must be kept alive manually. Consider FutureSplitter for
* automatic lifetime management. * automatic lifetime management.
*/ */
template <class T> template <class T>
......
...@@ -694,7 +694,7 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) { ...@@ -694,7 +694,7 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) {
}); });
p.setException(make_exception_wrapper<std::logic_error>("Try")); p.setException(make_exception_wrapper<std::logic_error>("Try"));
auto tryResult = std::move(sf).get(); auto tryResult = std::move(sf).get();
ASSERT_EQ(tryResult.value(), "Try"); ASSERT_EQ(tryResult, "Try");
} }
namespace { namespace {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment