]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/test/beast/core/bind_handler.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / beast / test / beast / core / bind_handler.cpp
CommitLineData
b32b8144 1//
92f5a8d4 2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
b32b8144
FG
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// Test that header file is self-contained.
11#include <boost/beast/core/bind_handler.hpp>
12
92f5a8d4
TL
13#include "test_handler.hpp"
14
b32b8144 15#include <boost/beast/core/detail/type_traits.hpp>
92f5a8d4
TL
16#include <boost/beast/_experimental/unit_test/suite.hpp>
17#include <boost/beast/_experimental/test/stream.hpp>
18#include <boost/asio/io_context.hpp>
19#include <boost/asio/bind_executor.hpp>
20#include <boost/asio/executor_work_guard.hpp>
21#include <boost/asio/dispatch.hpp>
22#include <boost/asio/defer.hpp>
23#include <boost/asio/post.hpp>
11fdf7f2 24#include <boost/asio/strand.hpp>
92f5a8d4
TL
25#include <boost/bind/placeholders.hpp>
26#include <boost/core/exchange.hpp>
27#include <memory>
b32b8144
FG
28#include <string>
29
30namespace boost {
31namespace beast {
32
33class bind_handler_test : public unit_test::suite
34{
35public:
36 template<class... Args>
37 struct handler
38 {
39 void
40 operator()(Args const&...) const
41 {
42 }
43 };
44
92f5a8d4
TL
45 struct copyable
46 {
47 template<class... Args>
48 void
49 operator()(Args&&...) const
50 {
51 }
52 };
53
54 struct move_only
55 {
56 move_only() = default;
57 move_only(move_only&&) = default;
58 move_only(move_only const&) = delete;
59 void operator()() const{};
60 };
61
62 // A move-only parameter
63 template<std::size_t I>
64 struct move_arg
65 {
66 move_arg() = default;
67 move_arg(move_arg&&) = default;
68 move_arg(move_arg const&) = delete;
69 void operator()() const
70 {
71 };
72 };
73
74 void
75 callback(int v)
76 {
77 BEAST_EXPECT(v == 42);
78 }
79
80 class test_executor
81 {
82 bind_handler_test& s_;
92f5a8d4 83
20effc67
TL
84#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
85 net::any_io_executor ex_;
86
87 // Storing the blocking property as a member is not strictly necessary,
88 // as we could simply forward the calls
89 // require(ex_, blocking.possibly)
90 // and
91 // require(ex_, blocking.never)
92 // to the underlying executor, and then
93 // query(ex_, blocking)
94 // when required. This forwarding approach is used here for the
95 // outstanding_work property.
96 net::execution::blocking_t blocking_;
97
98#else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
99 net::io_context::executor_type ex_;
100#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
92f5a8d4
TL
101 public:
102 test_executor(
103 test_executor const&) = default;
104
105 test_executor(
106 bind_handler_test& s,
107 net::io_context& ioc)
108 : s_(s)
109 , ex_(ioc.get_executor())
20effc67
TL
110#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
111 , blocking_(net::execution::blocking.possibly)
112#endif
92f5a8d4
TL
113 {
114 }
115
116 bool operator==(
117 test_executor const& other) const noexcept
118 {
119 return ex_ == other.ex_;
120 }
121
122 bool operator!=(
123 test_executor const& other) const noexcept
124 {
125 return ex_ != other.ex_;
126 }
127
20effc67
TL
128#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
129
130 net::execution_context&
131 query(
132 net::execution::context_t c) const noexcept
133 {
134 return net::query(ex_, c);
135 }
136
137 net::execution::blocking_t
138 query(
139 net::execution::blocking_t) const noexcept
140 {
141 return blocking_;
142 }
143
144 net::execution::outstanding_work_t
145 query(
146 net::execution::outstanding_work_t w) const noexcept
147 {
148 return net::query(ex_, w);
149 }
150
151 test_executor
152 require(
153 net::execution::blocking_t::possibly_t b) const
154 {
155 test_executor new_ex(*this);
156 new_ex.blocking_ = b;
157 return new_ex;
158 }
159
160 test_executor
161 require(
162 net::execution::blocking_t::never_t b) const
163 {
164 test_executor new_ex(*this);
165 new_ex.blocking_ = b;
166 return new_ex;
167 }
168
169 test_executor prefer(net::execution::outstanding_work_t::untracked_t w) const
170 {
171 test_executor new_ex(*this);
172 new_ex.ex_ = net::prefer(ex_, w);
173 return new_ex;
174 }
175
176 test_executor prefer(net::execution::outstanding_work_t::tracked_t w) const
177 {
178 test_executor new_ex(*this);
179 new_ex.ex_ = net::prefer(ex_, w);
180 return new_ex;
181 }
182
183 template<class F>
184 void execute(F&& f) const
185 {
186 if (blocking_ == net::execution::blocking.possibly)
187 {
188 s_.on_invoke();
189 net::execution::execute(ex_, std::forward<F>(f));
190 }
191 else
192 {
193 // shouldn't be called since the enclosing
194 // networking wrapper only uses dispatch
195 BEAST_FAIL();
196 }
197 }
198#endif
199#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
200 net::execution_context&
92f5a8d4
TL
201 context() const noexcept
202 {
203 return ex_.context();
204 }
205
20effc67
TL
206 void
207 on_work_started() const noexcept
92f5a8d4
TL
208 {
209 ex_.on_work_started();
210 }
211
20effc67
TL
212 void
213 on_work_finished() const noexcept
92f5a8d4
TL
214 {
215 ex_.on_work_finished();
216 }
217
218 template<class F, class Alloc>
20effc67
TL
219 void
220 dispatch(F&& f, Alloc const& a)
92f5a8d4
TL
221 {
222 s_.on_invoke();
20effc67
TL
223 net::execution::execute(
224 net::prefer(ex_,
225 net::execution::blocking.possibly,
226 net::execution::allocator(a)),
227 std::forward<F>(f));
228 // previously equivalent to
229 // ex_.dispatch(std::forward<F>(f), a);
92f5a8d4
TL
230 }
231
232 template<class F, class Alloc>
20effc67
TL
233 void
234 post(F&& f, Alloc const& a)
92f5a8d4
TL
235 {
236 // shouldn't be called since the enclosing
237 // networking wrapper only uses dispatch
238 BEAST_FAIL();
239 }
240
241 template<class F, class Alloc>
20effc67
TL
242 void
243 defer(F&& f, Alloc const& a)
92f5a8d4
TL
244 {
245 // shouldn't be called since the enclosing
246 // networking wrapper only uses dispatch
247 BEAST_FAIL();
248 }
20effc67 249#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
92f5a8d4
TL
250 };
251
20effc67
TL
252#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
253 BOOST_STATIC_ASSERT(net::execution::is_executor<test_executor>::value);
254#else
255 BOOST_STATIC_ASSERT(net::is_executor<test_executor>::value);
256#endif
257
92f5a8d4
TL
258 class test_cb
259 {
260 bool fail_ = true;
261
262 public:
263 test_cb() = default;
264 test_cb(test_cb const&) = delete;
265 test_cb(test_cb&& other)
266 : fail_(boost::exchange(
267 other.fail_, false))
268 {
269 }
270
271 ~test_cb()
272 {
273 BEAST_EXPECT(! fail_);
274 }
275
276 void
277 operator()()
278 {
279 fail_ = false;
280 BEAST_EXPECT(true);
281 }
282
283 void
284 operator()(int v)
285 {
286 fail_ = false;
287 BEAST_EXPECT(v == 42);
288 }
289
290 void
291 operator()(int v, string_view s)
292 {
293 fail_ = false;
294 BEAST_EXPECT(v == 42);
295 BEAST_EXPECT(s == "s");
296 }
297
298 void
299 operator()(int v, string_view s, move_arg<1>)
300 {
301 fail_ = false;
302 BEAST_EXPECT(v == 42);
303 BEAST_EXPECT(s == "s");
304 }
305
306 void
307 operator()(int v, string_view s, move_arg<1>, move_arg<2>)
308 {
309 fail_ = false;
310 BEAST_EXPECT(v == 42);
311 BEAST_EXPECT(s == "s");
312 }
313
314 void
315 operator()(error_code, std::size_t n)
316 {
317 fail_ = false;
318 BEAST_EXPECT(n == 256);
319 }
320
321 void
322 operator()(
323 error_code, std::size_t n, string_view s)
324 {
325 boost::ignore_unused(s);
326 fail_ = false;
327 BEAST_EXPECT(n == 256);
328 }
329
330 void
331 operator()(std::shared_ptr<int> const& sp)
332 {
333 fail_ = false;
334 BEAST_EXPECT(sp.get() != nullptr);
335 }
336 };
337
b32b8144 338#if 0
92f5a8d4
TL
339 // These functions should fail to compile
340
b32b8144
FG
341 void
342 failStdBind()
343 {
92f5a8d4
TL
344 std::bind(bind_handler(test_cb{}));
345 }
346
347 void
348 failStdBindFront()
349 {
350 std::bind(bind_front_handler(test_cb{}));
b32b8144
FG
351 }
352#endif
353
92f5a8d4
TL
354 //--------------------------------------------------------------------------
355
356 bool invoked_;
357
b32b8144 358 void
92f5a8d4 359 on_invoke()
b32b8144 360 {
92f5a8d4 361 invoked_ = true;
b32b8144 362 }
92f5a8d4
TL
363
364 template<class F>
b32b8144 365 void
92f5a8d4 366 testHooks(net::io_context& ioc, F&& f)
b32b8144 367 {
92f5a8d4
TL
368 invoked_ = false;
369 net::post(ioc, std::forward<F>(f));
370 ioc.run();
371 ioc.restart();
372 BEAST_EXPECT(invoked_);
b32b8144
FG
373 }
374
92f5a8d4
TL
375 //--------------------------------------------------------------------------
376
377 void
378 testBindHandler()
11fdf7f2 379 {
92f5a8d4
TL
380 using m1 = move_arg<1>;
381 using m2 = move_arg<2>;
382
11fdf7f2 383 {
92f5a8d4
TL
384 using namespace std::placeholders;
385
386 // 0-ary
387 bind_handler(test_cb{})();
388
389 // 1-ary
390 bind_handler(test_cb{}, 42)();
391 bind_handler(test_cb{}, _1)(42);
392 bind_handler(test_cb{}, _2)(0, 42);
393
394 // 2-ary
395 bind_handler(test_cb{}, 42, "s")();
396 bind_handler(test_cb{}, 42, "s")(0);
397 bind_handler(test_cb{}, _1, "s")(42);
398 bind_handler(test_cb{}, 42, _1) ("s");
399 bind_handler(test_cb{}, _1, _2)(42, "s");
400 bind_handler(test_cb{}, _1, _2)(42, "s", "X");
401 bind_handler(test_cb{}, _2, _1)("s", 42);
402 bind_handler(test_cb{}, _3, _2)("X", "s", 42);
403
404 // 3-ary
405 bind_handler(test_cb{}, 42, "s")(m1{});
406 bind_handler(test_cb{}, 42, "s", _1)(m1{});
407 bind_handler(test_cb{}, 42, _1, m1{})("s");
408
409 // 4-ary
410 bind_handler(test_cb{}, 42, "s")(m1{}, m2{});
411 bind_handler(test_cb{}, 42, "s", m1{})(m2{});
412 bind_handler(test_cb{}, 42, "s", m1{}, m2{})();
413 bind_handler(test_cb{}, 42, _1, m1{})("s", m2{});
414 bind_handler(test_cb{}, _3, _1, m1{})("s", m2{}, 42);
11fdf7f2 415 }
11fdf7f2 416
92f5a8d4
TL
417 {
418 using namespace boost::placeholders;
419
420 // 0-ary
421 bind_handler(test_cb{})();
422
423 // 1-ary
424 bind_handler(test_cb{}, 42)();
425 bind_handler(test_cb{}, _1)(42);
426 bind_handler(test_cb{}, _2)(0, 42);
427
428 // 2-ary
429 bind_handler(test_cb{}, 42, "s")();
430 bind_handler(test_cb{}, 42, "s")(0);
431 bind_handler(test_cb{}, _1, "s")(42);
432 bind_handler(test_cb{}, 42, _1) ("s");
433 bind_handler(test_cb{}, _1, _2)(42, "s");
434 bind_handler(test_cb{}, _1, _2)(42, "s", "X");
435 bind_handler(test_cb{}, _2, _1)("s", 42);
436 bind_handler(test_cb{}, _3, _2)("X", "s", 42);
437
438 // 3-ary
439 bind_handler(test_cb{}, 42, "s")(m1{});
440 bind_handler(test_cb{}, 42, "s", _1)(m1{});
441 bind_handler(test_cb{}, 42, _1, m1{})("s");
442
443 // 4-ary
444 bind_handler(test_cb{}, 42, "s")(m1{}, m2{});
445 bind_handler(test_cb{}, 42, "s", m1{})(m2{});
446 bind_handler(test_cb{}, 42, "s", m1{}, m2{})();
447 bind_handler(test_cb{}, 42, _1, m1{})("s", m2{});
448 bind_handler(test_cb{}, _3, _1, m1{})("s", m2{}, 42);
449 }
450
451 // perfect forwarding
452 {
453 std::shared_ptr<int> const sp =
454 std::make_shared<int>(42);
455 {
456 bind_handler(test_cb{}, sp)();
457 BEAST_EXPECT(sp.get() != nullptr);
458 }
459 {
460 bind_handler(test_cb{})(sp);
461 BEAST_EXPECT(sp.get() != nullptr);
462 }
463 }
464
465 // associated executor
466 {
467 net::io_context ioc;
468 testHooks(ioc, bind_handler(net::bind_executor(
469 test_executor(*this, ioc), test_cb{})));
470 }
471
472 // asio_handler_invoke
473 {
474 // make sure things compile, also can set a
475 // breakpoint in asio_handler_invoke to make sure
476 // it is instantiated.
477 net::io_context ioc;
478 net::strand<
479 net::io_context::executor_type> s{
480 ioc.get_executor()};
481 net::post(s,
482 bind_handler(test_cb{}, 42));
483 ioc.run();
484 }
485
486 // legacy hooks
487 legacy_handler::test(
488 [](legacy_handler h)
489 {
490 return bind_handler(h);
491 });
492 }
493
494 void
495 testBindFrontHandler()
496 {
497 using m1 = move_arg<1>;
498 using m2 = move_arg<2>;
499
500 // 0-ary
501 bind_front_handler(test_cb{})();
502
503 // 1-ary
504 bind_front_handler(test_cb{}, 42)();
505 bind_front_handler(test_cb{})(42);
506
507 // 2-ary
508 bind_front_handler(test_cb{}, 42, "s")();
509 bind_front_handler(test_cb{}, 42)("s");
510 bind_front_handler(test_cb{})(42, "s");
511
512 // 3-ary
513 bind_front_handler(test_cb{}, 42, "s", m1{})();
514 bind_front_handler(test_cb{}, 42, "s")(m1{});
515 bind_front_handler(test_cb{}, 42)("s", m1{});
516 bind_front_handler(test_cb{})(42, "s", m1{});
517
518 // 4-ary
519 bind_front_handler(test_cb{}, 42, "s", m1{}, m2{})();
520 bind_front_handler(test_cb{}, 42, "s", m1{})(m2{});
521 bind_front_handler(test_cb{}, 42, "s")(m1{}, m2{});
522 bind_front_handler(test_cb{}, 42)("s", m1{}, m2{});
523 bind_front_handler(test_cb{})(42, "s", m1{}, m2{});
524
525 error_code ec;
526 std::size_t n = 256;
527
528 // void(error_code, size_t)
529 bind_front_handler(test_cb{}, ec, n)();
530
531 // void(error_code, size_t)(string_view)
532 bind_front_handler(test_cb{}, ec, n)("s");
533
534 // perfect forwarding
535 {
536 std::shared_ptr<int> const sp =
537 std::make_shared<int>(42);
538 bind_front_handler(test_cb{}, sp)();
539 BEAST_EXPECT(sp.get() != nullptr);
540 }
541
542 // associated executor
543 {
544 net::io_context ioc;
545
546 testHooks(ioc, bind_front_handler(net::bind_executor(
547 test_executor(*this, ioc), test_cb{})
548 ));
549 testHooks(ioc, bind_front_handler(net::bind_executor(
550 test_executor(*this, ioc), test_cb{}),
551 42));
552 testHooks(ioc, bind_front_handler(net::bind_executor(
553 test_executor(*this, ioc), test_cb{}),
554 42, "s"));
555 testHooks(ioc, bind_front_handler(net::bind_executor(
556 test_executor(*this, ioc), test_cb{}),
557 42, "s", m1{}));
558 testHooks(ioc, bind_front_handler(net::bind_executor(
559 test_executor(*this, ioc), test_cb{}),
560 42, "s", m1{}, m2{}));
561 testHooks(ioc, bind_front_handler(net::bind_executor(
562 test_executor(*this, ioc), test_cb{}),
563 ec, n));
564 }
565
566 // legacy hooks
567 legacy_handler::test(
568 [](legacy_handler h)
569 {
570 return bind_front_handler(h);
571 });
572 legacy_handler::test(
573 [](legacy_handler h)
574 {
575 return bind_front_handler(
576 h, error_code{}, std::size_t{});
577 });
578 }
579
580
581 //--------------------------------------------------------------------------
582
583 template <class AsyncReadStream, class ReadHandler>
11fdf7f2 584 void
92f5a8d4
TL
585 signal_aborted (AsyncReadStream& stream, ReadHandler&& handler)
586 {
587 net::post(
588 stream.get_executor(),
589 bind_handler (std::forward <ReadHandler> (handler),
590 net::error::operation_aborted, 0));
591 }
592
593 template <class AsyncReadStream, class ReadHandler>
594 void
595 signal_eof (AsyncReadStream& stream, ReadHandler&& handler)
596 {
597 net::post(
598 stream.get_executor(),
599 bind_front_handler (std::forward<ReadHandler> (handler),
600 net::error::eof, 0));
11fdf7f2
TL
601 }
602
92f5a8d4
TL
603 void
604 testJavadocs()
605 {
606 BEAST_EXPECT((
607 &bind_handler_test::signal_aborted<
608 test::stream, handler<error_code, std::size_t>>));
609
610 BEAST_EXPECT((
611 &bind_handler_test::signal_eof<
612 test::stream, handler<error_code, std::size_t>>));
613 }
614
615 //--------------------------------------------------------------------------
616
b32b8144
FG
617 void
618 run() override
619 {
92f5a8d4
TL
620 testBindHandler();
621 testBindFrontHandler();
622 testJavadocs();
b32b8144
FG
623 }
624};
625
626BEAST_DEFINE_TESTSUITE(beast,core,bind_handler);
627
628} // beast
629} // boost