Base implementation of an ASIO completion token integration

* Bump the asio version to 1.41
* Move headers that require an external dependency to include/continuable/support
* Ref #28
* Ref #27
This commit is contained in:
Christos Stratopoulos 2019-12-05 11:57:35 -05:00 committed by Denis Blank
parent 0b1b284e3a
commit 1a1c7b68c6
9 changed files with 392 additions and 13 deletions

@ -1 +1 @@
Subproject commit 0a52abce85ab83b920cc7257d8a2703fe69bc79c
Subproject commit 8087252a0c3c2f0baad96ddbd6554db17a846376

View File

@ -49,7 +49,7 @@ Continuable is a header-only library with one required header-only dependency:
erasure wrapper to convert a \ref continuable_base into a \ref continuable.
Additionally GTest is required as optional dependency for the asynchronous
unit testing macros defined in `continuable/continuable-testing.hpp`
unit testing macros defined in `continuable/support/gtest.hpp`
if those are used:
- [google/googletest](https://github.com/google/googletest) is used as

View File

@ -1,15 +1,28 @@
add_library(asio-example-deps INTERFACE)
target_include_directories(asio-example-deps
INTERFACE
${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(asio-example-deps
INTERFACE
asio
continuable)
add_executable(example-asio
${CMAKE_CURRENT_LIST_DIR}/example-asio.cpp)
target_include_directories(example-asio
PRIVATE
${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(example-asio
PRIVATE
asio
continuable)
asio-example-deps)
target_compile_definitions(example-asio
PUBLIC
-DCONTINUABLE_WITH_NO_EXCEPTIONS)
add_executable(example-asio-integration
${CMAKE_CURRENT_LIST_DIR}/example-asio-integration.cpp)
target_link_libraries(example-asio-integration
PRIVATE
asio-example-deps)

View File

@ -0,0 +1,129 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v4.0.0
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
#include <asio.hpp>
#include <continuable/continuable.hpp>
#include <continuable/support/asio.hpp>
// Queries the NIST daytime service and prints the current date and time
void daytime_service();
// Checks that a cancelled timer async_wait fails with
// `asio::error::operation_aborted`
void cancelled_async_wait();
// Indicates fatal error due to an unexpected failure in the continuation chain.
void unexpected_error(cti::exception_t);
// Check that the failure was an aborted operation, as expected.
void check_aborted_operation(cti::exception_t);
int main(int, char**) {
daytime_service();
cancelled_async_wait();
return 0;
}
void daytime_service() {
using asio::ip::tcp;
asio::io_context ioc(1);
tcp::resolver resolver(ioc);
tcp::socket socket(ioc);
std::string buf;
resolver.async_resolve("time.nist.gov", "daytime", cti::asio_token)
.then([&socket](tcp::resolver::results_type endpoints) {
return asio::async_connect(socket, endpoints, cti::asio_token);
})
.then([&socket, &buf] {
return asio::async_read_until(socket, asio::dynamic_buffer(buf), '\n',
cti::asio_token);
})
.then([&buf](std::size_t) { puts(buf.data()); })
.fail(&unexpected_error);
ioc.run();
}
void cancelled_async_wait() {
asio::io_context ioc(1);
asio::steady_timer t(ioc);
t.expires_after(std::chrono::seconds(999));
t.async_wait(cti::asio_token)
.then([] {
puts("This should never be called");
std::terminate();
})
.fail(&check_aborted_operation);
t.cancel_one();
ioc.run();
}
void unexpected_error(cti::exception_t e) {
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
std::rethrow_exception(e);
#else
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)
try {
std::rethrow_exception(ex);
} catch (asio::system_error const& err) {
if (is_expected_error(err.code())) {
return;
}
}
#else
if (is_expected_error(ex)) {
return;
}
#endif
unexpected_error(ex);
}

View File

@ -5,7 +5,7 @@
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v3.0.0
v4.0.0
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>

View File

@ -0,0 +1,154 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v4.0.0
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
#ifndef CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED
#define CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED
#include <continuable/detail/features.hpp>
#if defined(ASIO_STANDALONE)
#include <asio/async_result.hpp>
#include <asio/error_code.hpp>
#include <asio/version.hpp>
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
#include <asio/system_error.hpp>
#endif
#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
#define CTI_DETAIL_ASIO_NAMESPACE_BEGIN namespace asio {
#define CTI_DETAIL_ASIO_NAMESPACE_END }
#else
#include <boost/asio/async_result.hpp>
#include <boost/system/error_code.hpp>
#include <boost/version.hpp>
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
#include <boost/system/system_error.hpp>
#endif
#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
#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 <continuable/detail/core/base.hpp>
#include <utility>
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
#include <exception>
#endif
namespace cti {
namespace detail {
namespace asio {
#if defined(ASIO_STANDALONE)
using error_code_t = ::asio::error_code;
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
using system_error_t = ::asio::system_error;
#endif
#else
using error_code_t = ::boost::system::error_code;
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
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 <typename Promise>
auto promise_resolver_handler(Promise&& promise) noexcept {
return [promise = std::forward<Promise>(promise)](
error_code_t e, auto&&... args) mutable noexcept {
if (e) {
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
promise.set_exception(
std::make_exception_ptr(system_error_t(std::move(e))));
#else
promise.set_exception(cti::exception_t(e.value(), e.category()));
#endif
} else {
promise.set_value(std::forward<decltype(args)>(args)...);
}
};
}
// Helper struct wrapping a call to `cti::make_continuable` and, if needed,
// providing an erased, explicit `return_type` for `async_result`.
template <typename Signature>
struct initiate_make_continuable;
template <typename... Args>
struct initiate_make_continuable<void(error_code_t, Args...)> {
#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION)
using erased_return_type = cti::continuable<Args...>;
#endif
template <typename Continuation>
auto operator()(Continuation&& continuation) {
return detail::base::attorney::create_from(
std::forward<Continuation>(continuation), detail::identity<Args...>{},
detail::util::ownership{});
}
};
template <typename... Args>
struct initiate_make_continuable<void(error_code_t const&, Args...)>
: initiate_make_continuable<void(error_code_t, Args...)> {};
} // namespace asio
} // namespace detail
} // namespace cti
#endif // CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED

View File

@ -0,0 +1,83 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v4.0.0
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
#ifndef CONTINUABLE_SUPPORT_ASIO_HPP_INCLUDED
#define CONTINUABLE_SUPPORT_ASIO_HPP_INCLUDED
#include <continuable/continuable-base.hpp>
#include <continuable/detail/support/asio.hpp>
#include <continuable/detail/utility/traits.hpp>
namespace cti {
// Type used as an ASIO completion token to specify an asynchronous operation
// should return a continuable.
struct asio_token_t {};
// Special value for instance of `asio_token_t`.
constexpr asio_token_t asio_token{};
} // namespace cti
CTI_DETAIL_ASIO_NAMESPACE_BEGIN
template <typename Signature>
class async_result<cti::asio_token_t, Signature> {
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 <typename Initiation, typename... Args>
static auto initiate(Initiation initiation, cti::asio_token_t, Args... args) {
return cti::detail::asio::initiate_make_continuable<Signature>{}(
[initiation = std::move(initiation),
init_args =
std::make_tuple(std::move(args)...)](auto&& promise) mutable {
cti::detail::traits::unpack(
[initiation = std::move(initiation),
handler = cti::detail::asio::promise_resolver_handler(
std::forward<decltype(promise)>(promise))](
auto&&... args) mutable {
std::move(initiation)(std::move(handler),
std::forward<decltype(args)>(args)...);
},
std::move(init_args));
});
}
};
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

View File

@ -28,8 +28,8 @@
SOFTWARE.
**/
#ifndef CONTINUABLE_TESTING_HPP_INCLUDED
#define CONTINUABLE_TESTING_HPP_INCLUDED
#ifndef CONTINUABLE_SUPPORT_GTEST_HPP_INCLUDED
#define CONTINUABLE_SUPPORT_GTEST_HPP_INCLUDED
#include <continuable/detail/other/testing.hpp>
#include <continuable/detail/utility/traits.hpp>
@ -169,4 +169,4 @@
/// \}
#endif // CONTINUABLE_TESTING_HPP_INCLUDED
#endif // CONTINUABLE_SUPPORT_GTEST_HPP_INCLUDED

View File

@ -31,8 +31,8 @@
#include <functional>
#include <continuable/continuable-base.hpp>
#include <continuable/continuable-testing.hpp>
#include <continuable/continuable.hpp>
#include <continuable/support/gtest.hpp>
#include <string>
using cti::detail::identity;