relative_pointer.h 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #pragma once
  2. #include <ostream>
  3. #include <string>
  4. #include <string_view>
  5. #include <jvalidate/compat/expected.h>
  6. #include <jvalidate/detail/expect.h>
  7. #include <jvalidate/detail/pointer.h>
  8. #include <jvalidate/forward.h>
  9. namespace jvalidate::detail {
  10. class RelativePointer {
  11. public:
  12. static expected<RelativePointer, std::string> parse(std::string_view path) {
  13. if (path == "0") {
  14. return RelativePointer();
  15. }
  16. RelativePointer rval;
  17. if (auto pos = path.find('/'); pos != path.npos) {
  18. expected ptr = Pointer::parse(path.substr(pos));
  19. JVALIDATE_PROPIGATE_UNEXPECTED(ptr);
  20. rval.pointer_ = *std::move(ptr);
  21. path.remove_suffix(path.size() - pos);
  22. } else if (path.back() == '#') {
  23. rval.requests_key_ = true;
  24. path.remove_suffix(1);
  25. }
  26. if (path.find_first_not_of("0123456789") != std::string_view::npos) {
  27. return unexpected("RelativePointer must end in a pointer, or a '#'");
  28. }
  29. expected parent_steps = Pointer::parse_integer<size_t>(path);
  30. JVALIDATE_PROPIGATE_UNEXPECTED(parent_steps);
  31. rval.parent_steps_ = *parent_steps;
  32. return rval;
  33. }
  34. template <Adapter A>
  35. std::variant<std::string, A> inspect(Pointer const & where, A const & root) const {
  36. if (requests_key_) {
  37. return where.parent(parent_steps_).back();
  38. }
  39. auto rval = where.parent(parent_steps_).walk(root);
  40. return pointer_.walk(rval);
  41. }
  42. friend std::ostream & operator<<(std::ostream & os, RelativePointer const & rel) {
  43. os << rel.parent_steps_;
  44. if (rel.requests_key_) {
  45. return os << '#';
  46. }
  47. os << rel.pointer_;
  48. return os;
  49. }
  50. private:
  51. size_t parent_steps_ = 0;
  52. bool requests_key_ = false;
  53. Pointer pointer_ = {};
  54. };
  55. }