diff --git a/include/continuable/detail/support/asio.hpp b/include/continuable/detail/support/asio.hpp index da885ef..f62fcee 100644 --- a/include/continuable/detail/support/asio.hpp +++ b/include/continuable/detail/support/asio.hpp @@ -33,17 +33,49 @@ #if defined(ASIO_STANDALONE) #include #include +#include + +#if (ASIO_VERSION / 100 % 1000) <= 12 +#define CTI_DETAIL_ASIO_HAS_NO_INTEGRATION +#elif (ASIO_VERSION / 100 % 1000) <= 14 +#define CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION +#endif + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) #include +#endif #define CTI_DETAIL_ASIO_NAMESPACE_BEGIN namespace asio { #define CTI_DETAIL_ASIO_NAMESPACE_END } #else #include #include -#include +#include -#define CTI_DETAIL_ASIO_NAMESPACE_BEGIN namespace boost { namespace asio { -#define CTI_DETAIL_ASIO_NAMESPACE_END }} +#if (BOOST_VERSION / 100 % 1000) <= 69 +#define CTI_DETAIL_ASIO_HAS_NO_INTEGRATION +#elif (BOOST_VERSION / 100 % 1000) <= 71 +#define CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION +#endif + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) +#include +#endif + +#define CTI_DETAIL_ASIO_NAMESPACE_BEGIN \ + namespace boost { \ + namespace asio { +#define CTI_DETAIL_ASIO_NAMESPACE_END \ + } \ + } +#endif + +#if defined(CTI_DETAIL_ASIO_HAS_NO_INTEGRATION) +#error \ + "First-class ASIO support for continuable requires the form of "\ + "`async_result` with an `initiate` static member function, which was added " \ + "in standalone ASIO 1.13.0 and Boost ASIO 1.70. Older versions can be " \ + "integrated manually with `cti::promisify`." #endif #include @@ -54,10 +86,38 @@ namespace asio { #if defined(ASIO_STANDALONE) using error_code_t = ::asio::error_code; +using error_cond_t = std::error_condition; + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) using exception_t = ::asio::system_error; +#endif #else using error_code_t = ::boost::system::error_code; +using error_cond_t = ::boost::system::error_condition; + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) using exception_t = ::boost::system::system_error; +#endif +#endif + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) +template +void promise_exception_helper(Promise& promise, error_code_t e) noexcept { + promise.set_exception(std::make_exception_ptr(exception_t(std::move(e)))); +} +#else +template +void promise_exception_helper(Promise& promise, error_code_t e) noexcept + ->decltype(promise.set_exception(std::move(e))) { + return promise.set_exception(std::move(e)); +} + +template +void promise_exception_helper(Promise& promise, error_code_t e) noexcept + ->decltype(promise.set_exception(error_cond_t(e.value(), e.category()))) { + promise.set_exception(error_cond_t(e.value(), e.category())); +} + #endif // Binds `promise` to the first argument of a continuable resolver, giving it @@ -65,41 +125,48 @@ using exception_t = ::boost::system::system_error; template auto promise_resolver_handler(Promise&& promise) noexcept { return [promise = std::forward(promise)]( - error_code_t e, auto&&... args) mutable noexcept { + error_code_t e, auto&&... args) mutable noexcept { if (e) { - promise.set_exception(std::make_exception_ptr(exception_t(std::move(e)))); + promise_exception_helper(promise, std::move(e)); } else { promise.set_value(std::forward(args)...); } }; } -// Type deduction helper for `Result` in `cti::make_continuable` +// Helper struct wrapping a call to `cti::make_continuable` and, if needed, +// providing an erased, explicit `return_type` for `async_result`. template -struct continuable_result; +struct initiate_make_continuable; -template <> -struct continuable_result { - using type = void; +template +struct initiate_make_continuable { + using is_void_cti_t = std::integral_constant; + +#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION) + using erased_return_type = + std::conditional_t, + cti::continuable>; +#endif + + template + auto operator()(Continuation&& continuation, + std::enable_if_t* = 0) { + return cti::make_continuable( + std::forward(continuation)); + } + + template + auto operator()(Continuation&& continuation, + std::enable_if_t* = 0) { + return cti::make_continuable( + std::forward(continuation)); + } }; -template <> -struct continuable_result - : continuable_result {}; - -template -struct continuable_result { - using type = T; -}; - -template -struct continuable_result - : continuable_result {}; - -template -using continuable_result_t = typename continuable_result::type; - - +template +struct initiate_make_continuable + : initiate_make_continuable {}; } // namespace asio } // namespace detail diff --git a/include/continuable/support/asio.hpp b/include/continuable/support/asio.hpp index f1dfcbf..a00b5b2 100644 --- a/include/continuable/support/asio.hpp +++ b/include/continuable/support/asio.hpp @@ -45,10 +45,20 @@ constexpr use_cti_t use_cti{}; template class async_result { public: +#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION) + using return_type = typename cti::detail::asio::initiate_make_continuable< + Signature>::erased_return_type; +#endif + template - static auto initiate(Initiation initiation, use_cti_t, Args... args) { - return cti::make_continuable< - cti::detail::asio::continuable_result_t>( + static +#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION) + return_type +#else + auto +#endif + initiate(Initiation initiation, use_cti_t, Args... args) { + return cti::detail::asio::initiate_make_continuable{}( [initiation = std::move(initiation), init_args = std::make_tuple(std::move(args)...)](auto&& promise) mutable { @@ -69,5 +79,6 @@ CTI_DETAIL_ASIO_NAMESPACE_END #undef CTI_DETAIL_ASIO_NAMESPACE_BEGIN #undef CTI_DETAIL_ASIO_NAMESPACE_END +#undef CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION #endif // CONTINUABLE_SUPPORT_ASIO_HPP_INCLUDED