[/
    Copyright (c) 2016-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)

    Official repository: https://github.com/boostorg/beast
]

[section Writing Composed Operations]
[block'''<?dbhtml stop-chunking?>''']

Asynchronous operations are started by calling a free function or member
function known as an asynchronous ['__async_initfn__]. This function accepts
parameters specific to the operation as well as a "completion token." The
token is either a completion handler, or a type defining how the caller is
informed of the asynchronous operation result. __Asio__ comes with the
special tokens __use_future__ and __yield_context__ for using futures
and coroutines respectively. This system of customizing the return value
and method of completion notification is known as the
['Extensible Asynchronous Model] described in __N3747__, and a built in
to __NetTS__. Here is an example of an initiating function which reads a
line from the stream and echoes it back. This function is developed
further in the next section:

[example_core_echo_op_1]

Authors using Beast can reuse the library's primitives to create their
own initiating functions for performing a series of other, intermediate
asynchronous operations before invoking a final completion handler.
The set of intermediate actions produced by an initiating function is
known as a
[@http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.html ['composed operation]].
To ensure full interoperability and well-defined behavior, __Asio__ imposes
requirements on the implementation of composed operations. These classes
and functions make it easier to develop initiating functions and their
composed operations:

[table Asynchronous Helpers
[[Name][Description]]
[[
    [link beast.ref.boost__beast__bind_handler `bind_handler`]
][
    This function creates a new handler which, when invoked, calls
    the original handler with the list of bound arguments. Any
    parameters passed in the invocation will be substituted for
    placeholders present in the list of bound arguments. Parameters
    which are not matched to placeholders are silently discarded.

    The passed handler and arguments are forwarded into the returned
    handler, whose associated allocator and associated executor will
    will be the same as those of the original handler.
]]
[[
    [link beast.ref.boost__beast__handler_ptr `handler_ptr`]
][
    This is a smart pointer container used to manage the internal state of a
    composed operation. It is useful when the state is non trivial. For example
    when the state has non-movable or contains expensive to move types. The
    container takes ownership of the final completion handler, and provides
    boilerplate to invoke the final handler in a way that also deletes the
    internal state. The internal state is allocated using the final completion
    handler's associated allocator, benefiting from all handler memory
    management optimizations transparently.
]]
]



[section Echo]

This example develops an initiating function called [*echo].
The operation will read up to the first newline on a stream, and
then write the same line including the newline back on the stream.
The implementation performs both reading and writing, and has a
non-trivially-copyable state.
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.

[example_core_echo_op_2]

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.

[example_core_echo_op_3]

The initiating 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.

Here is the boilerplate present in all composed operations written
in this style:

[example_core_echo_op_4]

Next is to implement the function call operator. Our strategy is to make our
composed object meet the requirements of a completion handler by being 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:

[example_core_echo_op_5]

This is the most important element of writing a composed operation, and
the part which is often neglected or implemented incorrectly. It is the
forwarding of the final handler's associated allocator and associated
executor to the composed operation.

Our composed operation stores the final handler and performs its own
intermediate asynchronous operations. To ensure that I/O objects, in this
case the stream, are accessed safely it is important to use the same
executor to invoke intermediate handlers as that used to invoke the final
handler. Similarly, for memory allocations our composed operation should
use the allocator associated with the final handler.

There are some common mistakes that should be avoided when writing
composed operations:

* Type erasing the final handler. This will cause undefined behavior.

* Forgetting to include a return statement after calling an
  initiating function.

* Calling a synchronous function by accident. In general composed
  operations should not block for long periods of time, since this
  ties up a thread running on the __io_context__.

* Forgetting to provide `executor_type` and `get_executor` for the
  composed operation. This will cause undefined behavior. For example,
  if someone  calls the initiating function with a strand-wrapped
  function object, and there is more than thread running on the
  __io_context__, the underlying stream may be accessed in a fashion
  that violates safety guarantees.

* Forgetting to create an object of type __executor_work_guard__ with the
  type of executor returned by the stream's `get_executor` member function.

* For operations which complete immediately (i.e. without calling an
  intermediate initiating function), forgetting to use __post__ to
  invoke the final handler. This breaks the following initiating
  function guarantee: ['Regardless of whether the asynchronous operation
  completes immediately or not, the handler will not be invoked from
  within this function. Invocation of the handler will be performed
  in a manner equivalent to using __post__]. The function
  __bind_handler__ is provided for this purpose.

A complete, runnable version of this example may be found in the examples
directory.

[endsect]



[endsect]
