Implement make_cancelling_continuable()

* Can be used to cancel the chain when being inside a handler
This commit is contained in:
Denis Blank 2018-12-25 09:30:23 +01:00
parent 4127c02c3f
commit f469b7058a
2 changed files with 58 additions and 6 deletions

View File

@ -360,10 +360,11 @@ public:
/// \since 2.0.0
template <typename OData, typename OAnnotation>
auto fail(continuable_base<OData, OAnnotation>&& continuation) && {
return std::move(*this).fail(
[continuation = std::move(continuation).freeze()](exception_t) mutable {
std::move(continuation).done();
});
return std::move(*this) //
.fail([continuation = std::move(continuation).freeze()] //
(exception_t) mutable {
std::move(continuation).done(); //
});
}
/// A method which allows to use an overloaded callable for the error
@ -866,6 +867,35 @@ constexpr auto make_exceptional_continuable(Exception&& exception) {
});
}
/// Returns a continuable_base with the parameterized result which never
/// resolves its promise and thus cancels the asynchronous continuation chain.
///
/// This can be used to cancel an asynchronous continuation chain when
/// returning a continuable_base from a handler where other paths could
/// possibly continue the asynchronous chain. See an example below:
/// ```cpp
/// do_sth().then([weak = this->weak_from_this()]() -> continuable<> {
/// if (auto me = weak.lock()) {
/// return do_sth_more();
/// } else {
/// // Abort the asynchronous continuation chain since the
/// // weakly referenced object expired previously.
/// return make_cancelling_continuable<void>();
/// }
/// });
/// ```
///
/// \tparam Signature The fake signature of the returned continuable.
///
/// \since 4.0.0
template <typename... Signature>
auto make_cancelling_continuable() {
static_assert(sizeof...(Signature) > 0,
"Requires at least one type for the fake signature!");
return make_continuable<Signature...>([](auto&&) { /* ... */ });
}
/// Can be used to recover to from a failure handler,
/// the result handler which comes after will be called with the
/// corresponding result.

View File

@ -45,7 +45,8 @@ TYPED_TEST(single_dimension_tests, are_called_on_destruct) {
ASSERT_ASYNC_TYPES(this->supply(tag1{}), tag1);
}
template <typename T> auto create_incomplete(T* me) {
template <typename T>
auto create_incomplete(T* me) {
return me->make(identity<>{}, identity<void>{}, [](auto&& callback) mutable {
// Destruct the callback here
auto destroy = std::forward<decltype(callback)>(callback);
@ -53,7 +54,16 @@ template <typename T> auto create_incomplete(T* me) {
});
}
template <typename T> auto assert_invocation(T* me) {
template <typename T>
auto create_incomplete_cancelling(T* me) {
return me->make(identity<>{}, identity<void>{}, [](auto&& callback) mutable {
make_cancelling_continuable<void>().next(
std::forward<decltype(callback)>(callback));
});
}
template <typename T>
auto assert_invocation(T* me) {
return me->make(identity<>{}, identity<void>{},
[](auto&& /*callback*/) mutable { FAIL(); });
}
@ -90,6 +100,18 @@ TYPED_TEST(single_dimension_tests, are_not_finished_when_not_continued) {
}
}
TYPED_TEST(single_dimension_tests, are_not_finished_when_cancelling) {
{
auto chain = create_incomplete_cancelling(this);
ASSERT_ASYNC_INCOMPLETION(std::move(chain));
}
{
auto chain = create_incomplete_cancelling(this);
ASSERT_ASYNC_INCOMPLETION(std::move(chain).then(this->supply()));
}
}
TYPED_TEST(single_dimension_tests, freeze_is_kept_across_the_chain) {
{
auto chain = this->supply().freeze().then([=] { return this->supply(); });