2016-05-18 12:30:15 -04:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef BEAST_HTTP_TYPE_CHECK_HPP
|
|
|
|
#define BEAST_HTTP_TYPE_CHECK_HPP
|
|
|
|
|
|
|
|
#include <beast/core/error.hpp>
|
2016-10-15 13:40:17 -04:00
|
|
|
#include <beast/core/detail/type_traits.hpp>
|
|
|
|
#include <beast/http/resume_context.hpp>
|
2016-05-18 12:30:15 -04:00
|
|
|
#include <boost/asio/buffer.hpp>
|
2016-10-15 13:40:17 -04:00
|
|
|
#include <boost/logic/tribool.hpp>
|
2016-05-18 12:30:15 -04:00
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace beast {
|
|
|
|
namespace http {
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
struct write_function
|
2016-05-18 12:30:15 -04:00
|
|
|
{
|
2016-10-15 13:40:17 -04:00
|
|
|
template<class ConstBufferSequence>
|
|
|
|
void
|
|
|
|
operator()(ConstBufferSequence const&);
|
2016-05-18 12:30:15 -04:00
|
|
|
};
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
template<class T, class = beast::detail::void_t<>>
|
|
|
|
struct has_value_type : std::false_type {};
|
2016-05-18 12:30:15 -04:00
|
|
|
|
|
|
|
template<class T>
|
2016-10-15 13:40:17 -04:00
|
|
|
struct has_value_type<T, beast::detail::void_t<
|
|
|
|
typename T::value_type
|
|
|
|
> > : std::true_type {};
|
|
|
|
|
|
|
|
template<class T, class = beast::detail::void_t<>>
|
|
|
|
struct has_content_length : std::false_type {};
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
struct has_content_length<T, beast::detail::void_t<decltype(
|
|
|
|
std::declval<T>().content_length()
|
|
|
|
)> > : std::true_type
|
2016-05-18 12:30:15 -04:00
|
|
|
{
|
2016-10-15 13:40:17 -04:00
|
|
|
static_assert(std::is_convertible<
|
|
|
|
decltype(std::declval<T>().content_length()),
|
|
|
|
std::uint64_t>::value,
|
|
|
|
"Writer::content_length requirements not met");
|
2016-05-18 12:30:15 -04:00
|
|
|
};
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
#if 0
|
|
|
|
template<class T, class M, class = beast::detail::void_t<>>
|
|
|
|
struct is_Writer : std::false_type {};
|
|
|
|
|
|
|
|
template<class T, class M>
|
|
|
|
struct is_Writer<T, M, beast::detail::void_t<decltype(
|
|
|
|
std::declval<T>().init(
|
|
|
|
std::declval<error_code&>())
|
|
|
|
// VFALCO This is unfortunate, we have to provide the template
|
|
|
|
// argument type because this is not a deduced context?
|
|
|
|
//
|
|
|
|
,std::declval<T>().template write<detail::write_function>(
|
|
|
|
std::declval<resume_context>(),
|
|
|
|
std::declval<error_code&>(),
|
|
|
|
std::declval<detail::write_function>())
|
|
|
|
)> > : std::integral_constant<bool,
|
|
|
|
std::is_nothrow_constructible<T, M const&>::value &&
|
|
|
|
std::is_convertible<decltype(
|
|
|
|
std::declval<T>().template write<detail::write_function>(
|
|
|
|
std::declval<resume_context>(),
|
|
|
|
std::declval<error_code&>(),
|
|
|
|
std::declval<detail::write_function>())),
|
|
|
|
boost::tribool>::value
|
|
|
|
>
|
2016-05-18 12:30:15 -04:00
|
|
|
{
|
2016-10-15 13:40:17 -04:00
|
|
|
static_assert(std::is_same<
|
|
|
|
typename M::body_type::writer, T>::value,
|
|
|
|
"Mismatched writer and message");
|
2016-05-18 12:30:15 -04:00
|
|
|
};
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
#else
|
|
|
|
|
|
|
|
template<class T, class M>
|
|
|
|
class is_Writer
|
2016-05-18 12:30:15 -04:00
|
|
|
{
|
2016-10-15 13:40:17 -04:00
|
|
|
template<class U, class R = decltype(
|
|
|
|
std::declval<U>().init(std::declval<error_code&>()),
|
|
|
|
std::true_type{})>
|
|
|
|
static R check1(int);
|
|
|
|
template<class>
|
|
|
|
static std::false_type check1(...);
|
|
|
|
using type1 = decltype(check1<T>(0));
|
|
|
|
|
|
|
|
// VFALCO This is unfortunate, we have to provide the template
|
|
|
|
// argument type because this is not a deduced context?
|
|
|
|
//
|
2016-05-18 12:30:15 -04:00
|
|
|
template<class U, class R =
|
2016-10-15 13:40:17 -04:00
|
|
|
std::is_convertible<decltype(
|
|
|
|
std::declval<U>().template write<detail::write_function>(
|
|
|
|
std::declval<resume_context>(),
|
|
|
|
std::declval<error_code&>(),
|
|
|
|
std::declval<detail::write_function>()))
|
|
|
|
, boost::tribool>>
|
|
|
|
static R check2(int);
|
2016-05-18 12:30:15 -04:00
|
|
|
template<class>
|
2016-10-15 13:40:17 -04:00
|
|
|
static std::false_type check2(...);
|
|
|
|
using type2 = decltype(check2<T>(0));
|
|
|
|
|
2016-05-18 12:30:15 -04:00
|
|
|
public:
|
2016-10-15 13:40:17 -04:00
|
|
|
static_assert(std::is_same<
|
|
|
|
typename M::body_type::writer, T>::value,
|
|
|
|
"Mismatched writer and message");
|
2016-05-18 12:30:15 -04:00
|
|
|
|
|
|
|
using type = std::integral_constant<bool,
|
2016-10-15 13:40:17 -04:00
|
|
|
std::is_nothrow_constructible<T, M const&>::value
|
|
|
|
&& type1::value
|
|
|
|
&& type2::value
|
2016-05-18 12:30:15 -04:00
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
#endif
|
|
|
|
|
2016-05-18 12:30:15 -04:00
|
|
|
template<class T>
|
|
|
|
class is_Parser
|
|
|
|
{
|
|
|
|
template<class U, class R =
|
|
|
|
std::is_convertible<decltype(
|
|
|
|
std::declval<U>().complete()),
|
|
|
|
bool>>
|
|
|
|
static R check1(int);
|
|
|
|
template<class>
|
|
|
|
static std::false_type check1(...);
|
|
|
|
using type1 = decltype(check1<T>(0));
|
|
|
|
|
|
|
|
template<class U, class R =
|
|
|
|
std::is_convertible<decltype(
|
|
|
|
std::declval<U>().write(
|
2016-09-25 11:19:51 -04:00
|
|
|
std::declval<boost::asio::const_buffers_1 const&>(),
|
2016-05-18 12:30:15 -04:00
|
|
|
std::declval<error_code&>())),
|
|
|
|
std::size_t>>
|
|
|
|
static R check2(int);
|
|
|
|
template<class>
|
|
|
|
static std::false_type check2(...);
|
|
|
|
using type2 = decltype(check2<T>(0));
|
|
|
|
|
|
|
|
template<class U, class R = decltype(
|
|
|
|
std::declval<U>().write_eof(std::declval<error_code&>()),
|
|
|
|
std::true_type{})>
|
|
|
|
static R check3(int);
|
|
|
|
template<class>
|
|
|
|
static std::false_type check3(...);
|
|
|
|
using type3 = decltype(check3<T>(0));
|
|
|
|
|
|
|
|
public:
|
|
|
|
using type = std::integral_constant<bool,
|
|
|
|
type1::value &&
|
|
|
|
type2::value &&
|
|
|
|
type3::value
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // detail
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
/// Determine if `T` meets the requirements of @b Body.
|
2016-05-18 12:30:15 -04:00
|
|
|
template<class T>
|
|
|
|
#if GENERATING_DOCS
|
|
|
|
struct is_Body : std::integral_constant<bool, ...>{};
|
|
|
|
#else
|
2016-10-15 13:40:17 -04:00
|
|
|
using is_Body = detail::has_value_type<T>;
|
2016-05-18 12:30:15 -04:00
|
|
|
#endif
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
/** Determine if a @ref Body has a nested type `reader`.
|
|
|
|
|
|
|
|
@tparam T The type to check, which must meet the
|
|
|
|
requirements of @b Body.
|
|
|
|
*/
|
2016-05-18 12:30:15 -04:00
|
|
|
#if GENERATING_DOCS
|
2016-10-15 13:40:17 -04:00
|
|
|
template<class T>
|
|
|
|
struct has_reader : std::integral_constant<bool, ...>{};
|
2016-05-18 12:30:15 -04:00
|
|
|
#else
|
2016-10-15 13:40:17 -04:00
|
|
|
template<class T, class = beast::detail::void_t<>>
|
|
|
|
struct has_reader : std::false_type {};
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
struct has_reader<T, beast::detail::void_t<
|
|
|
|
typename T::reader
|
|
|
|
> > : std::true_type {};
|
2016-05-18 12:30:15 -04:00
|
|
|
#endif
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
/** Determine if a @ref Body has a nested type `writer`.
|
|
|
|
|
|
|
|
@tparam T The type to check, which must meet the
|
|
|
|
requirements of @b Body.
|
|
|
|
*/
|
|
|
|
#if GENERATING_DOCS
|
|
|
|
template<class T>
|
|
|
|
struct has_writer : std::integral_constant<bool, ...>{};
|
|
|
|
#else
|
|
|
|
template<class T, class = beast::detail::void_t<>>
|
|
|
|
struct has_writer : std::false_type {};
|
|
|
|
|
2016-05-18 12:30:15 -04:00
|
|
|
template<class T>
|
2016-10-15 13:40:17 -04:00
|
|
|
struct has_writer<T, beast::detail::void_t<
|
|
|
|
typename T::writer
|
|
|
|
> > : std::true_type {};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Determine if `T` meets the requirements of @b Reader for `M`.
|
|
|
|
|
|
|
|
@tparam T The type to test.
|
|
|
|
|
|
|
|
@tparam M The message type to test with, which must be of
|
|
|
|
type `message`.
|
|
|
|
*/
|
|
|
|
#if GENERATING_DOCS
|
|
|
|
template<class T, class M>
|
|
|
|
struct is_Reader : std::integral_constant<bool, ...> {};
|
|
|
|
#else
|
|
|
|
template<class T, class M, class = beast::detail::void_t<>>
|
|
|
|
struct is_Reader : std::false_type {};
|
|
|
|
|
|
|
|
template<class T, class M>
|
|
|
|
struct is_Reader<T, M, beast::detail::void_t<decltype(
|
|
|
|
std::declval<T>().init(
|
|
|
|
std::declval<error_code&>()),
|
|
|
|
std::declval<T>().write(
|
|
|
|
std::declval<void const*>(),
|
|
|
|
std::declval<std::size_t>(),
|
|
|
|
std::declval<error_code&>())
|
|
|
|
)> > : std::integral_constant<bool,
|
|
|
|
std::is_nothrow_constructible<T, M&>::value
|
|
|
|
>
|
|
|
|
{
|
|
|
|
static_assert(std::is_same<
|
|
|
|
typename M::body_type::reader, T>::value,
|
|
|
|
"Mismatched reader and message");
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Determine if `T` meets the requirements of @b Writer for `M`.
|
|
|
|
|
|
|
|
@tparam T The type to test.
|
|
|
|
|
|
|
|
@tparam M The message type to test with, which must be of
|
|
|
|
type `message`.
|
|
|
|
*/
|
|
|
|
template<class T, class M>
|
2016-05-18 12:30:15 -04:00
|
|
|
#if GENERATING_DOCS
|
2016-10-15 13:40:17 -04:00
|
|
|
struct is_Writer : std::integral_constant<bool, ...> {};
|
2016-05-18 12:30:15 -04:00
|
|
|
#else
|
2016-10-15 13:40:17 -04:00
|
|
|
using is_Writer = typename detail::is_Writer<T, M>::type;
|
2016-05-18 12:30:15 -04:00
|
|
|
#endif
|
|
|
|
|
2016-10-15 13:40:17 -04:00
|
|
|
/// Determine if `T` meets the requirements of @b Parser.
|
2016-05-18 12:30:15 -04:00
|
|
|
template<class T>
|
|
|
|
#if GENERATING_DOCS
|
|
|
|
struct is_Parser : std::integral_constant<bool, ...>{};
|
|
|
|
#else
|
|
|
|
using is_Parser = typename detail::is_Parser<T>::type;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // http
|
|
|
|
} // beast
|
|
|
|
|
|
|
|
#endif
|