parser.hpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /* Copyright (c) 2018-2024 Marcelo Zimbres Silva (mzimbres@gmail.com)
  2. *
  3. * Distributed under the Boost Software License, Version 1.0. (See
  4. * accompanying file LICENSE.txt)
  5. */
  6. #ifndef BOOST_REDIS_RESP3_PARSER_HPP
  7. #define BOOST_REDIS_RESP3_PARSER_HPP
  8. #include <boost/redis/resp3/node.hpp>
  9. #include <boost/system/error_code.hpp>
  10. #include <array>
  11. #include <cstdint>
  12. #include <optional>
  13. #include <string_view>
  14. namespace boost::redis::resp3 {
  15. class parser {
  16. public:
  17. using node_type = basic_node<std::string_view>;
  18. using result = std::optional<node_type>;
  19. static constexpr std::size_t max_embedded_depth = 5;
  20. static constexpr std::string_view sep = "\r\n";
  21. private:
  22. using sizes_type = std::array<std::size_t, max_embedded_depth + 1>;
  23. // sizes_[0] = 2 because the sentinel must be more than 1.
  24. static constexpr sizes_type default_sizes = {
  25. {2, 1, 1, 1, 1, 1}
  26. };
  27. static constexpr auto default_bulk_length = static_cast<std::size_t>(-1);
  28. // The current depth. Simple data types will have depth 0, whereas
  29. // the elements of aggregates will have depth 1. Embedded types
  30. // will have increasing depth.
  31. std::size_t depth_;
  32. // The parser supports up to 5 levels of nested structures. The
  33. // first element in the sizes stack is a sentinel and must be
  34. // different from 1.
  35. sizes_type sizes_;
  36. // Contains the length expected in the next bulk read.
  37. std::size_t bulk_length_;
  38. // The type of the next bulk. Contains type::invalid if no bulk is
  39. // expected.
  40. type bulk_;
  41. // The number of bytes consumed from the buffer.
  42. std::size_t consumed_;
  43. // Returns the number of bytes that have been consumed.
  44. auto consume_impl(type t, std::string_view elem, system::error_code& ec) -> node_type;
  45. void commit_elem() noexcept;
  46. // The bulk type expected in the next read. If none is expected
  47. // returns type::invalid.
  48. [[nodiscard]]
  49. auto bulk_expected() const noexcept -> bool
  50. {
  51. return bulk_ != type::invalid;
  52. }
  53. public:
  54. parser();
  55. // Returns true when the parser is done with the current message.
  56. [[nodiscard]]
  57. auto done() const noexcept -> bool;
  58. auto get_consumed() const noexcept -> std::size_t;
  59. auto consume(std::string_view view, system::error_code& ec) noexcept -> result;
  60. void reset();
  61. bool is_parsing() const noexcept;
  62. };
  63. // Returns false if more data is needed. If true is returned the
  64. // parser is either done or an error occured, that can be checked on
  65. // ec.
  66. template <class Adapter>
  67. bool parse(parser& p, std::string_view const& msg, Adapter& adapter, system::error_code& ec)
  68. {
  69. // This if could be avoid with a state machine that jumps into the
  70. // correct position.
  71. if (!p.is_parsing())
  72. adapter.on_init();
  73. while (!p.done()) {
  74. auto const res = p.consume(msg, ec);
  75. if (ec)
  76. return true;
  77. if (!res)
  78. return false;
  79. adapter.on_node(res.value(), ec);
  80. if (ec)
  81. return true;
  82. }
  83. adapter.on_done();
  84. return true;
  85. }
  86. } // namespace boost::redis::resp3
  87. #endif // BOOST_REDIS_RESP3_PARSER_HPP