forked from boostorg/beast
67 lines
2.9 KiB
Plaintext
67 lines
2.9 KiB
Plaintext
[/
|
|
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail 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:op_tutorial Writing a Composed Operation]
|
|
|
|
To illustrate the usage of the asynchronous helpers in the core section of
|
|
this library, we will develop a simple asynchronous composed operation called
|
|
[*echo]. This operation will read up to the first newline on a stream, and
|
|
then write the same line including the newline back on the stream.
|
|
|
|
First we define the input parameters and results, then declare our initiation
|
|
function. For our echo operation the only inputs are the stream and the
|
|
completion token. The output is the error code which is usually included in
|
|
all completion handler signatures.
|
|
|
|
[core_sample_echo_op_1]
|
|
|
|
Now that we have a declaration, we will define the body of the function. We
|
|
want to achieve the following goals: perform static type checking on the input
|
|
parameters, set up the return value as per __N3747__, and launch the composed
|
|
operation by constructing the object and invoking it.
|
|
|
|
[core_sample_echo_op_2]
|
|
|
|
The initiation function contains a few relatively simple parts. There is the
|
|
customization of the return value type, static type checking, building the
|
|
return value type using the helper, and creating and launching the composed
|
|
operation object. The [*`echo_op`] object does most of the work here, and has
|
|
a somewhat non-trivial structure. This structure is necessary to meet the
|
|
stringent requirements of composed operations (described in more detail in
|
|
the __Asio__ documentation). We will touch on these requirements without
|
|
explaining them in depth.
|
|
|
|
First we will create boilerplate which is present in all composed operations
|
|
written in this style:
|
|
|
|
[core_sample_echo_op_3]
|
|
|
|
We have the common boilerplate for a composed operation and now we just need
|
|
to implement the function call operator. Our strategy is to make our composed
|
|
object meet the requirements of a completion handler by being copyable (also
|
|
movable), and by providing the function call operator with the correct
|
|
signature. Rather than using `std::bind` or `boost::bind`, which destroys
|
|
the type information and therefore breaks the allocation and invocation
|
|
hooks, we will simply pass `std::move(*this)` as the completion handler
|
|
parameter for any operations that we initiate. For the move to work correctly,
|
|
care must be taken to ensure that no access to data members are made after the
|
|
move takes place. Here is the implementation of the function call operator for
|
|
this echo operation:
|
|
|
|
[core_sample_echo_op_4]
|
|
|
|
```
|
|
// echo_op is callable with the signature void(error_code, bytes_transferred),
|
|
// allowing `*this` to be used as both a ReadHandler and a WriteHandler.
|
|
//
|
|
```
|
|
|
|
A complete, runnable version of this example may be found in the examples
|
|
directory.
|
|
|
|
[endsect]
|