validator.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #pragma once
  2. #include <jvalidate/_config.h> // IWYU pragma: keep
  3. #include <jvalidate/_macro.h>
  4. #include <jvalidate/detail/expect.h>
  5. #include <jvalidate/detail/on_block_exit.h>
  6. #include <jvalidate/forward.h>
  7. #include <jvalidate/regex.h>
  8. #include <jvalidate/validation_config.h>
  9. #include <jvalidate/validation_visitor.h>
  10. namespace jvalidate::detail {
  11. /**
  12. * @brief An implementation of an "Extension Constraint Visitor" plugin that
  13. * does nothing.
  14. */
  15. struct StubExtensionVisitor {};
  16. }
  17. namespace jvalidate {
  18. /**
  19. * @brief A validator is the tool by which a JSON object is actually validated
  20. * against a schema.
  21. *
  22. * @tparam RE A type that can be used to solve regular expressions
  23. */
  24. template <RegexEngine RE = JVALIDATE_IIF(JVALIDATE_HAS_ICU, ICURegexEngine, StdRegexEngine),
  25. typename ExtensionVisitor = detail::StubExtensionVisitor>
  26. class Validator {
  27. private:
  28. schema::Node const & schema_;
  29. ValidationConfig cfg_;
  30. ExtensionVisitor extension_{};
  31. RE regex_{};
  32. public:
  33. /**
  34. * @brief Construct a Validator
  35. *
  36. * @param schema The root schema being validated against. Must outlive this.
  37. *
  38. * @param cfg Any special (runtime) configuration rules being applied to the
  39. * validator.
  40. */
  41. explicit Validator(schema::Node const & schema, ExtensionVisitor extension = {},
  42. ValidationConfig const & cfg = {})
  43. : schema_(schema), cfg_(cfg), extension_(extension) {}
  44. Validator(schema::Node const & schema, ValidationConfig const & cfg)
  45. : schema_(schema), cfg_(cfg) {}
  46. template <typename... Args> Validator(schema::Node &&, Args &&...) = delete;
  47. /**
  48. * @brief Run validation on the given JSON
  49. *
  50. * @tparam A Any Adapter type, in principle a subclass of adapter::Adapter.
  51. * Disallows mutation via ValidationConfig.construct_default_values
  52. *
  53. * @param json The value being validated
  54. *
  55. * @param result An optional out-param of detailed information about
  56. * validation failures. If result is not provided, then the validator will
  57. * terminate on the first error. Otherwise it will run through the entire
  58. * schema to provide a record of all of the failures.
  59. */
  60. template <Adapter A>
  61. requires(not MutableAdapter<A>)
  62. bool validate(A const & json, ValidationResult * result = nullptr) {
  63. EXPECT_M(not cfg_.construct_default_values,
  64. "Cannot perform mutations on an immutable JSON Adapter");
  65. detail::OnBlockExit const _ = [&result, this]() { post_process(result); };
  66. ValidationVisitor visitor(schema_, json, cfg_, regex_, extension_, result);
  67. return static_cast<bool>(visitor.validate(json));
  68. }
  69. /**
  70. * @brief Run validation on the given JSON
  71. *
  72. * @tparam A Any Adapter type that supports assignment, in principle a
  73. * subclass of adapter::Adapter.
  74. *
  75. * @param json The value being validated. Because A is a reference-wrapper,
  76. * the underlying value may be mutated.
  77. *
  78. * @param result An optional out-param of detailed information about
  79. * validation failures. If result is not provided, then the validator will
  80. * terminate on the first error. Otherwise it will run through the entire
  81. * schema to provide a record of all of the failures.
  82. */
  83. template <MutableAdapter A> bool validate(A const & json, ValidationResult * result = nullptr) {
  84. detail::OnBlockExit const _ = [&result, this]() { post_process(result); };
  85. ValidationVisitor visitor(schema_, json, cfg_, regex_, extension_, result);
  86. return static_cast<bool>(visitor.validate(json));
  87. }
  88. /**
  89. * @brief Run validation on the given JSON
  90. *
  91. * @tparam JSON A concrete JSON type. Will be turned into an Adapter, or a
  92. * MutableAdapter (if json is non-const and exists).
  93. *
  94. * @param json The value being validated.
  95. *
  96. * @param result An optional out-param of detailed information about
  97. * validation failures. If result is not provided, then the validator will
  98. * terminate on the first error. Otherwise it will run through the entire
  99. * schema to provide a record of all of the failures.
  100. */
  101. template <typename JSON>
  102. requires(not Adapter<JSON>)
  103. bool validate(JSON & json, ValidationResult * result = nullptr) {
  104. return validate(adapter::AdapterFor<JSON>(json), result);
  105. }
  106. private:
  107. void post_process(ValidationResult *& result) const {
  108. if (result == nullptr) {
  109. return;
  110. }
  111. if (cfg_.only_return_results_with_error) {
  112. *result = result->only_errors();
  113. }
  114. }
  115. };
  116. }