BodyReader may construct from a non-const message

fix #619
This commit is contained in:
Vinnie Falco
2017-07-07 14:32:51 -07:00
parent 0324dc371f
commit db59a92011
6 changed files with 132 additions and 12 deletions

View File

@@ -2,6 +2,7 @@ Version 76:
* Always go through write_some * Always go through write_some
* Use Boost.Config * Use Boost.Config
* BodyReader may construct from a non-const message
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -29,7 +29,7 @@ In this table:
* `a` denotes a value of type `X`. * `a` denotes a value of type `X`.
* `m` denotes a value of type `message const&` where * `m` denotes a possibly const value of type `message&` where
`std::is_same<decltype(m.body), Body::value_type>:value == true`. `std::is_same<decltype(m.body), Body::value_type>:value == true`.
* `ec` is a value of type [link beast.ref.beast__error_code `error_code&`]. * `ec` is a value of type [link beast.ref.beast__error_code `error_code&`].
@@ -51,6 +51,17 @@ In this table:
[ [
Constructible from `m`. The lifetime of `m` is guaranteed Constructible from `m`. The lifetime of `m` is guaranteed
to end no earlier than after the `X` is destroyed. to end no earlier than after the `X` is destroyed.
The constructor may optionally require that `m` is const, which
has these consequences:
* If `X` requires that `m` is a const reference, then serializers
constructed for messages with this body type will also require a
`const` reference to a message, otherwise:
* If `X` requires that `m` is a non-const reference, then serializers
constructed for messages with this body type will aso require
a non-const reference to a message.
The function will ensure that `!ec` is `true` if there was The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if there was one. no error or set to the appropriate error code if there was one.
] ]

View File

@@ -52,11 +52,20 @@ do_visit(error_code& ec, Visit& visit)
boost::get<T1>(pv_))); boost::get<T1>(pv_)));
} }
//------------------------------------------------------------------------------
template<bool isRequest, class Body, template<bool isRequest, class Body,
class Fields, class ChunkDecorator> class Fields, class ChunkDecorator>
serializer<isRequest, Body, Fields, ChunkDecorator>:: serializer<isRequest, Body, Fields, ChunkDecorator>::
serializer(message<isRequest, Body, Fields> const& m, serializer(value_type& m)
ChunkDecorator const& d) : m_(m)
{
}
template<bool isRequest, class Body,
class Fields, class ChunkDecorator>
serializer<isRequest, Body, Fields, ChunkDecorator>::
serializer(value_type& m, ChunkDecorator const& d)
: m_(m) : m_(m)
, d_(d) , d_(d)
{ {

View File

@@ -127,12 +127,34 @@ template<
class ChunkDecorator = no_chunk_decorator> class ChunkDecorator = no_chunk_decorator>
class serializer class serializer
{ {
public:
static_assert(is_body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(is_body_reader<Body>::value, static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met"); "BodyReader requirements not met");
/** The type of the message referenced by this object.
This may be const or non-const depending on the
implementation of the corresponding @b BodyReader.
*/
#if BEAST_DOXYGEN
using value_type = implementation_defined;
#else
using value_type =
typename std::conditional<
std::is_constructible<typename Body::reader,
message<isRequest, Body, Fields>&,
error_code&>::value &&
! std::is_constructible<typename Body::reader,
message<isRequest, Body, Fields> const&,
error_code&>::value,
message<isRequest, Body, Fields>,
message<isRequest, Body, Fields> const>::type;
#endif
private:
enum enum
{ {
do_construct = 0, do_construct = 0,
@@ -225,7 +247,7 @@ class serializer
boost::asio::const_buffers_1>>; // crlf boost::asio::const_buffers_1>>; // crlf
using pcb8_t = buffer_prefix_view<cb8_t const&>; using pcb8_t = buffer_prefix_view<cb8_t const&>;
message<isRequest, Body, Fields> const& m_; value_type& m_;
boost::optional<typename Fields::reader> frd_; boost::optional<typename Fields::reader> frd_;
boost::optional<reader> rd_; boost::optional<reader> rd_;
boost::variant<boost::blank, boost::variant<boost::blank,
@@ -258,14 +280,34 @@ public:
@ref next. This allows the message to be lazily created. @ref next. This allows the message to be lazily created.
For example, if the header is filled in before serialization. For example, if the header is filled in before serialization.
@param msg The message to serialize, which must remain valid @param msg A reference to the message to serialize, which must
for the lifetime of the serializer. remain valid for the lifetime of the serializer. Depending on
the type of Body used, this may or may not be a `const` reference.
@param decorator An optional decorator to use. @note This function participates in overload resolution only if
Body::reader is constructible from a `const` message reference.
*/ */
explicit explicit
serializer(message<isRequest, Body, Fields> const& msg, serializer(value_type& msg);
ChunkDecorator const& decorator = ChunkDecorator{});
/** Constructor
The implementation guarantees that the message passed on
construction will not be accessed until the first call to
@ref next. This allows the message to be lazily created.
For example, if the header is filled in before serialization.
@param msg A reference to the message to serialize, which must
remain valid for the lifetime of the serializer. Depending on
the type of Body used, this may or may not be a `const` reference.
@param decorator The decorator to use.
@note This function participates in overload resolution only if
Body::reader is constructible from a `const` message reference.
*/
explicit
serializer(value_type& msg, ChunkDecorator const& decorator);
/// Returns the serialized buffer size limit /// Returns the serialized buffer size limit
std::size_t std::size_t

View File

@@ -87,10 +87,10 @@ struct is_body_reader<T, beast::detail::void_t<
is_const_buffer_sequence< is_const_buffer_sequence<
typename T::reader::const_buffers_type>::value && typename T::reader::const_buffers_type>::value &&
std::is_constructible<typename T::reader, std::is_constructible<typename T::reader,
message<true, T, detail::fields_model> const&, message<true, T, detail::fields_model>&,
error_code&>::value && error_code&>::value &&
std::is_constructible<typename T::reader, std::is_constructible<typename T::reader,
message<false, T, detail::fields_model> const&, message<false, T, detail::fields_model>&,
error_code&>::value error_code&>::value
> {}; > {};
#endif #endif

View File

@@ -17,6 +17,63 @@ namespace http {
class serializer_test : public beast::unit_test::suite class serializer_test : public beast::unit_test::suite
{ {
public: public:
struct const_body
{
struct value_type{};
struct reader
{
using const_buffers_type =
boost::asio::const_buffers_1;
template<bool isRequest, class Fields>
reader(message<isRequest, const_body, Fields> const&,
error_code&);
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code&);
};
};
struct mutable_body
{
struct value_type{};
struct reader
{
using const_buffers_type =
boost::asio::const_buffers_1;
template<bool isRequest, class Fields>
reader(message<isRequest, mutable_body, Fields>&,
error_code&);
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code&);
};
};
BOOST_STATIC_ASSERT(std::is_const< serializer<
true, const_body>::value_type>::value);
BOOST_STATIC_ASSERT(! std::is_const<serializer<
true, mutable_body>::value_type>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
serializer<true, const_body>,
message <true, const_body>&>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
serializer<true, const_body>,
message <true, const_body> const&>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
serializer<true, mutable_body>,
message <true, mutable_body>&>::value);
BOOST_STATIC_ASSERT(! std::is_constructible<
serializer<true, mutable_body>,
message <true, mutable_body> const&>::value);
struct lambda struct lambda
{ {
std::size_t size; std::size_t size;