diff --git a/dep/asio/asio b/dep/asio/asio index 8087252..6c054e9 160000 --- a/dep/asio/asio +++ b/dep/asio/asio @@ -1 +1 @@ -Subproject commit 8087252a0c3c2f0baad96ddbd6554db17a846376 +Subproject commit 6c054e98f3f53352d12b6cd46d63b6d404cc044b diff --git a/examples/example-asio/example-asio-integration.cpp b/examples/example-asio/example-asio-integration.cpp index 38e4b83..3dcb58c 100644 --- a/examples/example-asio/example-asio-integration.cpp +++ b/examples/example-asio/example-asio-integration.cpp @@ -50,18 +50,22 @@ void unexpected_error(cti::exception_t); // Check that the failure was an aborted operation, as expected. void check_aborted_operation(cti::exception_t); +// Use a strand as executor +void using_strand(); + int main(int, char**) { daytime_service(); successful_async_wait(); cancelled_async_wait(); + using_strand(); + return 0; } void daytime_service() { using asio::ip::tcp; - asio::io_context ioc(1); tcp::resolver resolver(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."); } } + +template +auto through_post(T& postable) { + return [&postable](auto&& work) mutable { + asio::post(postable, std::forward(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(); +} diff --git a/include/continuable/detail/external/asio.hpp b/include/continuable/detail/external/asio.hpp index 8a901cf..92c97d2 100644 --- a/include/continuable/detail/external/asio.hpp +++ b/include/continuable/detail/external/asio.hpp @@ -109,31 +109,50 @@ using system_error_t = ::boost::system::system_error; # endif #endif -// Binds `promise` to the first argument of a continuable resolver, giving it -// the signature of an ASIO handler. template -auto promise_resolver_handler(Promise&& promise, Token&& token) noexcept { - return [promise = std::forward(promise), - token = std::forward(token)](error_code_t e, - auto&&... args) mutable noexcept { +class promise_resolver { +public: + explicit promise_resolver(Promise promise, Token token) + : promise_(std::move(promise)) + , token_(std::move(token)) {} + + template + void operator()(T&&... args) noexcept { + promise_.set_value(std::forward(args)...); + } + + template + void operator()(error_code_t e, T&&... args) noexcept { if (e) { - if (!token.is_ignored(e)) { - if (token.is_cancellation(e)) { - promise.set_canceled(); + if (!token_.is_ignored(e)) { + if (token_.is_cancellation(e)) { + promise_.set_canceled(); return; } else { #if defined(CONTINUABLE_HAS_EXCEPTIONS) - promise.set_exception( + promise_.set_exception( std::make_exception_ptr(system_error_t(std::move(e)))); #else - promise.set_exception(exception_t(e.value(), e.category())); + promise_.set_exception(exception_t(e.value(), e.category())); #endif return; } } } - promise.set_value(std::forward(args)...); - }; + promise_.set_value(std::forward(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 +auto promise_resolver_handler(Promise&& promise, Token&& token) noexcept { + return promise_resolver, std::decay_t>( + std::forward(promise), std::forward(token)); } // 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 struct initiate_make_continuable; +template +struct initiate_make_continuable { +#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION) + using erased_return_type = continuable; +#endif + + template + auto operator()(Continuation&& continuation) { + return base::attorney::create_from(std::forward(continuation), + identity{}, util::ownership{}); + } +}; + template struct initiate_make_continuable { #if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION)