diff --git a/core/future.hh b/core/future.hh index 7ee5e882f9..b716927c39 100644 --- a/core/future.hh +++ b/core/future.hh @@ -257,6 +257,7 @@ template struct is_future : std::false_type {}; template struct is_future> : std::true_type {}; struct ready_future_marker {}; +struct ready_future_from_tuple_marker {}; struct exception_future_marker {}; template @@ -273,6 +274,10 @@ private: future(ready_future_marker, A&&... a) : _promise(nullptr) { _local_state.set(std::forward(a)...); } + template + future(ready_future_from_tuple_marker, std::tuple&& data) : _promise(nullptr) { + _local_state.set(std::move(data)); + } future(exception_future_marker, std::exception_ptr ex) noexcept : _promise(nullptr) { _local_state.set_exception(std::move(ex)); } @@ -386,6 +391,34 @@ public: return next_fut; } + template + std::result_of_t)> + then_wrapped(Func&& func) && noexcept { + using P = typename std::result_of_t)>::promise_type; + if (state()->available()) { + try { + return func(std::move(*this)); + } catch (...) { + P pr; + pr.set_exception(std::current_exception()); + return pr.get_future(); + } + } + P pr; + auto next_fut = pr.get_future(); + _promise->schedule([func = std::forward(func), pr = std::move(pr)] (auto& state) mutable { + try { + auto next_fut = func(future(ready_future_from_tuple_marker(), state.get())); + next_fut.forward_to(std::move(pr)); + } catch (...) { + pr.set_exception(std::current_exception()); + } + }); + _promise->_future = nullptr; + _promise = nullptr; + return next_fut; + } + template future<> rescue(Func&& func) noexcept { if (state()->available()) {