Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:28

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_STREAM_TRAITS_HPP
0011 #define BOOST_BEAST_STREAM_TRAITS_HPP
0012 
0013 #include <boost/beast/core/detail/config.hpp>
0014 #include <boost/beast/core/detail/static_const.hpp>
0015 #include <boost/beast/core/detail/stream_traits.hpp>
0016 #include <boost/asio/basic_socket.hpp>
0017 
0018 namespace boost {
0019 namespace beast {
0020 
0021 /** A trait to determine the lowest layer type of a stack of stream layers.
0022 
0023     If `t.next_layer()` is well-defined for an object `t` of type `T`,
0024     then `lowest_layer_type<T>` will be an alias for
0025     `lowest_layer_type<decltype(t.next_layer())>`,
0026     otherwise it will be the type
0027     `std::remove_reference<T>`.
0028 
0029     @param T The type to determine the lowest layer type of.
0030 
0031     @return The type of the lowest layer.
0032 */
0033 template<class T>
0034 #if BOOST_BEAST_DOXYGEN
0035 using lowest_layer_type = __see_below__;
0036 #else
0037 using lowest_layer_type = detail::lowest_layer_type<T>;
0038 #endif
0039 
0040 /** Return the lowest layer in a stack of stream layers.
0041 
0042     If `t.next_layer()` is well-defined, returns
0043     `get_lowest_layer(t.next_layer())`. Otherwise, it returns `t`.
0044 
0045     A stream layer is an object of class type which wraps another object through
0046     composition, and meets some or all of the named requirements of the wrapped
0047     type while optionally changing behavior. Examples of stream layers include
0048     `net::ssl::stream` or @ref beast::websocket::stream. The owner of a stream
0049     layer can interact directly with the wrapper, by passing it to stream
0050     algorithms. Or, the owner can obtain a reference to the wrapped object by
0051     calling `next_layer()` and accessing its members. This is necessary when it is
0052     desired to access functionality in the next layer which is not available
0053     in the wrapper. For example, @ref websocket::stream permits reading and
0054     writing, but in order to establish the underlying connection, members
0055     of the wrapped stream (such as `connect`) must be invoked directly.
0056 
0057     Usually the last object in the chain of composition is the concrete socket
0058     object (for example, a `net::basic_socket` or a class derived from it).
0059     The function @ref get_lowest_layer exists to easily obtain the concrete
0060     socket when it is desired to perform an action that is not prescribed by
0061     a named requirement, such as changing a socket option, cancelling all
0062     pending asynchronous I/O, or closing the socket (perhaps by using
0063     @ref close_socket).
0064 
0065     @par Example
0066     @code
0067     // Set non-blocking mode on a stack of stream
0068     // layers with a regular socket at the lowest layer.
0069     template <class Stream>
0070     void set_non_blocking (Stream& stream)
0071     {
0072         error_code ec;
0073         // A compile error here means your lowest layer is not the right type!
0074         get_lowest_layer(stream).non_blocking(true, ec);
0075         if(ec)
0076             throw system_error{ec};
0077     }
0078     @endcode
0079 
0080     @param t The layer in a stack of layered objects for which the lowest layer is returned.
0081 
0082     @see close_socket, lowest_layer_type
0083 */
0084 template<class T>
0085 lowest_layer_type<T>&
0086 get_lowest_layer(T& t) noexcept
0087 {
0088     return detail::get_lowest_layer_impl(
0089         t, detail::has_next_layer<T>{});
0090 }
0091 
0092 //------------------------------------------------------------------------------
0093 
0094 /** A trait to determine the return type of get_executor.
0095 
0096     This type alias will be the type of values returned by
0097     by calling member `get_exector` on an object of type `T&`.
0098 
0099     @param T The type to query
0100 
0101     @return The type of values returned from `get_executor`.
0102 */
0103 // Workaround for ICE on gcc 4.8
0104 #if BOOST_BEAST_DOXYGEN
0105 template<class T>
0106 using executor_type = __see_below__;
0107 #elif BOOST_WORKAROUND(BOOST_GCC, < 40900)
0108 template<class T>
0109 using executor_type =
0110     typename std::decay<T>::type::executor_type;
0111 #else
0112 template<class T>
0113 using executor_type =
0114     typename std::decay<decltype(std::declval<T&>().get_executor())>::type;
0115 #endif
0116 
0117 /** Determine if `T` has the `get_executor` member function.
0118 
0119     Metafunctions are used to perform compile time checking of template
0120     types. This type will be `std::true_type` if `T` has the member
0121     function with the correct signature, else type will be `std::false_type`. 
0122 
0123     @par Example
0124 
0125     Use with tag dispatching:
0126 
0127     @code
0128     template<class T>
0129     void maybe_hello(T const& t, std::true_type)
0130     {
0131         net::post(
0132             t.get_executor(),
0133             []
0134             {
0135                 std::cout << "Hello, world!" << std::endl;
0136             });
0137     }
0138 
0139     template<class T>
0140     void maybe_hello(T const&, std::false_type)
0141     {
0142         // T does not have get_executor
0143     }
0144 
0145     template<class T>
0146     void maybe_hello(T const& t)
0147     {
0148         maybe_hello(t, has_get_executor<T>{});
0149     }
0150     @endcode
0151 
0152     Use with `static_assert`:
0153 
0154     @code
0155     struct stream
0156     {
0157         using executor_type = net::io_context::executor_type;
0158         executor_type get_executor() noexcept;
0159     };
0160 
0161     static_assert(has_get_executor<stream>::value, "Missing get_executor member");
0162     @endcode
0163 */
0164 #if BOOST_BEAST_DOXYGEN
0165 template<class T>
0166 using has_get_executor = __see_below__;
0167 #else
0168 template<class T, class = void>
0169 struct has_get_executor : std::false_type {};
0170 
0171 template<class T>
0172 struct has_get_executor<T, boost::void_t<decltype(
0173     std::declval<T&>().get_executor())>> : std::true_type {};
0174 #endif
0175 
0176 //------------------------------------------------------------------------------
0177 
0178 /** Determine if at type meets the requirements of <em>SyncReadStream</em>.
0179 
0180     Metafunctions are used to perform compile time checking of template
0181     types. This type will be `std::true_type` if `T` meets the requirements,
0182     else the type will be `std::false_type`. 
0183 
0184     @par Example
0185     Use with `static_assert`:
0186     @code
0187     template<class SyncReadStream>
0188     void f(SyncReadStream& stream)
0189     {
0190         static_assert(is_sync_read_stream<SyncReadStream>::value,
0191             "SyncReadStream type requirements not met");
0192     ...
0193     @endcode
0194 
0195     Use with `std::enable_if` (SFINAE):
0196     @code
0197     template<class SyncReadStream>
0198     typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
0199     f(SyncReadStream& stream);
0200     @endcode
0201 */
0202 #if BOOST_BEAST_DOXYGEN
0203 template<class T>
0204 using is_sync_read_stream = __see_below__;
0205 #else
0206 template<class T, class = void>
0207 struct is_sync_read_stream : std::false_type {};
0208 
0209 template<class T>
0210 struct is_sync_read_stream<T, boost::void_t<decltype(
0211     std::declval<std::size_t&>() = std::declval<T&>().read_some(
0212         std::declval<detail::MutableBufferSequence>()),
0213     std::declval<std::size_t&>() = std::declval<T&>().read_some(
0214         std::declval<detail::MutableBufferSequence>(),
0215         std::declval<boost::system::error_code&>())
0216             )>> : std::true_type {};
0217 #endif
0218 
0219 /** Determine if `T` meets the requirements of <em>SyncWriteStream</em>.
0220 
0221     Metafunctions are used to perform compile time checking of template
0222     types. This type will be `std::true_type` if `T` meets the requirements,
0223     else the type will be `std::false_type`. 
0224 
0225     @par Example
0226 
0227     Use with `static_assert`:
0228 
0229     @code
0230     template<class SyncReadStream>
0231     void f(SyncReadStream& stream)
0232     {
0233         static_assert(is_sync_read_stream<SyncReadStream>::value,
0234             "SyncReadStream type requirements not met");
0235     ...
0236     @endcode
0237 
0238     Use with `std::enable_if` (SFINAE):
0239 
0240     @code
0241     template<class SyncReadStream>
0242     typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
0243     f(SyncReadStream& stream);
0244     @endcode
0245 */
0246 #if BOOST_BEAST_DOXYGEN
0247 template<class T>
0248 using is_sync_write_stream = __see_below__;
0249 #else
0250 template<class T, class = void>
0251 struct is_sync_write_stream : std::false_type {};
0252 
0253 template<class T>
0254 struct is_sync_write_stream<T, boost::void_t<decltype(
0255     (
0256     std::declval<std::size_t&>() = std::declval<T&>().write_some(
0257         std::declval<detail::ConstBufferSequence>()))
0258     ,std::declval<std::size_t&>() = std::declval<T&>().write_some(
0259         std::declval<detail::ConstBufferSequence>(),
0260         std::declval<boost::system::error_code&>())
0261             )>> : std::true_type {};
0262 #endif
0263 
0264 /** Determine if `T` meets the requirements of @b SyncStream.
0265 
0266     Metafunctions are used to perform compile time checking of template
0267     types. This type will be `std::true_type` if `T` meets the requirements,
0268     else the type will be `std::false_type`. 
0269 
0270     @par Example
0271 
0272     Use with `static_assert`:
0273 
0274     @code
0275     template<class SyncStream>
0276     void f(SyncStream& stream)
0277     {
0278         static_assert(is_sync_stream<SyncStream>::value,
0279             "SyncStream type requirements not met");
0280     ...
0281     @endcode
0282 
0283     Use with `std::enable_if` (SFINAE):
0284 
0285     @code
0286     template<class SyncStream>
0287     typename std::enable_if<is_sync_stream<SyncStream>::value>::type
0288     f(SyncStream& stream);
0289     @endcode
0290 */
0291 #if BOOST_BEAST_DOXYGEN
0292 template<class T>
0293 using is_sync_stream = __see_below__;
0294 #else
0295 template<class T>
0296 using is_sync_stream = std::integral_constant<bool,
0297     is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
0298 #endif
0299 
0300 //------------------------------------------------------------------------------
0301 
0302 /** Determine if `T` meets the requirements of <em>AsyncReadStream</em>.
0303 
0304     Metafunctions are used to perform compile time checking of template
0305     types. This type will be `std::true_type` if `T` meets the requirements,
0306     else the type will be `std::false_type`. 
0307 
0308     @par Example
0309     
0310     Use with `static_assert`:
0311     
0312     @code
0313     template<class AsyncReadStream>
0314     void f(AsyncReadStream& stream)
0315     {
0316         static_assert(is_async_read_stream<AsyncReadStream>::value,
0317             "AsyncReadStream type requirements not met");
0318     ...
0319     @endcode
0320     
0321     Use with `std::enable_if` (SFINAE):
0322     
0323     @code
0324         template<class AsyncReadStream>
0325         typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
0326         f(AsyncReadStream& stream);
0327     @endcode
0328 */
0329 #if BOOST_BEAST_DOXYGEN
0330 template<class T>
0331 using is_async_read_stream = __see_below__;
0332 #else
0333 template<class T, class = void>
0334 struct is_async_read_stream : std::false_type {};
0335 
0336 template<class T>
0337 struct is_async_read_stream<T, boost::void_t<decltype(
0338     std::declval<T&>().async_read_some(
0339         std::declval<detail::MutableBufferSequence>(),
0340         std::declval<detail::ReadHandler>())
0341             )>> : std::integral_constant<bool,
0342     has_get_executor<T>::value
0343         > {};
0344 #endif
0345 
0346 /** Determine if `T` meets the requirements of <em>AsyncWriteStream</em>.
0347 
0348     Metafunctions are used to perform compile time checking of template
0349     types. This type will be `std::true_type` if `T` meets the requirements,
0350     else the type will be `std::false_type`. 
0351 
0352     @par Example
0353 
0354     Use with `static_assert`:
0355 
0356     @code
0357     template<class AsyncWriteStream>
0358     void f(AsyncWriteStream& stream)
0359     {
0360         static_assert(is_async_write_stream<AsyncWriteStream>::value,
0361             "AsyncWriteStream type requirements not met");
0362     ...
0363     @endcode
0364 
0365     Use with `std::enable_if` (SFINAE):
0366 
0367     @code
0368     template<class AsyncWriteStream>
0369     typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
0370     f(AsyncWriteStream& stream);
0371     @endcode
0372 */
0373 #if BOOST_BEAST_DOXYGEN
0374 template<class T>
0375 using is_async_write_stream = __see_below__;
0376 #else
0377 template<class T, class = void>
0378 struct is_async_write_stream : std::false_type {};
0379 
0380 template<class T>
0381 struct is_async_write_stream<T, boost::void_t<decltype(
0382     std::declval<T&>().async_write_some(
0383         std::declval<detail::ConstBufferSequence>(),
0384         std::declval<detail::WriteHandler>())
0385             )>> : std::integral_constant<bool,
0386     has_get_executor<T>::value
0387         > {};
0388 #endif
0389 
0390 /** Determine if `T` meets the requirements of @b AsyncStream.
0391 
0392     Metafunctions are used to perform compile time checking of template
0393     types. This type will be `std::true_type` if `T` meets the requirements,
0394     else the type will be `std::false_type`. 
0395 
0396     @par Example
0397 
0398     Use with `static_assert`:
0399 
0400     @code
0401     template<class AsyncStream>
0402     void f(AsyncStream& stream)
0403     {
0404         static_assert(is_async_stream<AsyncStream>::value,
0405             "AsyncStream type requirements not met");
0406     ...
0407     @endcode
0408 
0409     Use with `std::enable_if` (SFINAE):
0410 
0411     @code
0412     template<class AsyncStream>
0413     typename std::enable_if<is_async_stream<AsyncStream>::value>::type
0414     f(AsyncStream& stream);
0415     @endcode
0416 */
0417 #if BOOST_BEAST_DOXYGEN
0418 template<class T>
0419 using is_async_stream = __see_below__;
0420 #else
0421 template<class T>
0422 using is_async_stream = std::integral_constant<bool,
0423     is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
0424 #endif
0425 
0426 //------------------------------------------------------------------------------
0427 
0428 /** Default socket close function.
0429 
0430     This function is not meant to be called directly. Instead, it
0431     is called automatically when using @ref close_socket. To enable
0432     closure of user-defined types or classes derived from a particular
0433     user-defined type, this function should be overloaded in the
0434     corresponding namespace for the type in question.
0435 
0436     @see close_socket
0437 */
0438 template<
0439     class Protocol,
0440     class Executor>
0441 void
0442 beast_close_socket(
0443     net::basic_socket<
0444         Protocol, Executor>& sock)
0445 {
0446     boost::system::error_code ec;
0447     sock.close(ec);
0448 }
0449 
0450 namespace detail {
0451 
0452 struct close_socket_impl
0453 {
0454     template<class T>
0455     void
0456     operator()(T& t) const
0457     {
0458         using beast::beast_close_socket;
0459         beast_close_socket(t);
0460     }
0461 };
0462 
0463 } // detail
0464 
0465 /** Close a socket or socket-like object.
0466 
0467     This function attempts to close an object representing a socket.
0468     In this context, a socket is an object for which an unqualified
0469     call to the function `void beast_close_socket(Socket&)` is
0470     well-defined. The function `beast_close_socket` is a
0471     <em>customization point</em>, allowing user-defined types to
0472     provide an algorithm for performing the close operation by
0473     overloading this function for the type in question.
0474 
0475     Since the customization point is a function call, the normal
0476     rules for finding the correct overload are applied including
0477     the rules for argument-dependent lookup ("ADL"). This permits
0478     classes derived from a type for which a customization is provided
0479     to inherit the customization point.
0480 
0481     An overload for the networking class template `net::basic_socket`
0482     is provided, which implements the close algorithm for all socket-like
0483     objects (hence the name of this customization point). When used
0484     in conjunction with @ref get_lowest_layer, a generic algorithm
0485     operating on a layered stream can perform a closure of the underlying
0486     socket without knowing the exact list of concrete types.
0487 
0488     @par Example 1
0489     The following generic function synchronously sends a message
0490     on the stream, then closes the socket.
0491     @code
0492     template <class WriteStream>
0493     void hello_and_close (WriteStream& stream)
0494     {
0495         net::write(stream, net::const_buffer("Hello, world!", 13));
0496         close_socket(get_lowest_layer(stream));
0497     }
0498     @endcode
0499 
0500     To enable closure of user defined types, it is necessary to provide
0501     an overload of the function `beast_close_socket` for the type.
0502 
0503     @par Example 2
0504     The following code declares a user-defined type which contains a
0505     private socket, and provides an overload of the customization
0506     point which closes the private socket.
0507     @code
0508     class my_socket
0509     {
0510         net::ip::tcp::socket sock_;
0511 
0512     public:
0513         my_socket(net::io_context& ioc)
0514             : sock_(ioc)
0515         {
0516         }
0517 
0518         friend void beast_close_socket(my_socket& s)
0519         {
0520             error_code ec;
0521             s.sock_.close(ec);
0522             // ignore the error
0523         }
0524     };
0525     @endcode
0526 
0527     @param sock The socket to close. If the customization point is not
0528     defined for the type of this object, or one of its base classes,
0529     then a compiler error results.
0530 
0531     @see beast_close_socket
0532 */
0533 #if BOOST_BEAST_DOXYGEN
0534 template<class Socket>
0535 void
0536 close_socket(Socket& sock);
0537 #else
0538 BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)
0539 #endif
0540 
0541 } // beast
0542 } // boost
0543 
0544 #endif