mirror of
https://github.com/boostorg/asio.git
synced 2026-01-19 04:02:09 +00:00
Add redirect_disposition completion token adapter.
This commit is contained in:
@@ -88,8 +88,10 @@ passed back to the coroutine as a `system_error` exception.
|
||||
[heading Error Handling]
|
||||
|
||||
To perform explicit error handling, rather than the default exception-throwing
|
||||
behaviour, use the [link boost_asio.reference.as_tuple `as_tuple`] or
|
||||
[link boost_asio.reference.redirect_error `redirect_error`] completion token adapters.
|
||||
behaviour, use the [link boost_asio.reference.as_tuple `as_tuple`],
|
||||
[link boost_asio.reference.redirect_disposition `redirect_disposition`] or
|
||||
[link boost_asio.reference.redirect_error `redirect_error`] or completion token
|
||||
adapters.
|
||||
|
||||
The `as_tuple` completion token adapter packages the completion
|
||||
handler arguments into a single tuple, which is then returned as the result of
|
||||
@@ -296,6 +298,7 @@ protocol in terms of a coroutine:
|
||||
[link boost_asio.reference.co_spawn co_spawn],
|
||||
[link boost_asio.reference.detached detached],
|
||||
[link boost_asio.reference.as_tuple as_tuple],
|
||||
[link boost_asio.reference.redirect_disposition redirect_disposition],
|
||||
[link boost_asio.reference.redirect_error redirect_error],
|
||||
[link boost_asio.reference.awaitable awaitable],
|
||||
[link boost_asio.reference.use_awaitable_t use_awaitable_t],
|
||||
|
||||
@@ -94,6 +94,42 @@ expression will no longer throw an exception on resumption.
|
||||
// ...
|
||||
}
|
||||
|
||||
[heading redirect_disposition]
|
||||
|
||||
The [link boost_asio.reference.redirect_disposition `redirect_disposition`] function
|
||||
adapts a completion token to capture any [link boost_asio.reference.Disposition
|
||||
disposition] produced by an operation into a specified variable. In doing so, it
|
||||
modifies the completion signature to remove the initial disposition parameter.
|
||||
|
||||
This example shows the `redirect_disposition` adapter applied to a lambda, to
|
||||
specify that the disposition should be captured into `my_exception`. The
|
||||
`error_code` (which is a disposition type) is no longer passed to the completion
|
||||
handler, but the remaining arguments are passed through as-is.
|
||||
|
||||
std::exception_ptr my_exception; // N.B. must be valid until operation completes
|
||||
// ...
|
||||
my_socket.async_read_some(my_buffer,
|
||||
boost::asio::redirect_disposition(
|
||||
[](std::size_t bytes_transferred)
|
||||
{
|
||||
// ...
|
||||
}, my_exception));
|
||||
|
||||
When applied to completion tokens that cause the initiating function to produce
|
||||
a result, such as [link boost_asio.reference.use_awaitable `use_awaitable`], the
|
||||
result is returned unmodified. However, if the operation fails, the `co_await`
|
||||
expression will no longer throw an exception on resumption.
|
||||
|
||||
boost::asio::awaitable<void> my_coroutine()
|
||||
{
|
||||
// ...
|
||||
std::exception my_exception;
|
||||
std::size_t bytes_transferred =
|
||||
co_await my_socket.async_read_some(my_buffer,
|
||||
boost::asio::redirect_disposition(boost::asio::use_awaitable, my_exception));
|
||||
// ...
|
||||
}
|
||||
|
||||
[heading as_tuple]
|
||||
|
||||
The [link boost_asio.reference.as_tuple `as_tuple`] adapter can be used to specify
|
||||
|
||||
@@ -234,8 +234,10 @@
|
||||
<member><link linkend="boost_asio.reference.partial_cancellation_slot_binder">partial_cancellation_slot_binder</link></member>
|
||||
<member><link linkend="boost_asio.reference.partial_executor_binder">partial_executor_binder</link></member>
|
||||
<member><link linkend="boost_asio.reference.partial_immediate_executor_binder">partial_immediate_executor_binder</link></member>
|
||||
<member><link linkend="boost_asio.reference.partial_redirect_disposition">partial_redirect_disposition</link></member>
|
||||
<member><link linkend="boost_asio.reference.prepend_t">prepend_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.recycling_allocator">recycling_allocator</link></member>
|
||||
<member><link linkend="boost_asio.reference.redirect_disposition_t">redirect_disposition_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.redirect_error_t">redirect_error_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.strand">strand</link></member>
|
||||
<member><link linkend="boost_asio.reference.thread_pool__basic_executor_type">thread_pool::basic_executor_type</link></member>
|
||||
@@ -277,6 +279,7 @@
|
||||
<member><link linkend="boost_asio.reference.make_work_guard">make_work_guard</link></member>
|
||||
<member><link linkend="boost_asio.reference.post">post</link></member>
|
||||
<member><link linkend="boost_asio.reference.prepend">prepend</link></member>
|
||||
<member><link linkend="boost_asio.reference.redirect_disposition">redirect_disposition</link></member>
|
||||
<member><link linkend="boost_asio.reference.redirect_error">redirect_error</link></member>
|
||||
<member><link linkend="boost_asio.reference.spawn">spawn</link></member>
|
||||
<member><link linkend="boost_asio.reference.this_coro__reset_cancellation_state">this_coro::reset_cancellation_state</link></member>
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
#include <boost/asio/read_until.hpp>
|
||||
#include <boost/asio/readable_pipe.hpp>
|
||||
#include <boost/asio/recycling_allocator.hpp>
|
||||
#include <boost/asio/redirect_disposition.hpp>
|
||||
#include <boost/asio/redirect_error.hpp>
|
||||
#include <boost/asio/registered_buffer.hpp>
|
||||
#include <boost/asio/require.hpp>
|
||||
|
||||
455
include/boost/asio/impl/redirect_disposition.hpp
Normal file
455
include/boost/asio/impl/redirect_disposition.hpp
Normal file
@@ -0,0 +1,455 @@
|
||||
|
||||
// impl/redirect_disposition.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_IMPL_REDIRECT_DISPOSITION_HPP
|
||||
#define BOOST_ASIO_IMPL_REDIRECT_DISPOSITION_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/associator.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/detail/handler_cont_helpers.hpp>
|
||||
#include <boost/asio/detail/initiation_base.hpp>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Class to adapt a redirect_disposition_t as a completion handler.
|
||||
template <typename Disposition, typename Handler>
|
||||
class redirect_disposition_handler
|
||||
{
|
||||
public:
|
||||
typedef void result_type;
|
||||
|
||||
template <typename CompletionToken>
|
||||
redirect_disposition_handler(
|
||||
redirect_disposition_t<CompletionToken, Disposition> e)
|
||||
: d_(e.d_),
|
||||
handler_(static_cast<CompletionToken&&>(e.token_))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename RedirectedHandler>
|
||||
redirect_disposition_handler(Disposition& d, RedirectedHandler&& h)
|
||||
: d_(d),
|
||||
handler_(static_cast<RedirectedHandler&&>(h))
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
static_cast<Handler&&>(handler_)();
|
||||
}
|
||||
|
||||
template <typename Arg, typename... Args>
|
||||
enable_if_t<
|
||||
!is_same<decay_t<Arg>, Disposition>::value
|
||||
>
|
||||
operator()(Arg&& arg, Args&&... args)
|
||||
{
|
||||
static_cast<Handler&&>(handler_)(
|
||||
static_cast<Arg&&>(arg),
|
||||
static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(const Disposition& d, Args&&... args)
|
||||
{
|
||||
d_ = d;
|
||||
static_cast<Handler&&>(handler_)(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
//private:
|
||||
Disposition& d_;
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
template <typename Handler>
|
||||
class redirect_disposition_handler<std::exception_ptr, Handler>
|
||||
{
|
||||
public:
|
||||
typedef void result_type;
|
||||
|
||||
template <typename CompletionToken>
|
||||
redirect_disposition_handler(
|
||||
redirect_disposition_t<CompletionToken, std::exception_ptr> e)
|
||||
: d_(e.d_),
|
||||
handler_(static_cast<CompletionToken&&>(e.token_))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename RedirectedHandler>
|
||||
redirect_disposition_handler(std::exception_ptr& d, RedirectedHandler&& h)
|
||||
: d_(d),
|
||||
handler_(static_cast<RedirectedHandler&&>(h))
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
static_cast<Handler&&>(handler_)();
|
||||
}
|
||||
|
||||
template <typename Arg, typename... Args>
|
||||
enable_if_t<
|
||||
!is_disposition<decay_t<Arg>>::value
|
||||
>
|
||||
operator()(Arg&& arg, Args&&... args)
|
||||
{
|
||||
static_cast<Handler&&>(handler_)(
|
||||
static_cast<Arg&&>(arg),
|
||||
static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template <typename Disposition, typename... Args>
|
||||
enable_if_t<
|
||||
is_disposition<Disposition>::value
|
||||
>
|
||||
operator()(const Disposition& d, Args&&... args)
|
||||
{
|
||||
d_ = disposition_traits<Disposition>::to_exception_ptr(d);
|
||||
static_cast<Handler&&>(handler_)(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
//private:
|
||||
std::exception_ptr& d_;
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename Handler>
|
||||
inline bool asio_handler_is_continuation(
|
||||
redirect_disposition_handler<Disposition, Handler>* this_handler)
|
||||
{
|
||||
return boost_asio_handler_cont_helpers::is_continuation(
|
||||
this_handler->handler_);
|
||||
}
|
||||
|
||||
template <typename Disposition, typename Signature, typename = void>
|
||||
struct redirect_disposition_signature
|
||||
{
|
||||
typedef Signature type;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(Disposition, Args...)>
|
||||
{
|
||||
typedef R type(Args...);
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(const Disposition&, Args...)>
|
||||
{
|
||||
typedef R type(Args...);
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(Disposition, Args...) &>
|
||||
{
|
||||
typedef R type(Args...) &;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(const Disposition&, Args...) &>
|
||||
{
|
||||
typedef R type(Args...) &;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(Disposition, Args...) &&>
|
||||
{
|
||||
typedef R type(Args...) &&;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(const Disposition&, Args...) &&>
|
||||
{
|
||||
typedef R type(Args...) &&;
|
||||
};
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(Disposition, Args...) noexcept>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(const Disposition&, Args...) noexcept>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(Disposition, Args...) & noexcept>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(const Disposition&, Args...) & noexcept>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(Disposition, Args...) && noexcept>
|
||||
{
|
||||
typedef R type(Args...) && noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
Disposition, R(const Disposition&, Args...) && noexcept>
|
||||
{
|
||||
typedef R type(Args...) && noexcept;
|
||||
};
|
||||
|
||||
#endif // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(Disposition, Args...),
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...);
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(const Disposition&, Args...),
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...);
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(Disposition, Args...) &,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) &;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(const Disposition&, Args...) &,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) &;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(Disposition, Args...) &&,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) &&;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(const Disposition&, Args...) &&,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) &&;
|
||||
};
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(Disposition, Args...) noexcept,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(const Disposition&, Args...) noexcept,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(Disposition, Args...) & noexcept,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(const Disposition&, Args...) & noexcept,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(Disposition, Args...) && noexcept,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) && noexcept;
|
||||
};
|
||||
|
||||
template <typename Disposition, typename R, typename... Args>
|
||||
struct redirect_disposition_signature<
|
||||
std::exception_ptr, R(const Disposition&, Args...) && noexcept,
|
||||
enable_if_t<is_disposition<Disposition>::value>>
|
||||
{
|
||||
typedef R type(Args...) && noexcept;
|
||||
};
|
||||
|
||||
#endif // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#if !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
template <typename CompletionToken, typename Disposition, typename Signature>
|
||||
struct async_result<
|
||||
redirect_disposition_t<CompletionToken, Disposition>, Signature>
|
||||
: async_result<CompletionToken,
|
||||
typename detail::redirect_disposition_signature<
|
||||
Disposition, Signature>::type>
|
||||
{
|
||||
template <typename Initiation>
|
||||
struct init_wrapper : detail::initiation_base<Initiation>
|
||||
{
|
||||
using detail::initiation_base<Initiation>::initiation_base;
|
||||
|
||||
template <typename Handler, typename... Args>
|
||||
void operator()(Handler&& handler,
|
||||
Disposition* d, Args&&... args) &&
|
||||
{
|
||||
static_cast<Initiation&&>(*this)(
|
||||
detail::redirect_disposition_handler<Disposition, decay_t<Handler>>(
|
||||
*d, static_cast<Handler&&>(handler)),
|
||||
static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template <typename Handler, typename... Args>
|
||||
void operator()(Handler&& handler,
|
||||
Disposition* d, Args&&... args) const &
|
||||
{
|
||||
static_cast<const Initiation&>(*this)(
|
||||
detail::redirect_disposition_handler<Disposition, decay_t<Handler>>(
|
||||
*d, static_cast<Handler&&>(handler)),
|
||||
static_cast<Args&&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Initiation, typename RawCompletionToken, typename... Args>
|
||||
static auto initiate(Initiation&& initiation,
|
||||
RawCompletionToken&& token, Args&&... args)
|
||||
-> decltype(
|
||||
async_initiate<
|
||||
conditional_t<
|
||||
is_const<remove_reference_t<RawCompletionToken>>::value,
|
||||
const CompletionToken, CompletionToken>,
|
||||
typename detail::redirect_disposition_signature<
|
||||
Disposition, Signature>::type>(
|
||||
declval<init_wrapper<decay_t<Initiation>>>(),
|
||||
token.token_, &token.d_, static_cast<Args&&>(args)...))
|
||||
{
|
||||
return async_initiate<
|
||||
conditional_t<
|
||||
is_const<remove_reference_t<RawCompletionToken>>::value,
|
||||
const CompletionToken, CompletionToken>,
|
||||
typename detail::redirect_disposition_signature<
|
||||
Disposition, Signature>::type>(
|
||||
init_wrapper<decay_t<Initiation>>(
|
||||
static_cast<Initiation&&>(initiation)),
|
||||
token.token_, &token.d_, static_cast<Args&&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename> class Associator,
|
||||
typename Disposition, typename Handler, typename DefaultCandidate>
|
||||
struct associator<Associator,
|
||||
detail::redirect_disposition_handler<
|
||||
Disposition, Handler>, DefaultCandidate>
|
||||
: Associator<Handler, DefaultCandidate>
|
||||
{
|
||||
static typename Associator<Handler, DefaultCandidate>::type get(
|
||||
const detail::redirect_disposition_handler<Disposition, Handler>& h)
|
||||
noexcept
|
||||
{
|
||||
return Associator<Handler, DefaultCandidate>::get(h.handler_);
|
||||
}
|
||||
|
||||
static auto get(
|
||||
const detail::redirect_disposition_handler<Disposition, Handler>& h,
|
||||
const DefaultCandidate& c) noexcept
|
||||
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
|
||||
{
|
||||
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Disposition, typename... Signatures>
|
||||
struct async_result<partial_redirect_disposition<Disposition>, Signatures...>
|
||||
{
|
||||
template <typename Initiation, typename RawCompletionToken, typename... Args>
|
||||
static auto initiate(Initiation&& initiation,
|
||||
RawCompletionToken&& token, Args&&... args)
|
||||
-> decltype(
|
||||
async_initiate<Signatures...>(
|
||||
static_cast<Initiation&&>(initiation),
|
||||
redirect_disposition_t<
|
||||
default_completion_token_t<associated_executor_t<Initiation>>,
|
||||
Disposition>(
|
||||
default_completion_token_t<associated_executor_t<Initiation>>{},
|
||||
token.d_),
|
||||
static_cast<Args&&>(args)...))
|
||||
{
|
||||
return async_initiate<Signatures...>(
|
||||
static_cast<Initiation&&>(initiation),
|
||||
redirect_disposition_t<
|
||||
default_completion_token_t<associated_executor_t<Initiation>>,
|
||||
Disposition>(
|
||||
default_completion_token_t<associated_executor_t<Initiation>>{},
|
||||
token.d_),
|
||||
static_cast<Args&&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_IMPL_REDIRECT_DISPOSITION_HPP
|
||||
117
include/boost/asio/redirect_disposition.hpp
Normal file
117
include/boost/asio/redirect_disposition.hpp
Normal file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// redirect_disposition.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_REDIRECT_DISPOSITION_HPP
|
||||
#define BOOST_ASIO_REDIRECT_DISPOSITION_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/disposition.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
/// A @ref completion_token adapter used to specify that the disposition
|
||||
/// produced by an asynchronous operation is captured to a variable.
|
||||
/**
|
||||
* The redirect_disposition_t class is used to indicate that any disposition
|
||||
* produced by an asynchronous operation is captured to a specified variable.
|
||||
*/
|
||||
template <typename CompletionToken, BOOST_ASIO_DISPOSITION Disposition>
|
||||
class redirect_disposition_t
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
template <typename T>
|
||||
redirect_disposition_t(T&& completion_token, Disposition& d)
|
||||
: token_(static_cast<T&&>(completion_token)),
|
||||
d_(d)
|
||||
{
|
||||
}
|
||||
|
||||
//private:
|
||||
CompletionToken token_;
|
||||
Disposition& d_;
|
||||
};
|
||||
|
||||
/// A function object type that adapts a @ref completion_token to capture
|
||||
/// any disposition produced by an asynchronous operation to a variable.
|
||||
/**
|
||||
* May also be used directly as a completion token, in which case it adapts the
|
||||
* asynchronous operation's default completion token (or boost::asio::deferred
|
||||
* if no default is available).
|
||||
*/
|
||||
template <BOOST_ASIO_DISPOSITION Disposition>
|
||||
class partial_redirect_disposition
|
||||
{
|
||||
public:
|
||||
/// Constructor that specifies the variable used to capture disposition
|
||||
/// values.
|
||||
explicit partial_redirect_disposition(Disposition& d)
|
||||
: d_(d)
|
||||
{
|
||||
}
|
||||
|
||||
/// Adapt a @ref completion_token to specify that the completion handler
|
||||
/// should capture disposition values to a variable.
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_NODISCARD inline
|
||||
constexpr redirect_disposition_t<decay_t<CompletionToken>, Disposition>
|
||||
operator()(CompletionToken&& completion_token) const
|
||||
{
|
||||
return redirect_disposition_t<decay_t<CompletionToken>, Disposition>(
|
||||
static_cast<CompletionToken&&>(completion_token), d_);
|
||||
}
|
||||
|
||||
//private:
|
||||
Disposition& d_;
|
||||
};
|
||||
|
||||
/// Create a partial completion token adapter that captures disposition values
|
||||
/// to a variable.
|
||||
/**
|
||||
* @note When redirecting to a variable of type @c std::exception_ptr, other
|
||||
* disposition types will be automatically converted to @c std::exception_ptr.
|
||||
*/
|
||||
template <BOOST_ASIO_DISPOSITION Disposition>
|
||||
BOOST_ASIO_NODISCARD inline partial_redirect_disposition<Disposition>
|
||||
redirect_disposition(Disposition& d)
|
||||
{
|
||||
return partial_redirect_disposition<Disposition>(d);
|
||||
}
|
||||
|
||||
/// Adapt a @ref completion_token to capture disposition values to a variable.
|
||||
/**
|
||||
* @note When redirecting to a variable of type @c std::exception_ptr, other
|
||||
* disposition types will be automatically converted to @c std::exception_ptr.
|
||||
*/
|
||||
template <typename CompletionToken, BOOST_ASIO_DISPOSITION Disposition>
|
||||
BOOST_ASIO_NODISCARD inline
|
||||
redirect_disposition_t<decay_t<CompletionToken>, Disposition>
|
||||
redirect_disposition(CompletionToken&& completion_token, Disposition& d)
|
||||
{
|
||||
return redirect_disposition_t<decay_t<CompletionToken>, Disposition>(
|
||||
static_cast<CompletionToken&&>(completion_token), d);
|
||||
}
|
||||
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#include <boost/asio/impl/redirect_disposition.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_REDIRECT_DISPOSITION_HPP
|
||||
@@ -252,6 +252,8 @@ test-suite "asio" :
|
||||
[ link readable_pipe.cpp : $(USE_SELECT) : readable_pipe_select ]
|
||||
[ run recycling_allocator.cpp ]
|
||||
[ run recycling_allocator.cpp : : : $(USE_SELECT) : recycling_allocator_select ]
|
||||
[ link redirect_disposition.cpp ]
|
||||
[ link redirect_disposition.cpp : $(USE_SELECT) : redirect_disposition_select ]
|
||||
[ link redirect_error.cpp ]
|
||||
[ link redirect_error.cpp : $(USE_SELECT) : redirect_error_select ]
|
||||
[ link registered_buffer.cpp ]
|
||||
|
||||
443
test/redirect_disposition.cpp
Normal file
443
test/redirect_disposition.cpp
Normal file
@@ -0,0 +1,443 @@
|
||||
//
|
||||
// redirect_disposition.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/asio/redirect_disposition.hpp>
|
||||
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/deferred.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/system_timer.hpp>
|
||||
#include <boost/asio/use_future.hpp>
|
||||
#include "unit_test.hpp"
|
||||
|
||||
struct redirect_disposition_handler
|
||||
{
|
||||
int* count_;
|
||||
|
||||
explicit redirect_disposition_handler(int* c)
|
||||
: count_(c)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
++(*count_);
|
||||
}
|
||||
};
|
||||
|
||||
void redirect_disposition_test()
|
||||
{
|
||||
boost::asio::io_context io1;
|
||||
boost::asio::io_context io2;
|
||||
boost::asio::system_timer timer1(io1);
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
int count = 0;
|
||||
|
||||
timer1.expires_after(boost::asio::chrono::seconds(0));
|
||||
timer1.async_wait(
|
||||
boost::asio::redirect_disposition(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
redirect_disposition_handler(&count)), ec));
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(!ec);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
ec = boost::asio::error::would_block;
|
||||
timer1.async_wait(
|
||||
boost::asio::redirect_disposition(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::deferred), ec))(redirect_disposition_handler(&count));
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(!ec);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
ec = boost::asio::error::would_block;
|
||||
std::future<void> f = timer1.async_wait(
|
||||
boost::asio::redirect_disposition(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::use_future), ec));
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(!ec);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::ready);
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
}
|
||||
|
||||
void partial_redirect_disposition_test()
|
||||
{
|
||||
boost::asio::io_context io1;
|
||||
boost::asio::io_context io2;
|
||||
boost::asio::system_timer timer1(io1);
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
int count = 0;
|
||||
|
||||
timer1.expires_after(boost::asio::chrono::seconds(0));
|
||||
timer1.async_wait(boost::asio::redirect_disposition(ec))(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
redirect_disposition_handler(&count)));
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(!ec);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
ec = boost::asio::error::would_block;
|
||||
timer1.async_wait(boost::asio::redirect_disposition(ec))(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::deferred))(redirect_disposition_handler(&count));
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(!ec);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
ec = boost::asio::error::would_block;
|
||||
timer1.async_wait()(boost::asio::redirect_disposition(ec))(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::deferred))(redirect_disposition_handler(&count));
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(!ec);
|
||||
BOOST_ASIO_CHECK(count == 3);
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
ec = boost::asio::error::would_block;
|
||||
std::future<void> f = timer1.async_wait(boost::asio::redirect_disposition(ec))(
|
||||
boost::asio::bind_executor(io2.get_executor(), boost::asio::use_future));
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(!ec);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::ready);
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
}
|
||||
|
||||
void redirect_disposition_to_exception_ptr_test()
|
||||
{
|
||||
boost::asio::io_context io1;
|
||||
boost::asio::io_context io2;
|
||||
boost::asio::system_timer timer1(io1);
|
||||
std::exception_ptr ex = nullptr;
|
||||
int count = 0;
|
||||
|
||||
timer1.expires_after(boost::asio::chrono::seconds(100));
|
||||
timer1.async_wait(
|
||||
boost::asio::redirect_disposition(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
redirect_disposition_handler(&count)), ex));
|
||||
timer1.cancel();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex != nullptr);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
|
||||
}
|
||||
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
|
||||
ex = nullptr;
|
||||
timer1.async_wait(
|
||||
boost::asio::redirect_disposition(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::deferred), ex))(redirect_disposition_handler(&count));
|
||||
timer1.cancel();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex != nullptr);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
|
||||
}
|
||||
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
ex = nullptr;
|
||||
std::future<void> f = timer1.async_wait(
|
||||
boost::asio::redirect_disposition(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::use_future), ex));
|
||||
timer1.cancel();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex != nullptr);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::ready);
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
}
|
||||
|
||||
void partial_redirect_disposition_to_exception_ptr_test()
|
||||
{
|
||||
boost::asio::io_context io1;
|
||||
boost::asio::io_context io2;
|
||||
boost::asio::system_timer timer1(io1);
|
||||
std::exception_ptr ex = nullptr;
|
||||
int count = 0;
|
||||
|
||||
timer1.expires_after(boost::asio::chrono::seconds(100));
|
||||
timer1.async_wait(boost::asio::redirect_disposition(ex))(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
redirect_disposition_handler(&count)));
|
||||
timer1.cancel();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 0);
|
||||
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex != nullptr);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
|
||||
}
|
||||
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
|
||||
ex = nullptr;
|
||||
timer1.async_wait(boost::asio::redirect_disposition(ex))(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::deferred))(redirect_disposition_handler(&count));
|
||||
timer1.cancel();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 1);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex != nullptr);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
|
||||
}
|
||||
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
|
||||
ex = nullptr;
|
||||
timer1.async_wait()(boost::asio::redirect_disposition(ex))(
|
||||
boost::asio::bind_executor(io2.get_executor(),
|
||||
boost::asio::deferred))(redirect_disposition_handler(&count));
|
||||
timer1.cancel();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(count == 2);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex != nullptr);
|
||||
BOOST_ASIO_CHECK(count == 3);
|
||||
|
||||
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
|
||||
}
|
||||
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
ex = nullptr;
|
||||
std::future<void> f = timer1.async_wait(boost::asio::redirect_disposition(ex))(
|
||||
boost::asio::bind_executor(io2.get_executor(), boost::asio::use_future));
|
||||
timer1.cancel();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io1.restart();
|
||||
io1.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex == nullptr);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::timeout);
|
||||
|
||||
io2.restart();
|
||||
io2.run();
|
||||
|
||||
BOOST_ASIO_CHECK(ex != nullptr);
|
||||
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
|
||||
== std::future_status::ready);
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
|
||||
}
|
||||
|
||||
BOOST_ASIO_TEST_SUITE
|
||||
(
|
||||
"redirect_disposition",
|
||||
BOOST_ASIO_TEST_CASE(redirect_disposition_test)
|
||||
BOOST_ASIO_TEST_CASE(partial_redirect_disposition_test)
|
||||
BOOST_ASIO_TEST_CASE(redirect_disposition_to_exception_ptr_test)
|
||||
BOOST_ASIO_TEST_CASE(partial_redirect_disposition_to_exception_ptr_test)
|
||||
)
|
||||
Reference in New Issue
Block a user