parser.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /* Copyright (c) 2018-2023 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 <string_view>
  12. #include <cstdint>
  13. #include <optional>
  14. namespace boost::redis::resp3 {
  15. using int_type = std::uint64_t;
  16. class parser {
  17. public:
  18. using node_type = basic_node<std::string_view>;
  19. using result = std::optional<node_type>;
  20. static constexpr std::size_t max_embedded_depth = 5;
  21. static constexpr std::string_view sep = "\r\n";
  22. private:
  23. // The current depth. Simple data types will have depth 0, whereas
  24. // the elements of aggregates will have depth 1. Embedded types
  25. // will have increasing depth.
  26. std::size_t depth_;
  27. // The parser supports up to 5 levels of nested structures. The
  28. // first element in the sizes stack is a sentinel and must be
  29. // different from 1.
  30. std::array<std::size_t, max_embedded_depth + 1> sizes_;
  31. // Contains the length expected in the next bulk read.
  32. int_type bulk_length_;
  33. // The type of the next bulk. Contains type::invalid if no bulk is
  34. // expected.
  35. type bulk_;
  36. // The number of bytes consumed from the buffer.
  37. std::size_t consumed_;
  38. // Returns the number of bytes that have been consumed.
  39. auto consume_impl(type t, std::string_view elem, system::error_code& ec) -> node_type;
  40. void commit_elem() noexcept;
  41. // The bulk type expected in the next read. If none is expected
  42. // returns type::invalid.
  43. [[nodiscard]]
  44. auto bulk_expected() const noexcept -> bool
  45. { return bulk_ != type::invalid; }
  46. public:
  47. parser();
  48. // Returns true when the parser is done with the current message.
  49. [[nodiscard]]
  50. auto done() const noexcept -> bool;
  51. auto get_suggested_buffer_growth(std::size_t hint) const noexcept -> std::size_t;
  52. auto get_consumed() const noexcept -> std::size_t;
  53. auto consume(std::string_view view, system::error_code& ec) noexcept -> result;
  54. void reset();
  55. };
  56. // Returns false if more data is needed. If true is returned the
  57. // parser is either done or an error occured, that can be checked on
  58. // ec.
  59. template <class Adapter>
  60. bool
  61. parse(
  62. resp3::parser& p,
  63. std::string_view const& msg,
  64. Adapter& adapter,
  65. system::error_code& ec)
  66. {
  67. while (!p.done()) {
  68. auto const res = p.consume(msg, ec);
  69. if (ec)
  70. return true;
  71. if (!res)
  72. return false;
  73. adapter(res.value(), ec);
  74. if (ec)
  75. return true;
  76. }
  77. return true;
  78. }
  79. } // boost::redis::resp3
  80. #endif // BOOST_REDIS_RESP3_PARSER_HPP