From 5613ce7e971161858e09c0698e28a7b3553cb8f4 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Mon, 19 Jun 2017 18:16:02 -0700 Subject: [PATCH] Add http::is_fields trait fix #515 --- CHANGELOG.md | 1 + doc/concept/Fields.qbk | 7 +++ doc/quickref.xml | 1 + include/beast/http/detail/type_traits.hpp | 72 +++++++++++++++++++++++ include/beast/http/message.hpp | 6 ++ include/beast/http/type_traits.hpp | 33 +++++++++++ test/http/fields.cpp | 3 + test/http/type_traits.cpp | 8 +++ 8 files changed, 131 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b22fe7d3..f7d61604 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Version 62: * Tidy up namespaces in examples * Clear the error faster * Avoid explicit operator bool for error +* Add http::is_fields trait API Changes: diff --git a/doc/concept/Fields.qbk b/doc/concept/Fields.qbk index b97afa9d..6f946a89 100644 --- a/doc/concept/Fields.qbk +++ b/doc/concept/Fields.qbk @@ -115,6 +115,13 @@ In this table: Transfer-Encoding field if the field is present ahd chunked is the last encoding. ] +][ + [`is_fields`] + [`std::true_type`] + [ + An alias for `std::true_type` for `X`, otherwise an alias + for `std::false_type`. + ] ] ] diff --git a/doc/quickref.xml b/doc/quickref.xml index 5a59fab2..eb08b6e7 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -96,6 +96,7 @@ is_body is_body_writer is_body_reader + is_fields Concepts diff --git a/include/beast/http/detail/type_traits.hpp b/include/beast/http/detail/type_traits.hpp index ea2e2284..05a72679 100644 --- a/include/beast/http/detail/type_traits.hpp +++ b/include/beast/http/detail/type_traits.hpp @@ -9,6 +9,8 @@ #define BEAST_HTTP_DETAIL_TYPE_TRAITS_HPP #include +#include +#include namespace beast { namespace http { @@ -49,6 +51,15 @@ struct fields_model string_view method() const; string_view reason() const; string_view target() const; + +protected: + void set_method_impl(string_view s); + void set_target_impl(string_view s); + void set_reason_impl(string_view s); + string_view get_method_impl() const; + string_view get_target_impl() const; + string_view get_reason_impl() const; + void prepare_payload_impl(bool b, boost::optional n); }; template> @@ -75,6 +86,67 @@ struct is_body_sized()), (void)0)>> : std::true_type {}; +template +struct is_fields_helper : T +{ + template + static auto f1(int) -> decltype( + void(std::declval().set_method_impl(std::declval())), + std::true_type()); + static auto f1(...) -> std::false_type; + using t1 = decltype(f1(0)); + + template + static auto f2(int) -> decltype( + void(std::declval().set_target_impl(std::declval())), + std::true_type()); + static auto f2(...) -> std::false_type; + using t2 = decltype(f2(0)); + + template + static auto f3(int) -> decltype( + void(std::declval().set_reason_impl(std::declval())), + std::true_type()); + static auto f3(...) -> std::false_type; + using t3 = decltype(f3(0)); + + template + static auto f4(int) -> decltype( + std::declval() = std::declval().get_method_impl(), + std::true_type()); + static auto f4(...) -> std::false_type; + using t4 = decltype(f4(0)); + + template + static auto f5(int) -> decltype( + std::declval() = std::declval().get_target_impl(), + std::true_type()); + static auto f5(...) -> std::false_type; + using t5 = decltype(f5(0)); + + template + static auto f6(int) -> decltype( + std::declval() = std::declval().get_reason_impl(), + std::true_type()); + static auto f6(...) -> std::false_type; + using t6 = decltype(f6(0)); + + template + static auto f7(int) -> decltype( + void(std::declval().prepare_payload_impl( + std::declval(), + std::declval>())), + std::true_type()); + static auto f7(...) -> std::false_type; + using t7 = decltype(f7(0)); + + using type = std::integral_constant; +}; + } // detail } // http } // beast diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp index f0e821c7..01b84298 100644 --- a/include/beast/http/message.hpp +++ b/include/beast/http/message.hpp @@ -48,6 +48,9 @@ template struct header : Fields #endif { + static_assert(is_fields::value, + "Fields requirements not met"); + /// Indicates if the header is a request or response. #if BEAST_DOXYGEN using is_request = isRequest; @@ -196,6 +199,9 @@ private: template struct header : Fields { + static_assert(is_fields::value, + "Fields requirements not met"); + /// Indicates if the header is a request or response. using is_request = std::false_type; diff --git a/include/beast/http/type_traits.hpp b/include/beast/http/type_traits.hpp index 9f31b157..97ca0a5c 100644 --- a/include/beast/http/type_traits.hpp +++ b/include/beast/http/type_traits.hpp @@ -137,6 +137,39 @@ struct is_body_writer + void f(message const&) + { + static_assert(is_fields::value, + "Fields requirements not met"); + ... + @endcode + + Use with `std::enable_if` (SFINAE): + + @code + template + typename std::enable_if::value>::type + f(message const&); + @endcode +*/ +#if BEAST_DOXYGEN +template +struct is_fields : std::integral_constant {}; +#else +template +using is_fields = typename detail::is_fields_helper::type; +#endif + } // http } // beast diff --git a/test/http/fields.cpp b/test/http/fields.cpp index c0b9f55b..d8b7e654 100644 --- a/test/http/fields.cpp +++ b/test/http/fields.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,8 @@ namespace beast { namespace http { +BOOST_STATIC_ASSERT(is_fields::value); + class fields_test : public beast::unit_test::suite { public: diff --git a/test/http/type_traits.cpp b/test/http/type_traits.cpp index 978d5a7e..a461c5b0 100644 --- a/test/http/type_traits.cpp +++ b/test/http/type_traits.cpp @@ -20,5 +20,13 @@ BOOST_STATIC_ASSERT(is_body_reader::value); BOOST_STATIC_ASSERT(! is_body_writer::value); +namespace { + +struct not_fields {}; + +} // (anonymous) + +BOOST_STATIC_ASSERT(! is_fields::value); + } // http } // beast