parser.hpp 2.7 KB

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