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 /// \since 2.0.0
template <typename OData, typename OAnnotation> template <typename OData, typename OAnnotation>
auto fail(continuable_base<OData, OAnnotation>&& continuation) && { auto fail(continuable_base<OData, OAnnotation>&& continuation) && {
return std::move(*this).fail( return std::move(*this) //
[continuation = std::move(continuation).freeze()](exception_t) mutable { .fail([continuation = std::move(continuation).freeze()] //
std::move(continuation).done(); (exception_t) mutable {
}); std::move(continuation).done(); //
});
} }
/// A method which allows to use an overloaded callable for the error /// 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, /// Can be used to recover to from a failure handler,
/// the result handler which comes after will be called with the /// the result handler which comes after will be called with the
/// corresponding result. /// corresponding result.

View File

@ -45,7 +45,8 @@ TYPED_TEST(single_dimension_tests, are_called_on_destruct) {
ASSERT_ASYNC_TYPES(this->supply(tag1{}), tag1); 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 { return me->make(identity<>{}, identity<void>{}, [](auto&& callback) mutable {
// Destruct the callback here // Destruct the callback here
auto destroy = std::forward<decltype(callback)>(callback); 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>{}, return me->make(identity<>{}, identity<void>{},
[](auto&& /*callback*/) mutable { FAIL(); }); [](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) { TYPED_TEST(single_dimension_tests, freeze_is_kept_across_the_chain) {
{ {
auto chain = this->supply().freeze().then([=] { return this->supply(); }); auto chain = this->supply().freeze().then([=] { return this->supply(); });