]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/core/stream_traits.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / beast / core / stream_traits.hpp
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
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)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_STREAM_TRAITS_HPP
11 #define BOOST_BEAST_STREAM_TRAITS_HPP
12
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>
17
18 namespace boost {
19 namespace beast {
20
21 /** A trait to determine the lowest layer type of a stack of stream layers.
22
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>`.
28
29 @param T The type to determine the lowest layer type of.
30
31 @return The type of the lowest layer.
32 */
33 template<class T>
34 #if BOOST_BEAST_DOXYGEN
35 using lowest_layer_type = __see_below__;
36 #else
37 using lowest_layer_type = detail::lowest_layer_type<T>;
38 #endif
39
40 /** Return the lowest layer in a stack of stream layers.
41
42 If `t.next_layer()` is well-defined, returns
43 `get_lowest_layer(t.next_layer())`. Otherwise, it returns `t`.
44
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.
56
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
63 @ref close_socket).
64
65 @par Example
66 @code
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)
71 {
72 error_code ec;
73 // A compile error here means your lowest layer is not the right type!
74 get_lowest_layer(stream).non_blocking(true, ec);
75 if(ec)
76 throw system_error{ec};
77 }
78 @endcode
79
80 @param t The layer in a stack of layered objects for which the lowest layer is returned.
81
82 @see close_socket, lowest_layer_type
83 */
84 template<class T>
85 lowest_layer_type<T>&
86 get_lowest_layer(T& t) noexcept
87 {
88 return detail::get_lowest_layer_impl(
89 t, detail::has_next_layer<T>{});
90 }
91
92 //------------------------------------------------------------------------------
93
94 /** A trait to determine the return type of get_executor.
95
96 This type alias will be the type of values returned by
97 by calling member `get_exector` on an object of type `T&`.
98
99 @param T The type to query
100
101 @return The type of values returned from `get_executor`.
102 */
103 // Workaround for ICE on gcc 4.8
104 #if BOOST_BEAST_DOXYGEN
105 template<class T>
106 using executor_type = __see_below__;
107 #elif BOOST_WORKAROUND(BOOST_GCC, < 40900)
108 template<class T>
109 using executor_type =
110 typename std::decay<T>::type::executor_type;
111 #else
112 template<class T>
113 using executor_type =
114 decltype(std::declval<T&>().get_executor());
115 #endif
116
117 /** Determine if `T` has the `get_executor` member function.
118
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`.
122
123 @par Example
124
125 Use with tag dispatching:
126
127 @code
128 template<class T>
129 void maybe_hello(T const& t, std::true_type)
130 {
131 net::post(
132 t.get_executor(),
133 []
134 {
135 std::cout << "Hello, world!" << std::endl;
136 });
137 }
138
139 template<class T>
140 void maybe_hello(T const&, std::false_type)
141 {
142 // T does not have get_executor
143 }
144
145 template<class T>
146 void maybe_hello(T const& t)
147 {
148 maybe_hello(t, has_get_executor<T>{});
149 }
150 @endcode
151
152 Use with `static_assert`:
153
154 @code
155 struct stream
156 {
157 using executor_type = net::io_context::executor_type;
158 executor_type get_executor() noexcept;
159 };
160
161 static_assert(has_get_executor<stream>::value, "Missing get_executor member");
162 @endcode
163 */
164 #if BOOST_BEAST_DOXYGEN
165 template<class T>
166 using has_get_executor = __see_below__;
167 #else
168 template<class T, class = void>
169 struct has_get_executor : std::false_type {};
170
171 template<class T>
172 struct has_get_executor<T, boost::void_t<decltype(
173 std::declval<T&>().get_executor())>> : std::true_type {};
174 #endif
175
176 //------------------------------------------------------------------------------
177
178 /** Determine if at type meets the requirements of <em>SyncReadStream</em>.
179
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`.
183
184 @par Example
185 Use with `static_assert`:
186 @code
187 template<class SyncReadStream>
188 void f(SyncReadStream& stream)
189 {
190 static_assert(is_sync_read_stream<SyncReadStream>::value,
191 "SyncReadStream type requirements not met");
192 ...
193 @endcode
194
195 Use with `std::enable_if` (SFINAE):
196 @code
197 template<class SyncReadStream>
198 typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
199 f(SyncReadStream& stream);
200 @endcode
201 */
202 #if BOOST_BEAST_DOXYGEN
203 template<class T>
204 using is_sync_read_stream = __see_below__;
205 #else
206 template<class T, class = void>
207 struct is_sync_read_stream : std::false_type {};
208
209 template<class T>
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 {};
217 #endif
218
219 /** Determine if `T` meets the requirements of <em>SyncWriteStream</em>.
220
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`.
224
225 @par Example
226
227 Use with `static_assert`:
228
229 @code
230 template<class SyncReadStream>
231 void f(SyncReadStream& stream)
232 {
233 static_assert(is_sync_read_stream<SyncReadStream>::value,
234 "SyncReadStream type requirements not met");
235 ...
236 @endcode
237
238 Use with `std::enable_if` (SFINAE):
239
240 @code
241 template<class SyncReadStream>
242 typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
243 f(SyncReadStream& stream);
244 @endcode
245 */
246 #if BOOST_BEAST_DOXYGEN
247 template<class T>
248 using is_sync_write_stream = __see_below__;
249 #else
250 template<class T, class = void>
251 struct is_sync_write_stream : std::false_type {};
252
253 template<class T>
254 struct is_sync_write_stream<T, boost::void_t<decltype(
255 (
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 {};
262 #endif
263
264 /** Determine if `T` meets the requirements of @b SyncStream.
265
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`.
269
270 @par Example
271
272 Use with `static_assert`:
273
274 @code
275 template<class SyncStream>
276 void f(SyncStream& stream)
277 {
278 static_assert(is_sync_stream<SyncStream>::value,
279 "SyncStream type requirements not met");
280 ...
281 @endcode
282
283 Use with `std::enable_if` (SFINAE):
284
285 @code
286 template<class SyncStream>
287 typename std::enable_if<is_sync_stream<SyncStream>::value>::type
288 f(SyncStream& stream);
289 @endcode
290 */
291 #if BOOST_BEAST_DOXYGEN
292 template<class T>
293 using is_sync_stream = __see_below__;
294 #else
295 template<class T>
296 using is_sync_stream = std::integral_constant<bool,
297 is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
298 #endif
299
300 //------------------------------------------------------------------------------
301
302 /** Determine if `T` meets the requirements of <em>AsyncReadStream</em>.
303
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`.
307
308 @par Example
309
310 Use with `static_assert`:
311
312 @code
313 template<class AsyncReadStream>
314 void f(AsyncReadStream& stream)
315 {
316 static_assert(is_async_read_stream<AsyncReadStream>::value,
317 "AsyncReadStream type requirements not met");
318 ...
319 @endcode
320
321 Use with `std::enable_if` (SFINAE):
322
323 @code
324 template<class AsyncReadStream>
325 typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
326 f(AsyncReadStream& stream);
327 @endcode
328 */
329 #if BOOST_BEAST_DOXYGEN
330 template<class T>
331 using is_async_read_stream = __see_below__;
332 #else
333 template<class T, class = void>
334 struct is_async_read_stream : std::false_type {};
335
336 template<class T>
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
343 > {};
344 #endif
345
346 /** Determine if `T` meets the requirements of <em>AsyncWriteStream</em>.
347
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`.
351
352 @par Example
353
354 Use with `static_assert`:
355
356 @code
357 template<class AsyncWriteStream>
358 void f(AsyncWriteStream& stream)
359 {
360 static_assert(is_async_write_stream<AsyncWriteStream>::value,
361 "AsyncWriteStream type requirements not met");
362 ...
363 @endcode
364
365 Use with `std::enable_if` (SFINAE):
366
367 @code
368 template<class AsyncWriteStream>
369 typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
370 f(AsyncWriteStream& stream);
371 @endcode
372 */
373 #if BOOST_BEAST_DOXYGEN
374 template<class T>
375 using is_async_write_stream = __see_below__;
376 #else
377 template<class T, class = void>
378 struct is_async_write_stream : std::false_type {};
379
380 template<class T>
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
387 > {};
388 #endif
389
390 /** Determine if `T` meets the requirements of @b AsyncStream.
391
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`.
395
396 @par Example
397
398 Use with `static_assert`:
399
400 @code
401 template<class AsyncStream>
402 void f(AsyncStream& stream)
403 {
404 static_assert(is_async_stream<AsyncStream>::value,
405 "AsyncStream type requirements not met");
406 ...
407 @endcode
408
409 Use with `std::enable_if` (SFINAE):
410
411 @code
412 template<class AsyncStream>
413 typename std::enable_if<is_async_stream<AsyncStream>::value>::type
414 f(AsyncStream& stream);
415 @endcode
416 */
417 #if BOOST_BEAST_DOXYGEN
418 template<class T>
419 using is_async_stream = __see_below__;
420 #else
421 template<class T>
422 using is_async_stream = std::integral_constant<bool,
423 is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
424 #endif
425
426 //------------------------------------------------------------------------------
427
428 /** Default socket close function.
429
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.
435
436 @see close_socket
437 */
438 template<
439 class Protocol,
440 class Executor>
441 void
442 beast_close_socket(
443 net::basic_socket<
444 Protocol, Executor>& sock)
445 {
446 boost::system::error_code ec;
447 sock.close(ec);
448 }
449
450 namespace detail {
451
452 struct close_socket_impl
453 {
454 template<class T>
455 void
456 operator()(T& t) const
457 {
458 using beast::beast_close_socket;
459 beast_close_socket(t);
460 }
461 };
462
463 } // detail
464
465 /** Close a socket or socket-like object.
466
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.
474
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.
480
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.
487
488 @par Example 1
489 The following generic function synchronously sends a message
490 on the stream, then closes the socket.
491 @code
492 template <class WriteStream>
493 void hello_and_close (WriteStream& stream)
494 {
495 net::write(stream, net::const_buffer("Hello, world!", 13));
496 close_socket(get_lowest_layer(stream));
497 }
498 @endcode
499
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.
502
503 @par Example 2
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.
507 @code
508 class my_socket
509 {
510 net::ip::tcp::socket sock_;
511
512 public:
513 my_socket(net::io_context& ioc)
514 : sock_(ioc)
515 {
516 }
517
518 friend void beast_close_socket(my_socket& s)
519 {
520 error_code ec;
521 s.sock_.close(ec);
522 // ignore the error
523 }
524 };
525 @endcode
526
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.
530
531 @see beast_close_socket
532 */
533 #if BOOST_BEAST_DOXYGEN
534 template<class Socket>
535 void
536 close_socket(Socket& sock);
537 #else
538 BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)
539 #endif
540
541 } // beast
542 } // boost
543
544 #endif