Commit b29280e3 authored by Lee Howes's avatar Lee Howes Committed by Facebook Github Bot

Make onError depend on thenError

Summary: Remove duplicate code from Future::onError and have it call Future::thenError.

Reviewed By: yfeldblum

Differential Revision: D13823960

fbshipit-source-id: d2e48e4e65e30c80adbbd70ff314e1a418b7c1e2
parent 0e818b2e
...@@ -1236,31 +1236,18 @@ typename std::enable_if< ...@@ -1236,31 +1236,18 @@ typename std::enable_if<
!futures::detail::Extract<F>::ReturnsFuture::value, !futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type Future<T>>::type
Future<T>::onError(F&& func) && { Future<T>::onError(F&& func) && {
typedef std::remove_reference_t< typedef typename futures::detail::Extract<F>::FirstArg Exn;
typename futures::detail::Extract<F>::FirstArg>
Exn;
static_assert( static_assert(
std::is_same<typename futures::detail::Extract<F>::RawReturn, T>::value, std::is_same<typename futures::detail::Extract<F>::RawReturn, T>::value,
"Return type of onError callback must be T or Future<T>"); "Return type of onError callback must be T or Future<T>");
Promise<T> p; // NOTE: Removes the executor to maintain historical behaviour.
p.core_->setInterruptHandlerNoLock(this->getCore().getInterruptHandler()); return std::move(*this)
auto sf = p.getSemiFuture(); .template thenError<Exn>(
[func = std::forward<F>(func)](auto&& ex) mutable {
this->setCallback_( return std::forward<F>(func)(ex);
[state = futures::detail::makeCoreCallbackState( })
std::move(p), std::forward<F>(func))](Try<T>&& t) mutable { .via(&InlineExecutor::instance());
if (auto e = t.template tryGetExceptionObject<Exn>()) {
state.setTry(makeTryWith([&] { return state.invoke(*e); }));
} else {
state.setTry(std::move(t));
}
});
// Allow for applying to future with null executor while this is still
// possible.
// TODO(T26801487): Should have an executor
return std::move(sf).via(&InlineExecutor::instance());
} }
// onError where the callback returns Future<T> // onError where the callback returns Future<T>
...@@ -1275,34 +1262,15 @@ Future<T>::onError(F&& func) && { ...@@ -1275,34 +1262,15 @@ Future<T>::onError(F&& func) && {
std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>:: std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>::
value, value,
"Return type of onError callback must be T or Future<T>"); "Return type of onError callback must be T or Future<T>");
typedef std::remove_reference_t< typedef typename futures::detail::Extract<F>::FirstArg Exn;
typename futures::detail::Extract<F>::FirstArg>
Exn;
Promise<T> p; // NOTE: Removes the executor to maintain historical behaviour.
auto sf = p.getSemiFuture(); return std::move(*this)
.template thenError<Exn>(
this->setCallback_( [func = std::forward<F>(func)](auto&& ex) mutable {
[state = futures::detail::makeCoreCallbackState( return std::forward<F>(func)(ex);
std::move(p), std::forward<F>(func))](Try<T>&& t) mutable { })
if (auto e = t.template tryGetExceptionObject<Exn>()) { .via(&InlineExecutor::instance());
auto tf2 = state.tryInvoke(*e);
if (tf2.hasException()) {
state.setException(std::move(tf2.exception()));
} else {
tf2->setCallback_([p = state.stealPromise()](Try<T>&& t3) mutable {
p.setTry(std::move(t3));
});
}
} else {
state.setTry(std::move(t));
}
});
// Allow for applying to future with null executor while this is still
// possible.
// TODO(T26801487): Should have an executor
return std::move(sf).via(&InlineExecutor::instance());
} }
template <class T> template <class T>
...@@ -1336,29 +1304,10 @@ Future<T>::onError(F&& func) && { ...@@ -1336,29 +1304,10 @@ Future<T>::onError(F&& func) && {
value, value,
"Return type of onError callback must be T or Future<T>"); "Return type of onError callback must be T or Future<T>");
Promise<T> p; // NOTE: Removes the executor to maintain historical behaviour.
auto sf = p.getSemiFuture(); return std::move(*this)
this->setCallback_( .template thenError(std::forward<F>(func))
[state = futures::detail::makeCoreCallbackState( .via(&InlineExecutor::instance());
std::move(p), std::forward<F>(func))](Try<T> t) mutable {
if (t.hasException()) {
auto tf2 = state.tryInvoke(std::move(t.exception()));
if (tf2.hasException()) {
state.setException(std::move(tf2.exception()));
} else {
tf2->setCallback_([p = state.stealPromise()](Try<T>&& t3) mutable {
p.setTry(std::move(t3));
});
}
} else {
state.setTry(std::move(t));
}
});
// Allow for applying to future with null executor while this is still
// possible.
// TODO(T26801487): Should have an executor
return std::move(sf).via(&InlineExecutor::instance());
} }
// onError(exception_wrapper) that returns T // onError(exception_wrapper) that returns T
...@@ -1374,23 +1323,10 @@ Future<T>::onError(F&& func) && { ...@@ -1374,23 +1323,10 @@ Future<T>::onError(F&& func) && {
value, value,
"Return type of onError callback must be T or Future<T>"); "Return type of onError callback must be T or Future<T>");
Promise<T> p; // NOTE: Removes the executor to maintain historical behaviour.
auto sf = p.getSemiFuture(); return std::move(*this)
this->setCallback_( .template thenError(std::forward<F>(func))
[state = futures::detail::makeCoreCallbackState( .via(&InlineExecutor::instance());
std::move(p), std::forward<F>(func))](Try<T>&& t) mutable {
if (t.hasException()) {
state.setTry(makeTryWith(
[&] { return state.invoke(std::move(t.exception())); }));
} else {
state.setTry(std::move(t));
}
});
// Allow for applying to future with null executor while this is still
// possible.
// TODO(T26801487): Should have an executor
return std::move(sf).via(&InlineExecutor::instance());
} }
template <class Func> template <class Func>
......
...@@ -1513,6 +1513,11 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1513,6 +1513,11 @@ class Future : private futures::detail::FutureBase<T> {
Future<T>>::type Future<T>>::type
onError(F&& func) &&; onError(F&& func) &&;
template <class R, class... Args>
Future<T> onError(R (&func)(Args...)) && {
return std::move(*this).onError(&func);
}
// clang-format off // clang-format off
template <class F> template <class F>
[[deprecated("ERROR: use rvalue-qualified fn, eg, std::move(future).onError(...)")]] [[deprecated("ERROR: use rvalue-qualified fn, eg, std::move(future).onError(...)")]]
......
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