Remap asio::error::basic_errors::operation_aborted to a default constructed exception_t

* Add a successful wait on the asio async timer
* Closes #27
* Closes #28
This commit is contained in:
Denis Blank 2020-04-03 19:37:51 +02:00
parent 564d134c75
commit ca26bbbc87
2 changed files with 64 additions and 36 deletions

View File

@ -36,8 +36,12 @@
// Queries the NIST daytime service and prints the current date and time // Queries the NIST daytime service and prints the current date and time
void daytime_service(); void daytime_service();
// Checks that a timer async_wait returns successfully
void successful_async_wait();
// Checks that a cancelled timer async_wait fails with // Checks that a cancelled timer async_wait fails with
// `asio::error::operation_aborted` // `asio::error::operation_aborted` and is converted to a default constructed
// cti::exception_t.
void cancelled_async_wait(); void cancelled_async_wait();
// Indicates fatal error due to an unexpected failure in the continuation chain. // Indicates fatal error due to an unexpected failure in the continuation chain.
@ -48,6 +52,8 @@ void check_aborted_operation(cti::exception_t);
int main(int, char**) { int main(int, char**) {
daytime_service(); daytime_service();
successful_async_wait();
cancelled_async_wait(); cancelled_async_wait();
return 0; return 0;
@ -69,7 +75,25 @@ void daytime_service() {
return asio::async_read_until(socket, asio::dynamic_buffer(buf), '\n', return asio::async_read_until(socket, asio::dynamic_buffer(buf), '\n',
cti::use_continuable); cti::use_continuable);
}) })
.then([&buf](std::size_t) { puts(buf.data()); }) .then([&buf](std::size_t) {
puts("Continuation successfully got a daytime response:");
puts(buf.c_str());
})
.fail(&unexpected_error);
ioc.run();
}
void successful_async_wait() {
asio::io_context ioc(1);
asio::steady_timer t(ioc);
t.expires_after(std::chrono::seconds(1));
t.async_wait(cti::use_continuable)
.then([] {
puts("Continuation succeeded after 1s as expected!");
})
.fail(&unexpected_error); .fail(&unexpected_error);
ioc.run(); ioc.run();
@ -93,37 +117,32 @@ void cancelled_async_wait() {
} }
void unexpected_error(cti::exception_t e) { void unexpected_error(cti::exception_t e) {
#if defined(CONTINUABLE_HAS_EXCEPTIONS) if (!bool(e)) {
std::rethrow_exception(e); puts("Continuation failed with unexpected cancellation!");
#else std::terminate();
puts("Continuation failed with unexpected error"); }
puts(e.message().data());
std::terminate();
#endif
}
void check_aborted_operation(cti::exception_t ex) {
auto is_expected_error = [](auto err_val) {
if (err_val == asio::error_code(asio::error::operation_aborted)) {
puts("Continuation failed due to aborted async operation, as expected.");
return true;
}
return false;
};
#if defined(CONTINUABLE_HAS_EXCEPTIONS) #if defined(CONTINUABLE_HAS_EXCEPTIONS)
try { try {
std::rethrow_exception(ex); std::rethrow_exception(e);
} catch (asio::system_error const& err) { } catch (std::exception const& ex) {
if (is_expected_error(err.code())) { puts("Continuation failed with unexpected exception");
return; puts(ex.what());
} } catch (...) {
// Rethrow the exception to the asynchronous unhandled exception handler
std::rethrow_exception(std::current_exception());
} }
#else #else
if (is_expected_error(ex)) { puts("Continuation failed with unexpected error");
return; puts(e.message().data());
}
#endif #endif
std::terminate();
unexpected_error(ex); }
void check_aborted_operation(cti::exception_t ex) {
if (bool(ex)) {
unexpected_error(ex);
} else {
puts("Continuation failed due to aborted async operation, as expected.");
}
} }

View File

@ -30,10 +30,14 @@
#ifndef CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED #ifndef CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED
#define CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED #define CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED
#include <utility>
#include <continuable/continuable-base.hpp>
#include <continuable/detail/core/base.hpp>
#include <continuable/detail/features.hpp> #include <continuable/detail/features.hpp>
#if defined(ASIO_STANDALONE) #if defined(ASIO_STANDALONE)
#include <asio/async_result.hpp> #include <asio/async_result.hpp>
#include <asio/error.hpp>
#include <asio/error_code.hpp> #include <asio/error_code.hpp>
#include <asio/version.hpp> #include <asio/version.hpp>
@ -51,6 +55,7 @@
#define CTI_DETAIL_ASIO_NAMESPACE_END } #define CTI_DETAIL_ASIO_NAMESPACE_END }
#else #else
#include <boost/asio/async_result.hpp> #include <boost/asio/async_result.hpp>
#include <boost/asio/error.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
@ -79,10 +84,6 @@
"integrated manually with `cti::promisify`." "integrated manually with `cti::promisify`."
#endif #endif
#include <continuable/detail/core/base.hpp>
#include <utility>
#if defined(CONTINUABLE_HAS_EXCEPTIONS) #if defined(CONTINUABLE_HAS_EXCEPTIONS)
#include <exception> #include <exception>
#endif #endif
@ -93,12 +94,14 @@ namespace asio {
#if defined(ASIO_STANDALONE) #if defined(ASIO_STANDALONE)
using error_code_t = ::asio::error_code; using error_code_t = ::asio::error_code;
using basic_errors_t = ::asio::error::basic_errors;
#if defined(CONTINUABLE_HAS_EXCEPTIONS) #if defined(CONTINUABLE_HAS_EXCEPTIONS)
using system_error_t = ::asio::system_error; using system_error_t = ::asio::system_error;
#endif #endif
#else #else
using error_code_t = ::boost::system::error_code; using error_code_t = ::boost::system::error_code;
using basic_errors_t = ::boost::asio::error::basic_errors;
#if defined(CONTINUABLE_HAS_EXCEPTIONS) #if defined(CONTINUABLE_HAS_EXCEPTIONS)
using system_error_t = ::boost::system::system_error; using system_error_t = ::boost::system::system_error;
@ -112,12 +115,18 @@ auto promise_resolver_handler(Promise&& promise) noexcept {
return [promise = std::forward<Promise>(promise)]( return [promise = std::forward<Promise>(promise)](
error_code_t e, auto&&... args) mutable noexcept { error_code_t e, auto&&... args) mutable noexcept {
if (e) { if (e) {
if (e != basic_errors_t::operation_aborted) {
#if defined(CONTINUABLE_HAS_EXCEPTIONS) #if defined(CONTINUABLE_HAS_EXCEPTIONS)
promise.set_exception( promise.set_exception(
std::make_exception_ptr(system_error_t(std::move(e)))); std::make_exception_ptr(system_error_t(std::move(e))));
#else #else
promise.set_exception(cti::exception_t(e.value(), e.category())); promise.set_exception(exception_t(e.value(), e.category()));
#endif #endif
} else {
// Continuable uses a default constructed exception type to signal
// cancellation to the followed asynchronous control flow.
promise.set_exception(exception_t{});
}
} else { } else {
promise.set_value(std::forward<decltype(args)>(args)...); promise.set_value(std::forward<decltype(args)>(args)...);
} }