From d80f5ef3ec0b7a981811e64097144e477cbcefb2 Mon Sep 17 00:00:00 2001 From: Denis Blank Date: Thu, 9 Apr 2020 16:03:47 +0200 Subject: [PATCH] Make the wait transform throw a wait_transform_canceled_exception on cancellation --- include/continuable/detail/transforms/wait.hpp | 18 +++++++++++++++++- include/continuable/transforms/wait.hpp | 14 ++++++++++++++ .../unit-test/async/test-continuable-async.cpp | 6 ++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/continuable/detail/transforms/wait.hpp b/include/continuable/detail/transforms/wait.hpp index ff0e1d5..02ae9be 100644 --- a/include/continuable/detail/transforms/wait.hpp +++ b/include/continuable/detail/transforms/wait.hpp @@ -50,6 +50,18 @@ namespace cti { namespace detail { namespace transforms { +#if defined(CONTINUABLE_HAS_EXCEPTIONS) +class wait_transform_canceled_exception : public std::exception { +public: + wait_transform_canceled_exception() noexcept = default; + + char const* what() const noexcept override { + return "cti::transforms::wait canceled due to cancellation of the " + "continuation"; + } +}; +#endif // CONTINUABLE_HAS_EXCEPTIONS + template struct sync_trait; template @@ -105,7 +117,11 @@ auto wait_and_unpack(continuable_base&& continuable) { return std::move(sync_result).get_value(); } else { assert(sync_result.is_exception()); - std::rethrow_exception(sync_result.get_exception()); + if (exception_t e = sync_result.get_exception()) { + std::rethrow_exception(e); + } else { + throw wait_transform_canceled_exception(); + } } #else return sync_result; diff --git a/include/continuable/transforms/wait.hpp b/include/continuable/transforms/wait.hpp index 6f19e15..c3f7d85 100644 --- a/include/continuable/transforms/wait.hpp +++ b/include/continuable/transforms/wait.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include namespace cti { @@ -41,6 +42,15 @@ namespace cti { /// \{ namespace transforms { +#if defined(CONTINUABLE_HAS_EXCEPTIONS) +/// Is thrown from wait if the awaited continuable_base was cancelled, +/// which was signaled through resolving with a default +/// constructed exception type. +/// +/// \since 4.1.0 +using wait_transform_canceled_exception = detail::transforms::wait_transform_canceled_exception; +#endif // CONTINUABLE_HAS_EXCEPTIONS + /// Returns a transform that if applied to a continuable, /// it will start the continuation chain and returns the result synchronously. /// The current thread is blocked until the continuation chain is finished. @@ -53,6 +63,10 @@ namespace transforms { /// | `continuable_base with ` | `Arg` | /// | `continuable_base with ` | `std::tuple` | /// +/// \throws wait_transform_canceled_exception if the awaited continuable_base +/// is cancelled, and thus was resolved with a default +/// constructed exception type. +/// /// \attention If exceptions are used, exceptions that are thrown, are rethrown /// synchronously. /// diff --git a/test/unit-test/async/test-continuable-async.cpp b/test/unit-test/async/test-continuable-async.cpp index a77b231..227170b 100644 --- a/test/unit-test/async/test-continuable-async.cpp +++ b/test/unit-test/async/test-continuable-async.cpp @@ -111,6 +111,12 @@ TYPED_TEST(single_dimension_tests, wait_test_exception) { .apply(cti::transforms::wait()), test_exception); } + +TYPED_TEST(single_dimension_tests, wait_test_cancellation) { + ASSERT_THROW(make_cancelling_continuable().apply( + cti::transforms::wait()), + transforms::wait_transform_canceled_exception); +} #endif // CONTINUABLE_HAS_EXCEPTIONS TYPED_TEST(single_dimension_tests, wait_for_test_sync) {