validation_result.h 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #pragma once
  2. #include <map>
  3. #include <ostream>
  4. #include <unordered_set>
  5. #include <vector>
  6. #include <jvalidate/forward.h>
  7. namespace jvalidate {
  8. class ValidationResult {
  9. public:
  10. template <Adapter A, RegexEngine RE> friend class ValidationVisitor;
  11. struct Errors {
  12. std::string constraint;
  13. std::string message;
  14. std::map<std::string, ValidationResult> properties;
  15. std::map<size_t, ValidationResult> items;
  16. };
  17. private:
  18. std::unordered_set<std::string> visited_properties_;
  19. std::unordered_set<size_t> visited_items_;
  20. std::string message_;
  21. std::vector<Errors> errors_;
  22. public:
  23. void message(std::string const & message) {
  24. (errors_.empty() ? message_ : errors_.back().message) = message;
  25. }
  26. bool has_visited(size_t item) const { return visited_items_.contains(item); }
  27. bool has_visited(std::string const & property) const {
  28. return visited_properties_.contains(property);
  29. }
  30. friend std::ostream & operator<<(std::ostream & os, ValidationResult const & result) {
  31. result.print(os, 0);
  32. return os;
  33. }
  34. private:
  35. void constraint(std::string const & name) { errors_.push_back(Errors{.constraint = name}); }
  36. void visit(size_t item) { visited_items_.emplace(item); }
  37. void visit(std::string const & property) { visited_properties_.emplace(property); }
  38. void error(size_t item, ValidationResult && result) {
  39. if (errors_.empty()) {
  40. return;
  41. }
  42. errors_.back().items.emplace(item, std::move(result));
  43. visited_items_.emplace(item);
  44. }
  45. void error(std::string const & property, ValidationResult && result) {
  46. if (errors_.empty()) {
  47. return;
  48. }
  49. errors_.back().properties.emplace(property, std::move(result));
  50. visited_properties_.emplace(property);
  51. }
  52. private:
  53. static void indent(std::ostream & os, int depth) {
  54. for (int i = 0; i < depth; ++i) {
  55. os << ' ' << ' ';
  56. }
  57. }
  58. void print(std::ostream & os, int depth) const {
  59. if (not message_.empty()) {
  60. indent(os, depth);
  61. os << message_ << "\n";
  62. }
  63. for (auto const & error : errors_) {
  64. if (error.items.empty() and error.properties.empty()) {
  65. continue;
  66. }
  67. indent(os, depth);
  68. os << "for constraint '" << error.constraint << "'";
  69. if (not error.message.empty()) {
  70. os << ": " << error.message;
  71. }
  72. os << "\n";
  73. for (auto const & [i, r] : error.items) {
  74. indent(os, depth + 1);
  75. os << "at " << i << ":\n";
  76. r.print(os, depth + 2);
  77. }
  78. for (auto const & [i, r] : error.properties) {
  79. indent(os, depth + 1);
  80. os << "at '" << i << "':\n";
  81. r.print(os, depth + 2);
  82. }
  83. }
  84. }
  85. };
  86. }