[/
    Copyright (c) 2013-2016 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:Writer Writer]

A `Writer` serializes the message body. The implementation creates an instance
of this type when serializing a message, and calls into it zero or more times
to provide buffers containing the data. The interface of `Writer` is intended
to allow serialization in these scenarios:

* A body that does not entirely fit in memory.
* A body produced incrementally from coroutine output.
* A body represented by zero or more buffers already in memory.
* A body as a series of buffers when the content size is not known ahead of time.
* Body data generated on demand from other threads.
* Body data computed algorithmically.

In this table:

* `X`  denotes a type meeting the requirements of `Writer`.

* `a`  denotes a value of type `X`.

* `m`  denotes a value of type `message const&` where
        `std::is_same<decltype(m.body), Body::value_type>:value == true`.

* `rc` is an object of type [link beast.ref.http__resume_context resume_context].

* `ec` is a value of type `error_code&`.

* `wf` is a [*write function]: a function object of unspecified type provided
       by the implementation which accepts any value meeting the requirements
       of `ConstBufferSequence` as its single parameter.

[table Writer requirements
[[operation] [type] [semantics, pre/post-conditions]]
[
    [`X a(m);`]
    []
    [
        `a` is constructible from `m`. The lifetime of `m` is
        guaranteed to end no earlier than after `a` is destroyed.
    ]
]
[
    [`a.init(ec)`]
    [`void`]
    [
        Called immediately after construction.
        If `ec` is set, the serialization is aborted and the error
        is propagated to the caller.
    ]
]
[
    [`a.content_length()`]
    [`std::uint64_t`]
    [
        If this member is present, it is called after initialization
        and before calls to provide buffers. The serialized message will
        have the Content-Length field set to the value returned from
        this function. If this member is absent, the serialized message
        body will be chunk-encoded for HTTP versions 1.1 and later, else
        the serialized message body will be sent unmodified, with the
        error `boost::asio::error::eof` returned to the caller, to notify
        they should close the connection to indicate the end of the message.
    ]
]
[
    [`a(rc, ec, wf)`]
    [`boost::tribool`]
    [
        Called repeatedly after `init` succeeds.
        `wf` is a function object which takes as its single parameter,
        any value meeting the requirements of `ConstBufferSequence`.
        Buffers provided by the `writer` to this [*write function] must
        remain valid until the next member function of `writer` is
        invoked (which may be the destructor). This function returns `true`
        to indicate all message body data has been written, or `false`
        if there is more body data. If the return value is
        `boost::indeterminate`, the implementation will suspend the operation
        until the writer invokes `rc`. It is the writers responsibility when
        returning `boost::indeterminate`, to acquire ownership of the
        `resume_context` via move construction and eventually call it or else
        undefined behavior results.
    ]
]
]

[note Definitions for required `Writer` member functions should be declared
inline so the generated code becomes part of the implementation. ]

Exemplar:
```
struct writer
{
public:
    /** Construct the writer.

        The msg object is guaranteed to exist for the lifetime of the writer.

        Exceptions:
            No-throw guarantee.

        @param msg The message whose body is to be written.
    */
    template<bool isRequest, class Body, class Headers>
    explicit
    writer(message<isRequest, Body, Headers> const& msg);

    /** Initialize the writer.

        Called once immediately after construction.
        The writer can perform initialization which may fail.

        @param ec Contains the error code if any errors occur.
    */
    void
    init(error_code& ec);

    /** Returns the content length.

        If this member is present, the implementation will set the
        Content-Length field accordingly. If absent, the implementation will
        use chunk-encoding or terminate the connection to indicate the end
        of the message.
    */
    std::size_t
    content_length() const;

    /** Write zero or one buffer representing the message body.

        Postconditions:

            If return value is `true`:
                * Callee does not take ownership of resume.
                * Callee made zero or one calls to `write`.
                * There is no more data remaining to write.

            If return value is `false`:
                * Callee does not take ownership of resume.
                * Callee made one call to `write`.

            If return value is boost::indeterminate:
                * Callee takes ownership of `resume`.
                * Caller suspends the write operation
                  until `resume` is invoked.

        When the caller takes ownership of resume, the
        asynchronous operation will not complete until the
        caller destroys the object.

        @param resume A functor to call to resume the write operation
        after the writer has returned boost::indeterminate.

        @param ec Set to indicate an error. This will cause an
        asynchronous write operation to complete with the error.

        @param write A functor the writer will call to provide the next
        set of buffers. Ownership of the buffers is not transferred,
        the writer must guarantee that the buffers remain valid until the
        next member function is invoked, which may be the destructor.

        @return `true` if there is data, `false` when done,
                boost::indeterminate to suspend.

        @note Undefined behavior if the callee takes ownership
              of resume but does not return boost::indeterminate.
    */
    template<class WriteFunction>
    boost::tribool
    operator()(resume_context&&, error_code&, WriteFunction&& write);
};
```

[endsect]
