123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- //
- // 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 =
- typename std::decay<decltype(std::declval<T&>().get_executor())>::type;
- #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
|