2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_STREAM_TRAITS_HPP
11 #define BOOST_BEAST_STREAM_TRAITS_HPP
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/detail/static_const.hpp>
15 #include <boost/beast/core/detail/stream_traits.hpp>
16 #include <boost/asio/basic_socket.hpp>
21 /** A trait to determine the lowest layer type of a stack of stream layers.
23 If `t.next_layer()` is well-defined for an object `t` of type `T`,
24 then `lowest_layer_type<T>` will be an alias for
25 `lowest_layer_type<decltype(t.next_layer())>`,
26 otherwise it will be the type
27 `std::remove_reference<T>`.
29 @param T The type to determine the lowest layer type of.
31 @return The type of the lowest layer.
34 #if BOOST_BEAST_DOXYGEN
35 using lowest_layer_type = __see_below__;
37 using lowest_layer_type = detail::lowest_layer_type<T>;
40 /** Return the lowest layer in a stack of stream layers.
42 If `t.next_layer()` is well-defined, returns
43 `get_lowest_layer(t.next_layer())`. Otherwise, it returns `t`.
45 A stream layer is an object of class type which wraps another object through
46 composition, and meets some or all of the named requirements of the wrapped
47 type while optionally changing behavior. Examples of stream layers include
48 `net::ssl::stream` or @ref beast::websocket::stream. The owner of a stream
49 layer can interact directly with the wrapper, by passing it to stream
50 algorithms. Or, the owner can obtain a reference to the wrapped object by
51 calling `next_layer()` and accessing its members. This is necessary when it is
52 desired to access functionality in the next layer which is not available
53 in the wrapper. For example, @ref websocket::stream permits reading and
54 writing, but in order to establish the underlying connection, members
55 of the wrapped stream (such as `connect`) must be invoked directly.
57 Usually the last object in the chain of composition is the concrete socket
58 object (for example, a `net::basic_socket` or a class derived from it).
59 The function @ref get_lowest_layer exists to easily obtain the concrete
60 socket when it is desired to perform an action that is not prescribed by
61 a named requirement, such as changing a socket option, cancelling all
62 pending asynchronous I/O, or closing the socket (perhaps by using
67 // Set non-blocking mode on a stack of stream
68 // layers with a regular socket at the lowest layer.
69 template <class Stream>
70 void set_non_blocking (Stream& stream)
73 // A compile error here means your lowest layer is not the right type!
74 get_lowest_layer(stream).non_blocking(true, ec);
76 throw system_error{ec};
80 @param t The layer in a stack of layered objects for which the lowest layer is returned.
82 @see close_socket, lowest_layer_type
86 get_lowest_layer(T& t) noexcept
88 return detail::get_lowest_layer_impl(
89 t, detail::has_next_layer<T>{});
92 //------------------------------------------------------------------------------
94 /** A trait to determine the return type of get_executor.
96 This type alias will be the type of values returned by
97 by calling member `get_exector` on an object of type `T&`.
99 @param T The type to query
101 @return The type of values returned from `get_executor`.
103 // Workaround for ICE on gcc 4.8
104 #if BOOST_BEAST_DOXYGEN
106 using executor_type = __see_below__;
107 #elif BOOST_WORKAROUND(BOOST_GCC, < 40900)
109 using executor_type =
110 typename std::decay<T>::type::executor_type;
113 using executor_type =
114 decltype(std::declval<T&>().get_executor());
117 /** Determine if `T` has the `get_executor` member function.
119 Metafunctions are used to perform compile time checking of template
120 types. This type will be `std::true_type` if `T` has the member
121 function with the correct signature, else type will be `std::false_type`.
125 Use with tag dispatching:
129 void maybe_hello(T const& t, std::true_type)
135 std::cout << "Hello, world!" << std::endl;
140 void maybe_hello(T const&, std::false_type)
142 // T does not have get_executor
146 void maybe_hello(T const& t)
148 maybe_hello(t, has_get_executor<T>{});
152 Use with `static_assert`:
157 using executor_type = net::io_context::executor_type;
158 executor_type get_executor() noexcept;
161 static_assert(has_get_executor<stream>::value, "Missing get_executor member");
164 #if BOOST_BEAST_DOXYGEN
166 using has_get_executor = __see_below__;
168 template<class T, class = void>
169 struct has_get_executor : std::false_type {};
172 struct has_get_executor<T, boost::void_t<decltype(
173 std::declval<T&>().get_executor())>> : std::true_type {};
176 //------------------------------------------------------------------------------
178 /** Determine if at type meets the requirements of <em>SyncReadStream</em>.
180 Metafunctions are used to perform compile time checking of template
181 types. This type will be `std::true_type` if `T` meets the requirements,
182 else the type will be `std::false_type`.
185 Use with `static_assert`:
187 template<class SyncReadStream>
188 void f(SyncReadStream& stream)
190 static_assert(is_sync_read_stream<SyncReadStream>::value,
191 "SyncReadStream type requirements not met");
195 Use with `std::enable_if` (SFINAE):
197 template<class SyncReadStream>
198 typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
199 f(SyncReadStream& stream);
202 #if BOOST_BEAST_DOXYGEN
204 using is_sync_read_stream = __see_below__;
206 template<class T, class = void>
207 struct is_sync_read_stream : std::false_type {};
210 struct is_sync_read_stream<T, boost::void_t<decltype(
211 std::declval<std::size_t&>() = std::declval<T&>().read_some(
212 std::declval<detail::MutableBufferSequence>()),
213 std::declval<std::size_t&>() = std::declval<T&>().read_some(
214 std::declval<detail::MutableBufferSequence>(),
215 std::declval<boost::system::error_code&>())
216 )>> : std::true_type {};
219 /** Determine if `T` meets the requirements of <em>SyncWriteStream</em>.
221 Metafunctions are used to perform compile time checking of template
222 types. This type will be `std::true_type` if `T` meets the requirements,
223 else the type will be `std::false_type`.
227 Use with `static_assert`:
230 template<class SyncReadStream>
231 void f(SyncReadStream& stream)
233 static_assert(is_sync_read_stream<SyncReadStream>::value,
234 "SyncReadStream type requirements not met");
238 Use with `std::enable_if` (SFINAE):
241 template<class SyncReadStream>
242 typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
243 f(SyncReadStream& stream);
246 #if BOOST_BEAST_DOXYGEN
248 using is_sync_write_stream = __see_below__;
250 template<class T, class = void>
251 struct is_sync_write_stream : std::false_type {};
254 struct is_sync_write_stream<T, boost::void_t<decltype(
256 std::declval<std::size_t&>() = std::declval<T&>().write_some(
257 std::declval<detail::ConstBufferSequence>()))
258 ,std::declval<std::size_t&>() = std::declval<T&>().write_some(
259 std::declval<detail::ConstBufferSequence>(),
260 std::declval<boost::system::error_code&>())
261 )>> : std::true_type {};
264 /** Determine if `T` meets the requirements of @b SyncStream.
266 Metafunctions are used to perform compile time checking of template
267 types. This type will be `std::true_type` if `T` meets the requirements,
268 else the type will be `std::false_type`.
272 Use with `static_assert`:
275 template<class SyncStream>
276 void f(SyncStream& stream)
278 static_assert(is_sync_stream<SyncStream>::value,
279 "SyncStream type requirements not met");
283 Use with `std::enable_if` (SFINAE):
286 template<class SyncStream>
287 typename std::enable_if<is_sync_stream<SyncStream>::value>::type
288 f(SyncStream& stream);
291 #if BOOST_BEAST_DOXYGEN
293 using is_sync_stream = __see_below__;
296 using is_sync_stream = std::integral_constant<bool,
297 is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
300 //------------------------------------------------------------------------------
302 /** Determine if `T` meets the requirements of <em>AsyncReadStream</em>.
304 Metafunctions are used to perform compile time checking of template
305 types. This type will be `std::true_type` if `T` meets the requirements,
306 else the type will be `std::false_type`.
310 Use with `static_assert`:
313 template<class AsyncReadStream>
314 void f(AsyncReadStream& stream)
316 static_assert(is_async_read_stream<AsyncReadStream>::value,
317 "AsyncReadStream type requirements not met");
321 Use with `std::enable_if` (SFINAE):
324 template<class AsyncReadStream>
325 typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
326 f(AsyncReadStream& stream);
329 #if BOOST_BEAST_DOXYGEN
331 using is_async_read_stream = __see_below__;
333 template<class T, class = void>
334 struct is_async_read_stream : std::false_type {};
337 struct is_async_read_stream<T, boost::void_t<decltype(
338 std::declval<T&>().async_read_some(
339 std::declval<detail::MutableBufferSequence>(),
340 std::declval<detail::ReadHandler>())
341 )>> : std::integral_constant<bool,
342 has_get_executor<T>::value
346 /** Determine if `T` meets the requirements of <em>AsyncWriteStream</em>.
348 Metafunctions are used to perform compile time checking of template
349 types. This type will be `std::true_type` if `T` meets the requirements,
350 else the type will be `std::false_type`.
354 Use with `static_assert`:
357 template<class AsyncWriteStream>
358 void f(AsyncWriteStream& stream)
360 static_assert(is_async_write_stream<AsyncWriteStream>::value,
361 "AsyncWriteStream type requirements not met");
365 Use with `std::enable_if` (SFINAE):
368 template<class AsyncWriteStream>
369 typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
370 f(AsyncWriteStream& stream);
373 #if BOOST_BEAST_DOXYGEN
375 using is_async_write_stream = __see_below__;
377 template<class T, class = void>
378 struct is_async_write_stream : std::false_type {};
381 struct is_async_write_stream<T, boost::void_t<decltype(
382 std::declval<T&>().async_write_some(
383 std::declval<detail::ConstBufferSequence>(),
384 std::declval<detail::WriteHandler>())
385 )>> : std::integral_constant<bool,
386 has_get_executor<T>::value
390 /** Determine if `T` meets the requirements of @b AsyncStream.
392 Metafunctions are used to perform compile time checking of template
393 types. This type will be `std::true_type` if `T` meets the requirements,
394 else the type will be `std::false_type`.
398 Use with `static_assert`:
401 template<class AsyncStream>
402 void f(AsyncStream& stream)
404 static_assert(is_async_stream<AsyncStream>::value,
405 "AsyncStream type requirements not met");
409 Use with `std::enable_if` (SFINAE):
412 template<class AsyncStream>
413 typename std::enable_if<is_async_stream<AsyncStream>::value>::type
414 f(AsyncStream& stream);
417 #if BOOST_BEAST_DOXYGEN
419 using is_async_stream = __see_below__;
422 using is_async_stream = std::integral_constant<bool,
423 is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
426 //------------------------------------------------------------------------------
428 /** Default socket close function.
430 This function is not meant to be called directly. Instead, it
431 is called automatically when using @ref close_socket. To enable
432 closure of user-defined types or classes derived from a particular
433 user-defined type, this function should be overloaded in the
434 corresponding namespace for the type in question.
444 Protocol, Executor>& sock)
446 boost::system::error_code ec;
452 struct close_socket_impl
456 operator()(T& t) const
458 using beast::beast_close_socket;
459 beast_close_socket(t);
465 /** Close a socket or socket-like object.
467 This function attempts to close an object representing a socket.
468 In this context, a socket is an object for which an unqualified
469 call to the function `void beast_close_socket(Socket&)` is
470 well-defined. The function `beast_close_socket` is a
471 <em>customization point</em>, allowing user-defined types to
472 provide an algorithm for performing the close operation by
473 overloading this function for the type in question.
475 Since the customization point is a function call, the normal
476 rules for finding the correct overload are applied including
477 the rules for argument-dependent lookup ("ADL"). This permits
478 classes derived from a type for which a customization is provided
479 to inherit the customization point.
481 An overload for the networking class template `net::basic_socket`
482 is provided, which implements the close algorithm for all socket-like
483 objects (hence the name of this customization point). When used
484 in conjunction with @ref get_lowest_layer, a generic algorithm
485 operating on a layered stream can perform a closure of the underlying
486 socket without knowing the exact list of concrete types.
489 The following generic function synchronously sends a message
490 on the stream, then closes the socket.
492 template <class WriteStream>
493 void hello_and_close (WriteStream& stream)
495 net::write(stream, net::const_buffer("Hello, world!", 13));
496 close_socket(get_lowest_layer(stream));
500 To enable closure of user defined types, it is necessary to provide
501 an overload of the function `beast_close_socket` for the type.
504 The following code declares a user-defined type which contains a
505 private socket, and provides an overload of the customization
506 point which closes the private socket.
510 net::ip::tcp::socket sock_;
513 my_socket(net::io_context& ioc)
518 friend void beast_close_socket(my_socket& s)
527 @param sock The socket to close. If the customization point is not
528 defined for the type of this object, or one of its base classes,
529 then a compiler error results.
531 @see beast_close_socket
533 #if BOOST_BEAST_DOXYGEN
534 template<class Socket>
536 close_socket(Socket& sock);
538 BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)