Add the void(...) asio handler overload to the use_continuable initiation token

* Makes it possible to use the initiation token with dispatch/post
* Ref #44
This commit is contained in:
Denis Blank 2021-10-22 07:53:20 +02:00
parent e2b5fc36fe
commit e6f817ca7b
3 changed files with 75 additions and 15 deletions

@ -1 +1 @@
Subproject commit 8087252a0c3c2f0baad96ddbd6554db17a846376 Subproject commit 6c054e98f3f53352d12b6cd46d63b6d404cc044b

View File

@ -50,18 +50,22 @@ void unexpected_error(cti::exception_t);
// Check that the failure was an aborted operation, as expected. // Check that the failure was an aborted operation, as expected.
void check_aborted_operation(cti::exception_t); void check_aborted_operation(cti::exception_t);
// Use a strand as executor
void using_strand();
int main(int, char**) { int main(int, char**) {
daytime_service(); daytime_service();
successful_async_wait(); successful_async_wait();
cancelled_async_wait(); cancelled_async_wait();
using_strand();
return 0; return 0;
} }
void daytime_service() { void daytime_service() {
using asio::ip::tcp; using asio::ip::tcp;
asio::io_context ioc(1); asio::io_context ioc(1);
tcp::resolver resolver(ioc); tcp::resolver resolver(ioc);
tcp::socket socket(ioc); tcp::socket socket(ioc);
@ -146,3 +150,27 @@ void check_aborted_operation(cti::exception_t ex) {
puts("Continuation failed due to aborted async operation, as expected."); puts("Continuation failed due to aborted async operation, as expected.");
} }
} }
template <typename T>
auto through_post(T& postable) {
return [&postable](auto&& work) mutable {
asio::post(postable, std::forward<decltype(work)>(work));
};
}
void using_strand() {
asio::io_context ioc(1);
asio::io_context::strand strand(ioc);
asio::post(strand, cti::use_continuable).then([]() {
puts("Dispatched through initiation token");
});
cti::async_on(
[]() mutable {
puts("Dispatched through executor token");
},
through_post(strand));
ioc.run();
}

View File

@ -109,31 +109,50 @@ using system_error_t = ::boost::system::system_error;
# endif # endif
#endif #endif
// Binds `promise` to the first argument of a continuable resolver, giving it
// the signature of an ASIO handler.
template <typename Promise, typename Token> template <typename Promise, typename Token>
auto promise_resolver_handler(Promise&& promise, Token&& token) noexcept { class promise_resolver {
return [promise = std::forward<Promise>(promise), public:
token = std::forward<Token>(token)](error_code_t e, explicit promise_resolver(Promise promise, Token token)
auto&&... args) mutable noexcept { : promise_(std::move(promise))
, token_(std::move(token)) {}
template <typename... T>
void operator()(T&&... args) noexcept {
promise_.set_value(std::forward<T>(args)...);
}
template <typename... T>
void operator()(error_code_t e, T&&... args) noexcept {
if (e) { if (e) {
if (!token.is_ignored(e)) { if (!token_.is_ignored(e)) {
if (token.is_cancellation(e)) { if (token_.is_cancellation(e)) {
promise.set_canceled(); promise_.set_canceled();
return; return;
} else { } else {
#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(exception_t(e.value(), e.category())); promise_.set_exception(exception_t(e.value(), e.category()));
#endif #endif
return; return;
} }
} }
} }
promise.set_value(std::forward<decltype(args)>(args)...); promise_.set_value(std::forward<T>(args)...);
}; }
private:
Promise promise_;
Token token_;
};
// Binds `promise` to the first argument of a continuable resolver, giving it
// the signature of an ASIO handler.
template <typename Promise, typename Token>
auto promise_resolver_handler(Promise&& promise, Token&& token) noexcept {
return promise_resolver<std::decay_t<Promise>, std::decay_t<Token>>(
std::forward<Promise>(promise), std::forward<Token>(token));
} }
// Helper struct wrapping a call to `cti::make_continuable` and, if needed, // Helper struct wrapping a call to `cti::make_continuable` and, if needed,
@ -141,6 +160,19 @@ auto promise_resolver_handler(Promise&& promise, Token&& token) noexcept {
template <typename Signature> template <typename Signature>
struct initiate_make_continuable; struct initiate_make_continuable;
template <typename... Args>
struct initiate_make_continuable<void(Args...)> {
#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION)
using erased_return_type = continuable<Args...>;
#endif
template <typename Continuation>
auto operator()(Continuation&& continuation) {
return base::attorney::create_from(std::forward<Continuation>(continuation),
identity<Args...>{}, util::ownership{});
}
};
template <typename... Args> template <typename... Args>
struct initiate_make_continuable<void(error_code_t, Args...)> { struct initiate_make_continuable<void(error_code_t, Args...)> {
#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION) #if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION)