Stream traits are in stream_traits.hpp (API Change):

These metafunctions are moved from type_traits.hpp
to stream_traits.hpp:

- has_get_executor
- is_sync_stream
- is_sync_read_stream
- is_sync_write_stream
- is_async_stream
- is_async_read_stream
- is_async_write_stream

Actions Required:

* Include the file stream_traits.hpp as needed
This commit is contained in:
Vinnie Falco
2019-02-05 07:40:30 -08:00
parent 9cee4e053f
commit 477cd75153
12 changed files with 553 additions and 476 deletions

View File

@ -6,6 +6,14 @@ Version 210:
* Add stream_traits.hpp
* Add executor_type trait
API Changes:
* Stream traits are now in stream_traits.hpp
Actions Required:
* Include the file stream_traits.hpp as needed
--------------------------------------------------------------------------------
Version 209:

View File

@ -32,21 +32,31 @@ New websocket-chat-multi example
[/* `BASIC_TIMEOUT_STREAM` TODO]
* ([issue 1305]) Better `flat_buffer`, `flat_static_buffer`, `multi_buffer`, and `static_buffer`:
* ([issue 1305]) Better
`flat_buffer`,
`flat_static_buffer`,
`multi_buffer`, and
`static_buffer`:
* Revise all reference documentation
* Move construction does not always invalidate buffers
* non-const `data()` returns a mutable buffer sequence
* Add `cdata()` to also return constant readable bytes
* Eligible member functions are declared `noexcept`
* ([issue 1345]) Better `flat_buffer`, `multi_buffer`
* ([issue 1345]) Better
`flat_buffer`,
`multi_buffer`
* Add `clear`, `reserve()`, `max_size()`, `shrink_to_fit()`
* Respect Allocator `max_size()`
* Specify exception safety
* ([issue 1384]) New functions `bind_back_handler`, `bind_front_handler`
* ([issue 1384]) New functions
`bind_back_handler`,
`bind_front_handler`
* Better `static_buffer`, `flat_static_buffer`
* Better
`static_buffer`,
`flat_static_buffer`
* Add `clear()`
* More members are `noexcept`
* Specify exception safety
@ -56,23 +66,32 @@ New websocket-chat-multi example
* New file <boost/beast/core/buffer_traits.hpp>
* New variadic `is_const_buffer_sequence`
* New variadic `is_mutable_buffer_sequence`
* New `buffers_iterator_type` trait
* New `buffers_type` trait
* New trait `buffers_iterator_type`
* New trait `buffers_type`
* New classes `async_op_base` and `stable_async_op_base`
* New classes
`async_op_base`,
`stable_async_op_base`
* Handle boilerplate for writing composed operations
* New `allocate_stable` is preferred over `handler_ptr`
* New
`allocate_stable`
is preferred over `handler_ptr`
* New `buffer_size` replacement for `net::buffer_size`
* New
`buffer_size`
replacement for `net::buffer_size`
* New:
* `saved_handler`
* `buffers_range_ref`
* `dynamic_buffer_ref`
* `executor_type`
* `get_lowest_layer` and `lowest_layer_type`
* `close_socket` and `beast_close_socket`
* `error` and `condition`
* `get_lowest_layer`,
`lowest_layer_type`
* `close_socket`,
`beast_close_socket`
* `error`,
`condition`
[*API Changes]
@ -80,38 +99,64 @@ New websocket-chat-multi example
from the stream. Previously, they returned the number of bytes
consumed by the parser.
['Actions Required]:
* Callers depending on the return value of `http::read` or
`http::async_read` overloads should adjust the usage of
* Callers depending on the return value of
`http::read` or
`http::async_read`
overloads should adjust the usage of
the returned value as needed.
* `flat_static_buffer::reset()` is deprecated.
['Actions Required]:
* call `clear()` instead.
* Metafunctions
`has_get_executor`,
`is_sync_stream`,
`is_sync_read_stream`,
`is_sync_write_stream`,
`is_async_stream`,
`is_async_read_stream`, and
`is_async_write_stream`
are now located in stream_traits.hpp.
['Actions Required]: Include stream_traits.hpp as needed.
* `buffers_adapter` is now called `buffers_adaptor`.
* `flat_static_buffer::reset()`
is deprecated.
['Actions Required]:
* Replace `buffers_adapter` with `buffers_adaptor`, or define
`BOOST_BEAST_ALLOW_DEPRECATED`.
* call
`clear()` instead.
* `buffers` is now called `make_printable`.
* `buffers_adapter` is now spelled
`buffers_adaptor`.
['Actions Required]:
* Replace `buffers` with `make_printable`, and include
"make_printable.hpp" instead of "ostream.hpp".
* Replace `buffers_adapter` with
`buffers_adaptor`,
or define `BOOST_BEAST_ALLOW_DEPRECATED`.
* `buffers` is now spelled
`make_printable`.
['Actions Required]:
* Replace `buffers` with
`make_printable`,
and include "make_printable.hpp" instead of "ostream.hpp".
* `file_mode::append_new` is removed, as it makes no sense.
['Actions Required]:
- Replace `file_mode::append_new` with either `file_mode::append`
or `file_mode::append_existing` as needed.
- Replace `file_mode::append_new` with either
`file_mode::append` or
`file_mode::append_existing`
as needed.
* `buffers_range_ref` is preferred to `std::reference_wrapper`.
* `buffers_range_ref`
is preferred to `std::reference_wrapper`.
['Actions Required]:
- Call `buffers_range_ref` with the buffer, instead of calling
`buffers_range` with a reference wrapper constructed from
the buffer.
- Call
`buffers_range_ref`
with the buffer, instead of calling
`buffers_range`
with a reference wrapper constructed from the buffer.
* Nested `lowest_layer` and `lowest_layer_type` are removed.
['Actions Required]: Use the free function `get_lowest_layer` and the
type trait `lowest_layer_type` instead.
['Actions Required]: Use the free function
`get_lowest_layer` and the
type trait
`lowest_layer_type` instead.
[*Examples]
@ -119,9 +164,10 @@ New websocket-chat-multi example
* ([issue 1347]) Improve echo-op
* ([issue 1401]) Examples use `flat_buffer`
* ([issue 1401]) Examples use
`flat_buffer`
* New websocket-chat-multi example
* New example [[source_file example/websocket/server/chat-multi]]
* `async_echo` works with move-only handlers
@ -129,33 +175,42 @@ New websocket-chat-multi example
* ([issue 1223]) HTTP read counts bytes correctly when an error occurs
* ([issue 1247]) Update `ssl_stream` for Asio changes
* ([issue 1247]) Update `ssl_stream`
for Asio changes
* ([issue 1279]) Enable explicit instantiations of `websocket::stream`
* ([issue 1279]) Enable explicit instantiations of
`websocket::stream`
* ([issue 1290]) Don't use deprecated Asio interfaces
* ([issue 1306]) `http::message` is not-a `boost::empty_value`
* ([issue 1306]) `http::message`
is not-a `boost::empty_value`
* ([issue 1306]) `test::stream` has fewer dependencies
* ([issue 1306]) `test::stream`
has fewer dependencies
* ([issue 1365]) Handler wrappers decay parameters sooner
* ([issue 1408]) `session_alloc` is thread-safe
* ([issue 1408]) `session_alloc`
is thread-safe
* ([issue 1414]) Boost.System is header-only
* ([issue 1418]) `test::stream` maintains a handler work guard
* ([issue 1418]) `test::stream`
maintains a handler work guard
* `buffers_cat` correctly skips empty buffers when iterated
* `buffers_cat`
correctly skips empty buffers when iterated
* `ostream` does not overflow or exceed the dynamic buffer's maximum size
* `ostream`
does not overflow or exceed the dynamic buffer's maximum size
* A handler work guard is maintained on paused websocket operations
* All behavior of default-constructed iterators is conforming
* `file_mode::append_existing` works correctly
* `file_mode::append_existing`
works correctly
[/-----------------------------------------------------------------------------]

View File

@ -14,7 +14,7 @@
#include <boost/beast/core/detail/static_const.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/type_traits.hpp>
#include <boost/type_traits/make_void.hpp>
#include <type_traits>
namespace boost {

View File

@ -13,7 +13,6 @@
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/async_op_base.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/throw_exception.hpp>

View File

@ -12,7 +12,7 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <cstdlib>

View File

@ -10,6 +10,8 @@
#ifndef BOOST_BEAST_DETAIL_STREAM_TRAITS_HPP
#define BOOST_BEAST_DETAIL_STREAM_TRAITS_HPP
#include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/type_traits/make_void.hpp>
#include <type_traits>
@ -25,13 +27,11 @@ namespace detail {
//
template <class T>
std::false_type has_next_layer_impl(void*) {}
std::false_type has_next_layer_impl(void*);
template <class T>
auto has_next_layer_impl(decltype(nullptr)) ->
decltype(std::declval<T&>().next_layer(), std::true_type{})
{
}
decltype(std::declval<T&>().next_layer(), std::true_type{});
template <class T>
using has_next_layer = decltype(has_next_layer_impl<T>(nullptr));
@ -73,6 +73,37 @@ get_lowest_layer_impl(
//------------------------------------------------------------------------------
// Types that meet the requirements,
// for use with std::declval only.
template<class BufferType>
struct BufferSequence
{
using value_type = BufferType;
using const_iterator = BufferType const*;
~BufferSequence();
BufferSequence(BufferSequence const&) = default;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
using ConstBufferSequence =
BufferSequence<net::const_buffer>;
using MutableBufferSequence =
BufferSequence<net::mutable_buffer>;
//
// Types that meet the requirements,
// for use with std::declval only.
struct StreamHandler
{
StreamHandler(StreamHandler const&) = default;
void operator()(error_code ec, std::size_t);
};
using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
//------------------------------------------------------------------------------
} // detail
} // beast
} // boost

View File

@ -13,7 +13,7 @@
#include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/mp11/function.hpp>
#include <boost/type_traits.hpp>
#include <boost/type_traits/make_void.hpp>
#include <iterator>
#include <tuple>
#include <type_traits>
@ -161,39 +161,6 @@ struct is_contiguous_container<T, E, void_t<
//------------------------------------------------------------------------------
//
// buffer concepts
//
// Types that meet the requirements,
// for use with std::declval only.
template<class BufferType>
struct BufferSequence
{
using value_type = BufferType;
using const_iterator = BufferType const*;
~BufferSequence();
BufferSequence(BufferSequence const&) = default;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
using ConstBufferSequence =
BufferSequence<net::const_buffer>;
using MutableBufferSequence =
BufferSequence<net::mutable_buffer>;
//
// Types that meet the requirements,
// for use with std::declval only.
struct StreamHandler
{
StreamHandler(StreamHandler const&) = default;
void operator()(error_code ec, std::size_t);
};
using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
/* If this static assert goes off, it means that the completion
handler you provided to an asynchronous initiating function did
not have the right signature. Check the parameter types for your

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
// Copyright (c) 2019 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)
@ -87,6 +87,8 @@ get_lowest_layer(T& t) noexcept
t, detail::has_next_layer<T>{});
}
//------------------------------------------------------------------------------
/** A trait to determine the return type of get_executor.
This type alias will be the type of values returned by
@ -110,6 +112,318 @@ using executor_type =
decltype(std::declval<T&>().get_executor());
#endif
/** Determine if `T` has the `get_executor` member function.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` has the member
function with the correct signature, else type will be `std::false_type`.
@par Example
Use with tag dispatching:
@code
template<class T>
void maybe_hello(T const& t, std::true_type)
{
net::post(
t.get_executor(),
[]
{
std::cout << "Hello, world!" << std::endl;
});
}
template<class T>
void maybe_hello(T const&, std::false_type)
{
// T does not have get_executor
}
template<class T>
void maybe_hello(T const& t)
{
maybe_hello(t, has_get_executor<T>{});
}
@endcode
Use with `static_assert`:
@code
struct stream
{
using executor_type = net::io_context::executor_type;
executor_type get_executor() noexcept;
};
static_assert(has_get_executor<stream>::value, "Missing get_executor member");
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct has_get_executor : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct has_get_executor : std::false_type {};
template<class T>
struct has_get_executor<T, boost::void_t<decltype(
std::declval<T&>().get_executor())>> : std::true_type {};
#endif
//------------------------------------------------------------------------------
/** Determine if `T` meets the requirements of @b SyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_read_stream : std::false_type {};
template<class T>
struct is_sync_read_stream<T, boost::void_t<decltype(
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>()),
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b SyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_write_stream : std::false_type {};
template<class T>
struct is_sync_write_stream<T, boost::void_t<decltype(
(
std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>()))
,std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b SyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncStream>
void f(SyncStream& stream)
{
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncStream>
typename std::enable_if<is_sync_stream<SyncStream>::value>::type
f(SyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_sync_stream = std::integral_constant<bool,
is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
#endif
//------------------------------------------------------------------------------
/** Determine if `T` meets the requirements of @b AsyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncReadStream>
void f(AsyncReadStream& stream)
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncReadStream>
typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
f(AsyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_read_stream : std::false_type {};
template<class T>
struct is_async_read_stream<T, boost::void_t<decltype(
std::declval<T>().async_read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<detail::ReadHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b AsyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncWriteStream>
void f(AsyncWriteStream& stream)
{
static_assert(is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncWriteStream>
typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
f(AsyncWriteStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_write_stream : std::false_type {};
template<class T>
struct is_async_write_stream<T, boost::void_t<decltype(
std::declval<T>().async_write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<detail::WriteHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b AsyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncStream>
void f(AsyncStream& stream)
{
static_assert(is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncStream>
typename std::enable_if<is_async_stream<AsyncStream>::value>::type
f(AsyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_async_stream = std::integral_constant<bool,
is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
#endif
} // beast
} // boost

View File

@ -56,320 +56,6 @@ using is_completion_handler = std::integral_constant<bool,
detail::is_invocable<T, Signature>::value>;
#endif
//------------------------------------------------------------------------------
//
// Stream concepts
//
//------------------------------------------------------------------------------
/** Determine if `T` has the `get_executor` member function.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` has the member
function with the correct signature, else type will be `std::false_type`.
@par Example
Use with tag dispatching:
@code
template<class T>
void maybe_hello(T& t, std::true_type)
{
net::post(
t.get_executor(),
[]
{
std::cout << "Hello, world!" << std::endl;
});
}
template<class T>
void maybe_hello(T&, std::false_type)
{
// T does not have get_executor
}
template<class T>
void maybe_hello(T& t)
{
maybe_hello(t, has_get_executor<T>{});
}
@endcode
Use with `static_assert`:
@code
struct stream
{
using executor_type = net::io_context::executor_type;
executor_type get_executor() noexcept;
};
static_assert(has_get_executor<stream>::value, "Missing get_executor member");
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct has_get_executor : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct has_get_executor : std::false_type {};
template<class T>
struct has_get_executor<T, beast::detail::void_t<decltype(
std::declval<T&>().get_executor())>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b AsyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncReadStream>
void f(AsyncReadStream& stream)
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncReadStream>
typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
f(AsyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_read_stream : std::false_type {};
template<class T>
struct is_async_read_stream<T, detail::void_t<decltype(
std::declval<T>().async_read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<detail::ReadHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b AsyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncWriteStream>
void f(AsyncWriteStream& stream)
{
static_assert(is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncWriteStream>
typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
f(AsyncWriteStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_async_write_stream : std::false_type {};
template<class T>
struct is_async_write_stream<T, detail::void_t<decltype(
std::declval<T>().async_write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<detail::WriteHandler>())
)>> : std::integral_constant<bool,
has_get_executor<T>::value
> {};
#endif
/** Determine if `T` meets the requirements of @b SyncReadStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_read_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_read_stream : std::false_type {};
template<class T>
struct is_sync_read_stream<T, detail::void_t<decltype(
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>()),
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b SyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncReadStream>
void f(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncReadStream>
typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
f(SyncReadStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_write_stream : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_sync_write_stream : std::false_type {};
template<class T>
struct is_sync_write_stream<T, detail::void_t<decltype(
(
std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>()))
,std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<boost::system::error_code&>())
)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b AsyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class AsyncStream>
void f(AsyncStream& stream)
{
static_assert(is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class AsyncStream>
typename std::enable_if<is_async_stream<AsyncStream>::value>::type
f(AsyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_async_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_async_stream = std::integral_constant<bool,
is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
#endif
/** Determine if `T` meets the requirements of @b SyncStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class SyncStream>
void f(SyncStream& stream)
{
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class SyncStream>
typename std::enable_if<is_sync_stream<SyncStream>::value>::type
f(SyncStream& stream);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_sync_stream : std::integral_constant<bool, ...>{};
#else
template<class T>
using is_sync_stream = std::integral_constant<bool,
is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
#endif
//------------------------------------------------------------------------------
//
// File concepts

View File

@ -12,7 +12,7 @@
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/use_future.hpp>

View File

@ -13,6 +13,7 @@
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/io_context.hpp>
namespace boost {
namespace beast {
@ -161,7 +162,7 @@ public:
};
void
testJavadoc()
testGetLowestLayerJavadoc()
{
write_stream<without> s;
BOOST_STATIC_ASSERT(
@ -178,11 +179,102 @@ public:
//--------------------------------------------------------------------------
void
testExecutorType()
{
}
void
testExecutorTypeJavadoc()
{
}
//--------------------------------------------------------------------------
struct sync_read_stream
{
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const&);
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const&,
error_code& ec);
};
struct sync_write_stream
{
template<class ConstBufferSequence>
std::size_t
write_some(ConstBufferSequence const&);
template<class ConstBufferSequence>
std::size_t
write_some(
ConstBufferSequence const&, error_code&);
};
struct async_read_stream
{
net::io_context::executor_type
get_executor();
template<class MutableBufferSequence, class ReadHandler>
void
async_read_some(
MutableBufferSequence const&, ReadHandler&&);
};
struct async_write_stream
{
net::io_context::executor_type
get_executor();
template<class ConstBufferSequence, class WriteHandler>
void
async_write_some(
ConstBufferSequence const&, WriteHandler&&);
};
struct sync_stream : sync_read_stream, sync_write_stream
{
};
struct async_stream : async_read_stream, async_write_stream
{
using async_read_stream::get_executor;
};
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_sync_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<async_read_stream>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<async_write_stream>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<async_stream>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<async_stream>::value);
BOOST_STATIC_ASSERT(is_async_stream<async_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_read_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_write_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(! is_async_read_stream<async_write_stream>::value);
BOOST_STATIC_ASSERT(! is_async_write_stream<async_read_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_stream<async_stream>::value);
BOOST_STATIC_ASSERT(! is_async_stream<sync_stream>::value);
//--------------------------------------------------------------------------
void
run() override
{
testGetLowestLayer();
testJavadoc();
testGetLowestLayerJavadoc();
testExecutorType();
testExecutorTypeJavadoc();
}
};

View File

@ -79,80 +79,5 @@ struct H
BOOST_STATIC_ASSERT(is_completion_handler<H, void(int)>::value);
BOOST_STATIC_ASSERT(! is_completion_handler<H, void(void)>::value);
//
// stream concepts
//
struct sync_write_stream
{
net::io_context&
get_io_service();
template<class ConstBufferSequence>
std::size_t
write_some(ConstBufferSequence const& buffers);
template<class ConstBufferSequence>
std::size_t
write_some(
ConstBufferSequence const& buffers, error_code& ec);
};
struct sync_read_stream
{
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const& buffers);
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const& buffers,
error_code& ec);
};
struct sync_stream : sync_read_stream, sync_write_stream
{
};
BOOST_STATIC_ASSERT(! is_sync_read_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_write_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<sync_stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<sync_stream>::value);
namespace {
using stream_type = net::ip::tcp::socket;
struct not_a_stream
{
void
get_io_service();
};
BOOST_STATIC_ASSERT(has_get_executor<stream_type>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_async_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<stream_type>::value);
BOOST_STATIC_ASSERT(is_sync_stream<stream_type>::value);
BOOST_STATIC_ASSERT(! has_get_executor<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_async_read_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_async_write_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_read_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(! is_sync_write_stream<not_a_stream>::value);
BOOST_STATIC_ASSERT(is_sync_read_stream<test::stream>::value);
BOOST_STATIC_ASSERT(is_sync_write_stream<test::stream>::value);
BOOST_STATIC_ASSERT(is_async_read_stream<test::stream>::value);
BOOST_STATIC_ASSERT(is_async_write_stream<test::stream>::value);
} // (anonymous)
} // beast
} // boost