validation_result.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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. bool empty() const { return message.empty() && properties.empty() && items.empty(); }
  13. std::string constraint;
  14. std::string message;
  15. std::map<std::string, ValidationResult> properties;
  16. std::map<size_t, ValidationResult> items;
  17. };
  18. private:
  19. std::unordered_set<std::string> visited_properties_;
  20. std::unordered_set<size_t> visited_items_;
  21. std::string message_;
  22. std::vector<Errors> errors_;
  23. public:
  24. void message(std::string const & message) {
  25. (errors_.empty() ? message_ : errors_.back().message) = message;
  26. }
  27. bool empty() const {
  28. return message_.empty() &&
  29. std::all_of(errors_.begin(), errors_.end(), [](auto & e) { return e.empty(); });
  30. }
  31. bool has_visited(size_t item) const { return visited_items_.contains(item); }
  32. bool has_visited(std::string const & property) const {
  33. return visited_properties_.contains(property);
  34. }
  35. friend std::ostream & operator<<(std::ostream & os, ValidationResult const & result) {
  36. result.print(os, 0);
  37. return os;
  38. }
  39. private:
  40. void constraint(std::string const & name) { errors_.push_back(Errors{.constraint = name}); }
  41. void visit(size_t item) { visited_items_.emplace(item); }
  42. void visit(std::string const & property) { visited_properties_.emplace(property); }
  43. void error(size_t item, ValidationResult && result) {
  44. if (errors_.empty()) {
  45. return;
  46. }
  47. if (!result.empty()) {
  48. errors_.back().items.emplace(item, std::move(result));
  49. }
  50. visited_items_.emplace(item);
  51. }
  52. void error(std::string const & property, ValidationResult && result) {
  53. if (errors_.empty()) {
  54. return;
  55. }
  56. if (!result.empty()) {
  57. errors_.back().properties.emplace(property, std::move(result));
  58. }
  59. visited_properties_.emplace(property);
  60. }
  61. private:
  62. static void indent(std::ostream & os, int depth) {
  63. for (int i = 0; i < depth; ++i) {
  64. os << ' ' << ' ';
  65. }
  66. }
  67. void print(std::ostream & os, int depth) const {
  68. if (not message_.empty()) {
  69. indent(os, depth);
  70. os << message_ << "\n";
  71. }
  72. for (auto const & error : errors_) {
  73. if (error.empty()) {
  74. continue;
  75. }
  76. indent(os, depth);
  77. os << "for constraint '" << error.constraint << "'";
  78. if (not error.message.empty()) {
  79. os << ": " << error.message;
  80. }
  81. os << "\n";
  82. for (auto const & [i, r] : error.items) {
  83. indent(os, depth + 1);
  84. os << "at " << i << ":\n";
  85. r.print(os, depth + 2);
  86. }
  87. for (auto const & [i, r] : error.properties) {
  88. indent(os, depth + 1);
  89. os << "at '" << i << "':\n";
  90. r.print(os, depth + 2);
  91. }
  92. }
  93. }
  94. };
  95. }