validation_result.h 2.4 KB

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