validation_result.h 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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({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. errors_.back().items.emplace(item, std::move(result));
  40. visited_items_.emplace(item);
  41. }
  42. void error(std::string const & property, ValidationResult && result) {
  43. errors_.back().properties.emplace(property, std::move(result));
  44. visited_properties_.emplace(property);
  45. }
  46. private:
  47. static void indent(std::ostream & os, int depth) {
  48. for (int i = 0; i < depth; ++i) {
  49. os << ' ' << ' ';
  50. }
  51. }
  52. void print(std::ostream & os, int depth) const {
  53. if (not message_.empty()) {
  54. indent(os, depth);
  55. os << message_ << "\n";
  56. }
  57. for (auto const & error : errors_) {
  58. if (error.items.empty() and error.properties.empty()) {
  59. continue;
  60. }
  61. indent(os, depth);
  62. os << "for constraint '" << error.constraint << "'";
  63. if (not error.message.empty()) {
  64. os << ": " << error.message;
  65. }
  66. os << "\n";
  67. for (auto const & [i, r] : error.items) {
  68. indent(os, depth + 1);
  69. os << "at " << i << ":\n";
  70. r.print(os, depth + 2);
  71. }
  72. for (auto const & [i, r] : error.properties) {
  73. indent(os, depth + 1);
  74. os << "at '" << i << "':\n";
  75. r.print(os, depth + 2);
  76. }
  77. }
  78. }
  79. };
  80. }