Exemplars are compiled code

fix #455
This commit is contained in:
Vinnie Falco
2017-06-20 20:10:47 -07:00
parent a8c2f54534
commit 67e3e801cb
11 changed files with 293 additions and 216 deletions

View File

@ -3,6 +3,7 @@ Version 64:
* Simplify buffered_read_stream composed op
* Simplify ssl teardown composed op
* Simplify websocket write_op
* Exemplars are compiled code
--------------------------------------------------------------------------------

View File

@ -82,6 +82,7 @@
[import ../example/server-framework/file_body.hpp]
[import ../example/websocket-client/websocket_client.cpp]
[import ../test/exemplars.cpp]
[import ../test/core/doc_snippets.cpp]
[import ../test/http/doc_snippets.cpp]
[import ../test/websocket/doc_snippets.cpp]

View File

@ -69,22 +69,6 @@ In this table:
[heading Exemplar]
```
struct Body
{
using value_type = implementation_defined;
/// The algorithm used for extracting buffers
class reader;
/// The algorithm used for inserting buffers
class writer;
/// Returns the body's payload size
static
std::uint64_t
size(value_type const& v);
}
```
[concept_Body]
[endsect]

View File

@ -112,78 +112,8 @@ In this table:
]
]
[note
Definitions for required [*BodyReader] member functions may
be declared inline so the generated code can become part of
the implementation.
]
[heading Exemplar]
```
struct BodyReader
{
public:
/** Controls when the implementation requests buffers.
If false, the implementation will request the first buffer
immediately and try to serialize both the header and some
or all of the body in a single buffer.
*/
using is_deferred = std::false_type;
/// The type of buffer returned by `get`.
using const_buffers_type = boost::asio::const_buffers_1;
/** Construct the reader.
@param msg The message whose body is to be retrieved.
*/
template<bool isRequest, class Body, class Headers>
explicit
BodyReader(message<isRequest, Body, Headers> const& msg);
/** Initialization.
Called once immediately after construction.
@param ec Set to the error, if any occurred.
*/
void
init(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
/** Returns the next buffer in the body.
@li If the return value is `boost::none` (unseated optional) and
`ec` does not contain an error, this indicates the end of the
body, no more buffers are present.
@li If the optional contains a value, the first element of the
pair represents a @b ConstBufferSequence containing one or
more octets of the body data. The second element indicates
whether or not there are additional octets of body data.
A value of `true` means there is more data, and that the
implementation will perform a subsequent call to `get`.
A value of `false` means there is no more body data.
@li If `ec` contains an error code, the return value is ignored.
@param ec Set to the error, if any occurred.
*/
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code& ec);
/** Called after `get` indicates there are no more buffers.
@param ec Set to the error, if any occurred.
*/
void
finish(error_code& ec);
};
```
[concept_BodyReader]
[endsect]

View File

@ -20,7 +20,7 @@ representation:
to compress it first.
* Saving body data to a file
In the table below:
In this table:
* `X` denotes a type meeting the requirements of [*BodyWriter].
@ -88,59 +88,8 @@ In the table below:
]
]
[note
Definitions for required [*BodyReader] member functions may
be declared inline so the generated code can become part of
the implementation.
]
[heading Exemplar]
```
struct BodyWriter
{
/** Construct the writer.
@param msg The message whose body is to be stored.
*/
template<bool isRequest, class Body, class Fields>
explicit
BodyWriter(message<isRequest, Body, Fields>& msg);
/** Initialization.
Called once immediately before storing any buffers.
@param content_length The content length if known, else `boost::none`.
@param ec Set to the error, if any occurred.
*/
void
init(boost::optional<std::uint64_t> content_length, error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
/** Store buffers.
This is called zero or more times with parsed body octets.
@param buffers The constant buffer sequence to store.
@param ec Set to the error, if any occurred.
*/
template<class ConstBufferSequence>
void
put(ConstBufferSequence const& buffers, error_code& ec);
/** Called when the body is complete.
@param ec Set to the error, if any occurred.
*/
void
finish(error_code& ec);
};
```
[concept_BodyWriter]
[endsect]

View File

@ -31,7 +31,7 @@ implementation strategies:
size of the character sequence. This is the implementation approach
currently offered by __multi_buffer__.
In the table below:
In this table:
* `X` denotes a dynamic buffer class.
* `a` denotes a value of type `X`.

View File

@ -127,54 +127,6 @@ In this table:
[heading Exemplar]
```
class Fields
{
protected:
/** Set or clear the method string.
@note Only called for requests.
*/
void set_method_impl(string_view s);
/** Set or clear the target string.
@note Only called for requests.
*/
void set_target_impl(string_view s);
/** Set or clear the reason string.
@note Only called for responses.
*/
void set_reason_impl(string_view s);
/** Returns the request-method string.
@note Only called for requests.
*/
string_view get_method_impl() const;
/** Returns the request-target string.
@note Only called for requests.
*/
string_view get_target_impl() const;
/** Returns the response reason-phrase string.
@note Only called for responses.
*/
string_view get_reason_impl() const;
/** Updates the payload metadata.
@param b `true` if chunked
@param n The content length if known, otherwise `boost::none`
*/
void prepare_payload_impl(bool b, boost::optional<std::uint64_t> n)
};
```
[concept_Fields]
[endsect]

View File

@ -98,30 +98,6 @@ In this table:
[heading Exemplar]
```
struct FieldsReader
{
// The type of buffers returned by `get`
using const_buffers_type = implementation-defined;
// Constructor for requests
FieldsReader(F const& f, unsigned version, verb method);
// Constructor for responses
FieldsReader(F const& f, unsigned version, unsigned status);
// Returns `true` if the payload uses the chunked Transfer-Encoding
bool
chunked();
// Returns `true` if keep-alive is indicated
bool
keep_alive();
// Returns the serialized header buffers
const_buffers_type
get();
};
```
[concept_FieldsReader]
[endsect]

View File

@ -22,6 +22,7 @@ if ((NOT "${VARIANT}" STREQUAL "coverage") AND
../extras/beast/unit_test/main.cpp
config.cpp
core.cpp
exemplars.cpp
http.cpp
version.cpp
websocket.cpp

View File

@ -13,6 +13,9 @@ compile config.cpp : <variant>coverage:<build>no
compile core.cpp : <variant>coverage:<build>no
<variant>ubasan:<build>no : ;
compile exemplars.cpp : <variant>coverage:<build>no
<variant>ubasan:<build>no : ;
compile http.cpp : <variant>coverage:<build>no
<variant>ubasan:<build>no : ;

280
test/exemplars.cpp Normal file
View File

@ -0,0 +1,280 @@
//
// 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)
//
#include <beast/core/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/type_traits.hpp>
#include <boost/optional.hpp>
#include <cstdint>
#include <utility>
namespace beast {
namespace http {
class BodyReader;
class BodyWriter;
//[concept_Body
struct Body
{
// The type of message::body when used
struct value_type;
/// The algorithm used for extracting buffers
using reader = BodyReader;
/// The algorithm used for inserting buffers
using writer = BodyWriter;
/// Returns the body's payload size
static
std::uint64_t
size(value_type const& v);
};
static_assert(is_body<Body>::value, "");
//]
struct Body_BodyReader {
struct value_type{};
//[concept_BodyReader
struct BodyReader
{
public:
/** Controls when the implementation requests buffers.
If false, the implementation will request the first buffer
immediately and try to serialize both the header and some
or all of the body in a single buffer.
*/
using is_deferred = std::false_type;
/// The type of buffer returned by `get`.
using const_buffers_type = boost::asio::const_buffers_1;
/** Construct the reader.
@param msg The message whose body is to be retrieved.
*/
template<bool isRequest, class Body, class Headers>
explicit
BodyReader(message<isRequest, Body, Headers> const& msg);
/** Initialization.
Called once immediately after construction.
@param ec Set to the error, if any occurred.
*/
void
init(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
/** Returns the next buffer in the body.
@li If the return value is `boost::none` (unseated optional) and
`ec` does not contain an error, this indicates the end of the
body, no more buffers are present.
@li If the optional contains a value, the first element of the
pair represents a @b ConstBufferSequence containing one or
more octets of the body data. The second element indicates
whether or not there are additional octets of body data.
A value of `true` means there is more data, and that the
implementation will perform a subsequent call to `get`.
A value of `false` means there is no more body data.
@li If `ec` contains an error code, the return value is ignored.
@param ec Set to the error, if any occurred.
*/
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
return boost::none; // for exposition only
}
/** Called after `get` indicates there are no more buffers.
@param ec Set to the error, if any occurred.
*/
void
finish(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
};
//]
using reader = BodyReader;
};
static_assert(is_body_reader<Body_BodyReader>::value, "");
struct Body_BodyWriter {
struct value_type{};
//[concept_BodyWriter
struct BodyWriter
{
/** Construct the writer.
@param msg The message whose body is to be stored.
*/
template<bool isRequest, class Body, class Fields>
explicit
BodyWriter(message<isRequest, Body, Fields>& msg);
/** Initialization.
Called once immediately before storing any buffers.
@param content_length The content length if known, else `boost::none`.
@param ec Set to the error, if any occurred.
*/
void
init(boost::optional<std::uint64_t> content_length, error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
/** Store buffers.
This is called zero or more times with parsed body octets.
@param buffers The constant buffer sequence to store.
@param ec Set to the error, if any occurred.
*/
template<class ConstBufferSequence>
void
put(ConstBufferSequence const& buffers, error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
/** Called when the body is complete.
@param ec Set to the error, if any occurred.
*/
void
finish(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
};
//]
using writer = BodyWriter;
};
static_assert(is_body_writer<Body_BodyWriter>::value, "");
//[concept_Fields
class Fields
{
public:
struct reader;
protected:
/** Set or clear the method string.
@note Only called for requests.
*/
void set_method_impl(string_view s);
/** Set or clear the target string.
@note Only called for requests.
*/
void set_target_impl(string_view s);
/** Set or clear the reason string.
@note Only called for responses.
*/
void set_reason_impl(string_view s);
/** Returns the request-method string.
@note Only called for requests.
*/
string_view get_method_impl() const;
/** Returns the request-target string.
@note Only called for requests.
*/
string_view get_target_impl() const;
/** Returns the response reason-phrase string.
@note Only called for responses.
*/
string_view get_reason_impl() const;
/** Updates the payload metadata.
@param b `true` if chunked
@param n The content length if known, otherwise `boost::none`
*/
void prepare_payload_impl(bool b, boost::optional<std::uint64_t> n);
};
static_assert(is_fields<Fields>::value, "");
//]
struct Fields_FieldsReader {
using F = Fields_FieldsReader;
//[concept_FieldsReader
struct FieldsReader
{
// The type of buffers returned by `get`
struct const_buffers_type;
// Constructor for requests
FieldsReader(F const& f, unsigned version, verb method);
// Constructor for responses
FieldsReader(F const& f, unsigned version, unsigned status);
// Returns `true` if the payload uses the chunked Transfer-Encoding
bool
chunked();
// Returns `true` if keep-alive is indicated
bool
keep_alive();
// Returns the serialized header buffers
const_buffers_type
get();
};
//]
};
} // http
} // beast