244 lines
7.8 KiB
Plaintext
244 lines
7.8 KiB
Plaintext
[/
|
|
/ Copyright (c) 2003-2023 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)
|
|
/]
|
|
|
|
[section:token_adapters Completion Token Adapters]
|
|
|
|
A ['completion token adapter] is a utility that can be generically applied to a
|
|
[link boost_asio.overview.model.completion_tokens completion token], to produce a new
|
|
completion token with modified behaviour. Common uses of completion token
|
|
adapters include:
|
|
|
|
* Automatically wrapping the completion handler to add [link
|
|
boost_asio.overview.model.associators associated characteristics].
|
|
|
|
* Transforming the completion signature and arguments passed to the completion
|
|
handler.
|
|
|
|
Boost.Asio includes a number of completion token adapters as described below.
|
|
|
|
[heading bind_executor, bind_allocator, and bind_cancellation_slot]
|
|
|
|
The [link boost_asio.reference.bind_executor `bind_executor`] function adapts a
|
|
completion token to imbue the completion handler with an [link
|
|
boost_asio.overview.model.executors associated executor].
|
|
|
|
This example shows the `bind_executor` adapter applied to a lambda, to specify
|
|
that the handler should execute in the specified strand. The arguments to the
|
|
completion handler are passed through as-is.
|
|
|
|
my_socket.async_read_some(my_buffer,
|
|
boost::asio::bind_executor(my_strand,
|
|
[](boost::system::error_code error, std::size_t bytes_transferred)
|
|
{
|
|
// ...
|
|
}));
|
|
|
|
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.
|
|
|
|
boost::asio::awaitable<void> my_coroutine()
|
|
{
|
|
// ...
|
|
std::size_t bytes_transferred =
|
|
co_await my_socket.async_read_some(my_buffer,
|
|
boost::asio::bind_executor(my_strand, boost::asio::use_awaitable));
|
|
// ...
|
|
}
|
|
|
|
The [link boost_asio.reference.bind_allocator `bind_allocator`] and [link
|
|
boost_asio.reference.bind_cancellation_slot `bind_cancellation_slot`] adapters work
|
|
similarly, to imbue the completion handler with an [link
|
|
boost_asio.overview.model.allocators associated allocator] or [link
|
|
boost_asio.overview.model.cancellation associated cancellation slot] respectively.
|
|
|
|
[heading redirect_error]
|
|
|
|
The [link boost_asio.reference.redirect_error `redirect_error`] function adapts a
|
|
completion token to capture the `error_code` produced by an operation into a
|
|
specified variable. In doing so, it modifies the completion signature to remove
|
|
the initial `error_code` parameter.
|
|
|
|
This example shows the `redirect_error` adapter applied to a lambda, to specify
|
|
that the error should be captured into `my_error`. The `error_code` is no
|
|
longer passed to the completion handler, but the remaining arguments are passed
|
|
through as-is.
|
|
|
|
boost::system::error_code my_error; // N.B. must be valid until operation completes
|
|
// ...
|
|
my_socket.async_read_some(my_buffer,
|
|
boost::asio::redirect_error(
|
|
[](std::size_t bytes_transferred)
|
|
{
|
|
// ...
|
|
}, my_error));
|
|
|
|
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()
|
|
{
|
|
// ...
|
|
boost::system::error_code my_error;
|
|
std::size_t bytes_transferred =
|
|
co_await my_socket.async_read_some(my_buffer,
|
|
boost::asio::redirect_error(boost::asio::use_awaitable, my_error));
|
|
// ...
|
|
}
|
|
|
|
[heading as_tuple]
|
|
|
|
The [link boost_asio.reference.as_tuple `as_tuple`] adapter can be used to specify
|
|
that the completion handler arguments should be combined into a single tuple
|
|
argument.
|
|
|
|
For example, the `as_tuple` adapter may be used in conjunction with [link
|
|
boost_asio.reference.use_awaitable `use_awaitable`] and structured bindings as
|
|
follows:
|
|
|
|
auto [e, n] =
|
|
co_await my_socket.async_read_some(my_buffer,
|
|
boost::asio::as_tuple(boost::asio::use_awaitable));
|
|
|
|
This adapter may also be used as a default completion token:
|
|
|
|
using default_token = boost::asio::as_tuple_t<boost::asio::use_awaitable_t<>>;
|
|
using tcp_socket = default_token::as_default_on_t<tcp::socket>;
|
|
// ...
|
|
boost::asio::awaitable<void> do_read(tcp_socket my_socket)
|
|
{
|
|
// ...
|
|
auto [e, n] = co_await my_socket.async_read_some(my_buffer);
|
|
// ...
|
|
}
|
|
|
|
[heading as_single]
|
|
|
|
[note This is an experimental feature.]
|
|
|
|
The [link boost_asio.reference.experimental__as_single `experimental::as_single`]
|
|
adapter can be used to specify that the completion handler
|
|
arguments should be combined into a single argument. For completion signatures
|
|
with a single parameter, the argument is passed through as-is. For signatures
|
|
with two or more parameters, the arguments are combined into a tuple.
|
|
|
|
For example, when applied to a timer wait operation, the single `error_code`
|
|
argument is passed directly to the completion handler:
|
|
|
|
my_timer.async_wait(
|
|
boost::asio::experimental::as_single(
|
|
[](boost::system::error_code error)
|
|
{
|
|
// ...
|
|
}));
|
|
|
|
When applied to a socket read operation, where the completion signature
|
|
specifies two parameters, the handler is passed the result as a tuple:
|
|
|
|
my_socket.async_read_some(my_buffer,
|
|
boost::asio::experimental::as_single,
|
|
[](std::tuple<boost::system::error_code, std::size_t> result)
|
|
{
|
|
// ...
|
|
}));
|
|
|
|
[heading append]
|
|
|
|
The [link boost_asio.reference.append `append`] completion token adapter can be
|
|
used to pass additional completion handler arguments at the end of the
|
|
completion signature.
|
|
|
|
For example:
|
|
|
|
timer.async_wait(
|
|
boost::asio::append(
|
|
[](boost::system::error_code ec, int i)
|
|
{
|
|
// ...
|
|
},
|
|
42
|
|
)
|
|
);
|
|
|
|
std::future<int> f = timer.async_wait(
|
|
boost::asio::append(
|
|
boost::asio::use_future,
|
|
42
|
|
)
|
|
);
|
|
|
|
[heading prepend]
|
|
|
|
The [link boost_asio.reference.prepend `prepend`] completion token adapter can be
|
|
used to pass additional completion handler arguments before the existing
|
|
completion handler arguments.
|
|
|
|
For example:
|
|
|
|
timer.async_wait(
|
|
boost::asio::prepend(
|
|
[](int i, boost::system::error_code ec)
|
|
{
|
|
// ...
|
|
},
|
|
42
|
|
)
|
|
);
|
|
|
|
std::future<std::tuple<int, boost::system::error_code>> f = timer.async_wait(
|
|
boost::asio::prepend(
|
|
boost::asio::use_future,
|
|
42
|
|
)
|
|
);
|
|
|
|
[heading consign]
|
|
|
|
The [link boost_asio.reference.consign `consign`] completion token adapter can be
|
|
used to attach additional values to a completion handler. This is typically used
|
|
to keep at least one copy of an object, such as a smart pointer, alive until the
|
|
completion handler is called.
|
|
|
|
For example:
|
|
|
|
auto timer1 = std::make_shared<boost::asio::steady_timer>(my_io_context);
|
|
timer1->expires_after(std::chrono::seconds(1));
|
|
timer1->async_wait(
|
|
boost::asio::consign(
|
|
[](boost::system::error_code ec)
|
|
{
|
|
// ...
|
|
},
|
|
timer1
|
|
)
|
|
);
|
|
|
|
auto timer2 = std::make_shared<boost::asio::steady_timer>(my_io_context);
|
|
timer2->expires_after(std::chrono::seconds(30));
|
|
std::future<void> f =
|
|
timer2->async_wait(
|
|
boost::asio::consign(
|
|
boost::asio::use_future,
|
|
timer2
|
|
)
|
|
);
|
|
|
|
[heading See Also]
|
|
|
|
[link boost_asio.reference.bind_executor bind_executor],
|
|
[link boost_asio.reference.bind_allocator bind_allocator],
|
|
[link boost_asio.reference.bind_cancellation_slot bind_cancellation_slot],
|
|
[link boost_asio.reference.redirect_error redirect_error],
|
|
[link boost_asio.reference.as_tuple as_tuple],
|
|
[link boost_asio.reference.experimental__as_single experimental::as_single],
|
|
[link boost_asio.reference.append append],
|
|
[link boost_asio.reference.prepend prepend].
|
|
|
|
[endsect]
|