write_message.hpp 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. //
  2. // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 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. #ifndef BHO_MYSQL_IMPL_INTERNAL_CHANNEL_WRITE_MESSAGE_HPP
  8. #define BHO_MYSQL_IMPL_INTERNAL_CHANNEL_WRITE_MESSAGE_HPP
  9. #include <asio2/bho/mysql/error_code.hpp>
  10. #include <asio2/bho/mysql/detail/any_stream.hpp>
  11. #include <asio2/bho/mysql/impl/internal/channel/message_writer.hpp>
  12. #include <asio2/bho/mysql/impl/internal/protocol/constants.hpp>
  13. #include <asio/async_result.hpp>
  14. #include <asio/buffer.hpp>
  15. #include <asio/compose.hpp>
  16. #include <asio/coroutine.hpp>
  17. #include <cstddef>
  18. #include <cstdint>
  19. namespace bho {
  20. namespace mysql {
  21. namespace detail {
  22. // Writes an entire message to stream; partitions the message into
  23. // chunks and adds the required headers
  24. inline void write_message(any_stream& stream, message_writer& processor, error_code& ec)
  25. {
  26. while (!processor.done())
  27. {
  28. std::size_t bytes_written = stream.write_some(asio::buffer(processor.next_chunk()), ec);
  29. if (ec)
  30. break;
  31. processor.on_bytes_written(bytes_written);
  32. }
  33. }
  34. struct write_message_op : asio::coroutine
  35. {
  36. any_stream& stream_;
  37. message_writer& processor_;
  38. write_message_op(any_stream& stream, message_writer& processor) noexcept
  39. : stream_(stream), processor_(processor)
  40. {
  41. }
  42. template <class Self>
  43. void operator()(Self& self, error_code ec = {}, std::size_t bytes_written = 0)
  44. {
  45. // Error handling
  46. if (ec)
  47. {
  48. self.complete(ec);
  49. return;
  50. }
  51. // Non-error path
  52. ASIO_CORO_REENTER(*this)
  53. {
  54. // done() never returns false after a call to prepare_buffer(), so no post() needed
  55. BHO_ASSERT(!processor_.done());
  56. while (!processor_.done())
  57. {
  58. ASIO_CORO_YIELD stream_.async_write_some(
  59. asio::buffer(processor_.next_chunk()),
  60. std::move(self)
  61. );
  62. processor_.on_bytes_written(bytes_written);
  63. };
  64. self.complete(error_code());
  65. }
  66. }
  67. };
  68. template <ASIO_COMPLETION_TOKEN_FOR(void(::bho::mysql::error_code)) CompletionToken>
  69. ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(bho::mysql::error_code))
  70. async_write_message(any_stream& stream, message_writer& processor, CompletionToken&& token)
  71. {
  72. return asio::async_compose<CompletionToken, void(error_code)>(
  73. write_message_op(stream, processor),
  74. token,
  75. stream
  76. );
  77. }
  78. } // namespace detail
  79. } // namespace mysql
  80. } // namespace bho
  81. #endif