#pragma once #include #include #include #include #include #include #include #include namespace jvalidate::detail { class RelativePointer { public: static expected parse(std::string_view path) { if (path == "0") { return RelativePointer(); } RelativePointer rval; if (auto pos = path.find('/'); pos != path.npos) { expected ptr = Pointer::parse(path.substr(pos)); JVALIDATE_PROPIGATE_UNEXPECTED(ptr); rval.pointer_ = *std::move(ptr); path.remove_suffix(path.size() - pos); } else if (path.back() == '#') { rval.requests_key_ = true; path.remove_suffix(1); } if (path.find_first_not_of("0123456789") != std::string_view::npos) { return unexpected("RelativePointer must end in a pointer, or a '#'"); } size_t read = 0; expected parent_steps = parse_integer(path, {.read = read}); JVALIDATE_PROPIGATE_UNEXPECTED(parent_steps.transform_error(to_message)); EXPECT_M(read == path.size(), "Extra chars in RelativePointer"); rval.parent_steps_ = *parent_steps; return rval; } template std::variant inspect(Pointer const & where, A const & root) const { if (requests_key_) { return where.parent(parent_steps_).back(); } auto rval = where.parent(parent_steps_).walk(root); return pointer_.walk(rval); } friend std::ostream & operator<<(std::ostream & os, RelativePointer const & rel) { os << rel.parent_steps_; if (rel.requests_key_) { return os << '#'; } os << rel.pointer_; return os; } private: size_t parent_steps_ = 0; bool requests_key_ = false; Pointer pointer_ = {}; }; }