summaryrefslogtreecommitdiff
path: root/boost/beast/core/stream_traits.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/core/stream_traits.hpp')
-rw-r--r--boost/beast/core/stream_traits.hpp544
1 files changed, 544 insertions, 0 deletions
diff --git a/boost/beast/core/stream_traits.hpp b/boost/beast/core/stream_traits.hpp
new file mode 100644
index 0000000000..f1945ea93a
--- /dev/null
+++ b/boost/beast/core/stream_traits.hpp
@@ -0,0 +1,544 @@
+//
+// Copyright (c) 2016-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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_STREAM_TRAITS_HPP
+#define BOOST_BEAST_STREAM_TRAITS_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/static_const.hpp>
+#include <boost/beast/core/detail/stream_traits.hpp>
+#include <boost/asio/basic_socket.hpp>
+
+namespace boost {
+namespace beast {
+
+/** A trait to determine the lowest layer type of a stack of stream layers.
+
+ If `t.next_layer()` is well-defined for an object `t` of type `T`,
+ then `lowest_layer_type<T>` will be an alias for
+ `lowest_layer_type<decltype(t.next_layer())>`,
+ otherwise it will be the type
+ `std::remove_reference<T>`.
+
+ @param T The type to determine the lowest layer type of.
+
+ @return The type of the lowest layer.
+*/
+template<class T>
+#if BOOST_BEAST_DOXYGEN
+using lowest_layer_type = __see_below__;
+#else
+using lowest_layer_type = detail::lowest_layer_type<T>;
+#endif
+
+/** Return the lowest layer in a stack of stream layers.
+
+ If `t.next_layer()` is well-defined, returns
+ `get_lowest_layer(t.next_layer())`. Otherwise, it returns `t`.
+
+ A stream layer is an object of class type which wraps another object through
+ composition, and meets some or all of the named requirements of the wrapped
+ type while optionally changing behavior. Examples of stream layers include
+ `net::ssl::stream` or @ref beast::websocket::stream. The owner of a stream
+ layer can interact directly with the wrapper, by passing it to stream
+ algorithms. Or, the owner can obtain a reference to the wrapped object by
+ calling `next_layer()` and accessing its members. This is necessary when it is
+ desired to access functionality in the next layer which is not available
+ in the wrapper. For example, @ref websocket::stream permits reading and
+ writing, but in order to establish the underlying connection, members
+ of the wrapped stream (such as `connect`) must be invoked directly.
+
+ Usually the last object in the chain of composition is the concrete socket
+ object (for example, a `net::basic_socket` or a class derived from it).
+ The function @ref get_lowest_layer exists to easily obtain the concrete
+ socket when it is desired to perform an action that is not prescribed by
+ a named requirement, such as changing a socket option, cancelling all
+ pending asynchronous I/O, or closing the socket (perhaps by using
+ @ref close_socket).
+
+ @par Example
+ @code
+ // Set non-blocking mode on a stack of stream
+ // layers with a regular socket at the lowest layer.
+ template <class Stream>
+ void set_non_blocking (Stream& stream)
+ {
+ error_code ec;
+ // A compile error here means your lowest layer is not the right type!
+ get_lowest_layer(stream).non_blocking(true, ec);
+ if(ec)
+ throw system_error{ec};
+ }
+ @endcode
+
+ @param t The layer in a stack of layered objects for which the lowest layer is returned.
+
+ @see close_socket, lowest_layer_type
+*/
+template<class T>
+lowest_layer_type<T>&
+get_lowest_layer(T& t) noexcept
+{
+ return detail::get_lowest_layer_impl(
+ 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
+ by calling member `get_exector` on an object of type `T&`.
+
+ @param T The type to query
+
+ @return The type of values returned from `get_executor`.
+*/
+// Workaround for ICE on gcc 4.8
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using executor_type = __see_below__;
+#elif BOOST_WORKAROUND(BOOST_GCC, < 40900)
+template<class T>
+using executor_type =
+ typename std::decay<T>::type::executor_type;
+#else
+template<class T>
+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>
+using has_get_executor = __see_below__;
+#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 at type meets the requirements of <em>SyncReadStream</em>.
+
+ 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 type 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>
+using is_sync_read_stream = __see_below__;
+#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 <em>SyncWriteStream</em>.
+
+ 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 type 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>
+using is_sync_write_stream = __see_below__;
+#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 type 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>
+using is_sync_stream = __see_below__;
+#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 <em>AsyncReadStream</em>.
+
+ 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 type 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>
+using is_async_read_stream = __see_below__;
+#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 <em>AsyncWriteStream</em>.
+
+ 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 type 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>
+using is_async_write_stream = __see_below__;
+#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 type 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>
+using is_async_stream = __see_below__;
+#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
+
+//------------------------------------------------------------------------------
+
+/** Default socket close function.
+
+ This function is not meant to be called directly. Instead, it
+ is called automatically when using @ref close_socket. To enable
+ closure of user-defined types or classes derived from a particular
+ user-defined type, this function should be overloaded in the
+ corresponding namespace for the type in question.
+
+ @see close_socket
+*/
+template<
+ class Protocol,
+ class Executor>
+void
+beast_close_socket(
+ net::basic_socket<
+ Protocol, Executor>& sock)
+{
+ boost::system::error_code ec;
+ sock.close(ec);
+}
+
+namespace detail {
+
+struct close_socket_impl
+{
+ template<class T>
+ void
+ operator()(T& t) const
+ {
+ using beast::beast_close_socket;
+ beast_close_socket(t);
+ }
+};
+
+} // detail
+
+/** Close a socket or socket-like object.
+
+ This function attempts to close an object representing a socket.
+ In this context, a socket is an object for which an unqualified
+ call to the function `void beast_close_socket(Socket&)` is
+ well-defined. The function `beast_close_socket` is a
+ <em>customization point</em>, allowing user-defined types to
+ provide an algorithm for performing the close operation by
+ overloading this function for the type in question.
+
+ Since the customization point is a function call, the normal
+ rules for finding the correct overload are applied including
+ the rules for argument-dependent lookup ("ADL"). This permits
+ classes derived from a type for which a customization is provided
+ to inherit the customization point.
+
+ An overload for the networking class template `net::basic_socket`
+ is provided, which implements the close algorithm for all socket-like
+ objects (hence the name of this customization point). When used
+ in conjunction with @ref get_lowest_layer, a generic algorithm
+ operating on a layered stream can perform a closure of the underlying
+ socket without knowing the exact list of concrete types.
+
+ @par Example 1
+ The following generic function synchronously sends a message
+ on the stream, then closes the socket.
+ @code
+ template <class WriteStream>
+ void hello_and_close (WriteStream& stream)
+ {
+ net::write(stream, net::const_buffer("Hello, world!", 13));
+ close_socket(get_lowest_layer(stream));
+ }
+ @endcode
+
+ To enable closure of user defined types, it is necessary to provide
+ an overload of the function `beast_close_socket` for the type.
+
+ @par Example 2
+ The following code declares a user-defined type which contains a
+ private socket, and provides an overload of the customization
+ point which closes the private socket.
+ @code
+ class my_socket
+ {
+ net::ip::tcp::socket sock_;
+
+ public:
+ my_socket(net::io_context& ioc)
+ : sock_(ioc)
+ {
+ }
+
+ friend void beast_close_socket(my_socket& s)
+ {
+ error_code ec;
+ s.sock_.close(ec);
+ // ignore the error
+ }
+ };
+ @endcode
+
+ @param sock The socket to close. If the customization point is not
+ defined for the type of this object, or one of its base classes,
+ then a compiler error results.
+
+ @see beast_close_socket
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class Socket>
+void
+close_socket(Socket& sock);
+#else
+BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)
+#endif
+
+} // beast
+} // boost
+
+#endif