|
||||
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
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |