|
|
@@ -1,22 +1,35 @@
|
|
|
#pragma once
|
|
|
|
|
|
#include <algorithm>
|
|
|
+#include <concepts>
|
|
|
+#include <cstdint>
|
|
|
+#include <cstdlib>
|
|
|
+#include <map>
|
|
|
+#include <optional>
|
|
|
+#include <ranges>
|
|
|
+#include <set>
|
|
|
+#include <string>
|
|
|
#include <tuple>
|
|
|
#include <type_traits>
|
|
|
+#include <unordered_set>
|
|
|
+#include <utility>
|
|
|
+#include <variant>
|
|
|
#include <vector>
|
|
|
|
|
|
+#include <jvalidate/_macro.h>
|
|
|
#include <jvalidate/compat/enumerate.h>
|
|
|
#include <jvalidate/constraint/array_constraint.h>
|
|
|
#include <jvalidate/constraint/general_constraint.h>
|
|
|
#include <jvalidate/constraint/number_constraint.h>
|
|
|
#include <jvalidate/constraint/object_constraint.h>
|
|
|
#include <jvalidate/constraint/string_constraint.h>
|
|
|
-#include <jvalidate/detail/expect.h>
|
|
|
#include <jvalidate/detail/iostream.h>
|
|
|
#include <jvalidate/detail/number.h>
|
|
|
#include <jvalidate/detail/pointer.h>
|
|
|
#include <jvalidate/detail/scoped_state.h>
|
|
|
+#include <jvalidate/detail/string.h>
|
|
|
#include <jvalidate/detail/string_adapter.h>
|
|
|
+#include <jvalidate/detail/tribool.h>
|
|
|
#include <jvalidate/format.h>
|
|
|
#include <jvalidate/forward.h>
|
|
|
#include <jvalidate/schema.h>
|
|
|
@@ -36,7 +49,8 @@
|
|
|
} \
|
|
|
} while (false)
|
|
|
|
|
|
-#define NOOP_UNLESS_TYPE(etype) RETURN_UNLESS(adapter::Type::etype == document.type(), Status::Noop)
|
|
|
+#define NOOP_UNLESS_TYPE(etype) \
|
|
|
+ JVALIDATE_RETURN_UNLESS(adapter::Type::etype == document.type(), Status::Noop)
|
|
|
|
|
|
#define BREAK_EARLY_IF_NO_RESULT_TREE() \
|
|
|
do { \
|
|
|
@@ -248,13 +262,13 @@ private:
|
|
|
Status visit(constraint::MaximumConstraint const & cons, Adapter auto const & document) const {
|
|
|
switch (document.type()) {
|
|
|
case adapter::Type::Integer:
|
|
|
- if (int64_t value = document.as_integer(); not cons(value)) {
|
|
|
+ if (int64_t const value = document.as_integer(); not cons(value)) {
|
|
|
return result(Status::Reject, value, cons.exclusive ? " >= " : " > ", cons.value);
|
|
|
} else {
|
|
|
return result(Status::Accept, value, cons.exclusive ? " < " : " <= ", cons.value);
|
|
|
}
|
|
|
case adapter::Type::Number:
|
|
|
- if (double value = document.as_number(); not cons(value)) {
|
|
|
+ if (double const value = document.as_number(); not cons(value)) {
|
|
|
return result(Status::Reject, value, cons.exclusive ? " >= " : " > ", cons.value);
|
|
|
} else {
|
|
|
return result(Status::Accept, value, cons.exclusive ? " < " : " <= ", cons.value);
|
|
|
@@ -267,13 +281,13 @@ private:
|
|
|
Status visit(constraint::MinimumConstraint const & cons, Adapter auto const & document) const {
|
|
|
switch (document.type()) {
|
|
|
case adapter::Type::Integer:
|
|
|
- if (int64_t value = document.as_integer(); not cons(value)) {
|
|
|
+ if (int64_t const value = document.as_integer(); not cons(value)) {
|
|
|
return result(Status::Reject, value, cons.exclusive ? " <= " : " < ", cons.value);
|
|
|
} else {
|
|
|
return result(Status::Accept, value, cons.exclusive ? " > " : " >= ", cons.value);
|
|
|
}
|
|
|
case adapter::Type::Number:
|
|
|
- if (double value = document.as_number(); not cons(value)) {
|
|
|
+ if (double const value = document.as_number(); not cons(value)) {
|
|
|
return result(Status::Reject, value, cons.exclusive ? " <= " : " < ", cons.value);
|
|
|
} else {
|
|
|
return result(Status::Accept, value, cons.exclusive ? " > " : " >= ", cons.value);
|
|
|
@@ -285,33 +299,34 @@ private:
|
|
|
|
|
|
Status visit(constraint::MultipleOfConstraint const & cons, Adapter auto const & document) const {
|
|
|
adapter::Type const type = document.type();
|
|
|
- RETURN_UNLESS(type == adapter::Type::Number || type == adapter::Type::Integer, Status::Noop);
|
|
|
+ JVALIDATE_RETURN_IF(type != adapter::Type::Number && type != adapter::Type::Integer,
|
|
|
+ Status::Noop);
|
|
|
|
|
|
- if (double value = document.as_number(); not cons(value)) {
|
|
|
- return result(Status::Reject, value, " is not a multiple of ", cons.value);
|
|
|
- } else {
|
|
|
+ double const value = document.as_number();
|
|
|
+ if (cons(value)) {
|
|
|
return result(Status::Accept, value, " is a multiple of ", cons.value);
|
|
|
}
|
|
|
+ return result(Status::Reject, value, " is not a multiple of ", cons.value);
|
|
|
}
|
|
|
|
|
|
Status visit(constraint::MaxLengthConstraint const & cons, Adapter auto const & document) const {
|
|
|
NOOP_UNLESS_TYPE(String);
|
|
|
std::string const str = document.as_string();
|
|
|
- if (int64_t len = detail::length(str); len > cons.value) {
|
|
|
+ size_t const len = detail::length(str);
|
|
|
+ if (len > cons.value) {
|
|
|
return result(Status::Reject, "string of length ", len, " is >", cons.value);
|
|
|
- } else {
|
|
|
- return result(Status::Accept, "string of length ", len, " is <=", cons.value);
|
|
|
}
|
|
|
+ return result(Status::Accept, "string of length ", len, " is <=", cons.value);
|
|
|
}
|
|
|
|
|
|
Status visit(constraint::MinLengthConstraint const & cons, Adapter auto const & document) const {
|
|
|
NOOP_UNLESS_TYPE(String);
|
|
|
std::string const str = document.as_string();
|
|
|
- if (int64_t len = detail::length(str); len < cons.value) {
|
|
|
+ size_t const len = detail::length(str);
|
|
|
+ if (len < cons.value) {
|
|
|
return result(Status::Reject, "string of length ", len, " is <", cons.value);
|
|
|
- } else {
|
|
|
- return result(Status::Accept, "string of length ", len, " is >=", cons.value);
|
|
|
}
|
|
|
+ return result(Status::Accept, "string of length ", len, " is >=", cons.value);
|
|
|
}
|
|
|
|
|
|
Status visit(constraint::PatternConstraint const & cons, Adapter auto const & document) const {
|
|
|
@@ -334,7 +349,7 @@ private:
|
|
|
// Don't both validating formats if we're not in assertion mode
|
|
|
// Assertion mode is specified either by using the appropriate "$vocab"
|
|
|
// meta-schema or by requesting it in the ValidationConfig.
|
|
|
- return true; // TODO: I think this can be made into Noop
|
|
|
+ return true; // TODO(samjaffe): I think this can be made into Noop
|
|
|
}
|
|
|
|
|
|
switch (format_(cons.format, cons.for_version, document.as_string())) {
|
|
|
@@ -389,20 +404,20 @@ private:
|
|
|
|
|
|
Status visit(constraint::MaxItemsConstraint const & cons, Adapter auto const & document) const {
|
|
|
NOOP_UNLESS_TYPE(Array);
|
|
|
- if (size_t size = document.array_size(); size > cons.value) {
|
|
|
+ size_t const size = document.array_size();
|
|
|
+ if (size > cons.value) {
|
|
|
return result(Status::Reject, "array of size ", size, " is >", cons.value);
|
|
|
- } else {
|
|
|
- return result(Status::Accept, "array of size ", size, " is <=", cons.value);
|
|
|
}
|
|
|
+ return result(Status::Accept, "array of size ", size, " is <=", cons.value);
|
|
|
}
|
|
|
|
|
|
Status visit(constraint::MinItemsConstraint const & cons, Adapter auto const & document) const {
|
|
|
NOOP_UNLESS_TYPE(Array);
|
|
|
- if (size_t size = document.array_size(); size < cons.value) {
|
|
|
+ size_t const size = document.array_size();
|
|
|
+ if (size < cons.value) {
|
|
|
return result(Status::Reject, "array of size ", size, " is <", cons.value);
|
|
|
- } else {
|
|
|
- return result(Status::Accept, "array of size ", size, " is >=", cons.value);
|
|
|
}
|
|
|
+ return result(Status::Accept, "array of size ", size, " is >=", cons.value);
|
|
|
}
|
|
|
|
|
|
Status visit(constraint::TupleConstraint const & cons, Adapter auto const & document) const {
|
|
|
@@ -424,7 +439,7 @@ private:
|
|
|
}
|
|
|
|
|
|
template <Adapter A>
|
|
|
- Status visit(constraint::UniqueItemsConstraint const & cons, A const & document) const {
|
|
|
+ Status visit(constraint::UniqueItemsConstraint const &, A const & document) const {
|
|
|
NOOP_UNLESS_TYPE(Array);
|
|
|
|
|
|
if constexpr (std::totally_ordered<A>) {
|
|
|
@@ -510,21 +525,21 @@ private:
|
|
|
Status visit(constraint::MaxPropertiesConstraint const & cons,
|
|
|
Adapter auto const & document) const {
|
|
|
NOOP_UNLESS_TYPE(Object);
|
|
|
- if (size_t size = document.object_size(); size > cons.value) {
|
|
|
+ size_t const size = document.object_size();
|
|
|
+ if (size > cons.value) {
|
|
|
return result(Status::Reject, "object of size ", size, " is >", cons.value);
|
|
|
- } else {
|
|
|
- return result(Status::Accept, "object of size ", size, " is <=", cons.value);
|
|
|
}
|
|
|
+ return result(Status::Accept, "object of size ", size, " is <=", cons.value);
|
|
|
}
|
|
|
|
|
|
Status visit(constraint::MinPropertiesConstraint const & cons,
|
|
|
Adapter auto const & document) const {
|
|
|
NOOP_UNLESS_TYPE(Object);
|
|
|
- if (size_t size = document.object_size(); size < cons.value) {
|
|
|
+ size_t const size = document.object_size();
|
|
|
+ if (size < cons.value) {
|
|
|
return result(Status::Reject, "object of size ", size, " is <", cons.value);
|
|
|
- } else {
|
|
|
- return result(Status::Accept, "object of size ", size, " is >=", cons.value);
|
|
|
}
|
|
|
+ return result(Status::Accept, "object of size ", size, " is >=", cons.value);
|
|
|
}
|
|
|
|
|
|
Status visit(constraint::PatternPropertiesConstraint const & cons,
|
|
|
@@ -692,7 +707,7 @@ public:
|
|
|
// constraints. This is enforced in the parsing of the schema, rather than
|
|
|
// during validation {@see jvalidate::schema::Node::construct}.
|
|
|
if (std::optional<schema::Node const *> ref = schema_->reference_schema()) {
|
|
|
- // TODO: Investigate why this seems to produce .../$ref/$ref pointers
|
|
|
+ // TODO(samjaffe): Investigate why this seems to produce .../$ref/$ref pointers
|
|
|
rval = validate_subschema(*ref, document, "$ref");
|
|
|
}
|
|
|
|
|
|
@@ -704,7 +719,7 @@ public:
|
|
|
for (auto const & [key, p_constraint] : schema_->constraints()) {
|
|
|
BREAK_EARLY_IF_NO_RESULT_TREE();
|
|
|
schema_path_ = current_schema / key;
|
|
|
- rval &= std::visit([this, &document](auto & c) { return this->visit(c, document); },
|
|
|
+ rval &= std::visit([this, &document](auto & cons) { return this->visit(cons, document); },
|
|
|
*p_constraint);
|
|
|
}
|
|
|
|
|
|
@@ -713,7 +728,7 @@ public:
|
|
|
for (auto const & [key, p_constraint] : schema_->post_constraints()) {
|
|
|
BREAK_EARLY_IF_NO_RESULT_TREE();
|
|
|
schema_path_ = current_schema / key;
|
|
|
- rval &= std::visit([this, &document](auto & c) { return this->visit(c, document); },
|
|
|
+ rval &= std::visit([this, &document](auto & cons) { return this->visit(cons, document); },
|
|
|
*p_constraint);
|
|
|
}
|
|
|
|
|
|
@@ -736,9 +751,7 @@ public:
|
|
|
* @return A ScopedState object that will restore the tracking mode once it
|
|
|
* is destroyed.
|
|
|
*/
|
|
|
- [[nodiscard]] detail::ScopedState invert_tracking() const {
|
|
|
- return detail::ScopedState(tracking_, !tracking_);
|
|
|
- }
|
|
|
+ [[nodiscard]] auto invert_tracking() const { return detail::ScopedState(tracking_, !tracking_); }
|
|
|
|
|
|
/**
|
|
|
* @brief Allow ExtensionVisitor to enable tracking of all results in child
|
|
|
@@ -747,7 +760,7 @@ public:
|
|
|
* @return A ScopedState object that will restore the tracking mode once it
|
|
|
* is destroyed.
|
|
|
*/
|
|
|
- [[nodiscard]] detail::ScopedState track_everything() const {
|
|
|
+ [[nodiscard]] auto track_everything() const {
|
|
|
return detail::ScopedState(tracking_, StoreResults::ForAnything);
|
|
|
}
|
|
|
|
|
|
@@ -789,10 +802,9 @@ public:
|
|
|
Adapter auto const & document, K const &... keys) const {
|
|
|
if (schema::Node const * const * ppschema = std::get_if<0>(&subschema)) {
|
|
|
return validate_subschema(*ppschema, document, keys...);
|
|
|
- } else {
|
|
|
- return std::visit([this, &document](auto & c) { return this->visit(c, document); },
|
|
|
- *std::get<1>(subschema));
|
|
|
}
|
|
|
+ return std::visit([this, &document](auto & cons) { return this->visit(cons, document); },
|
|
|
+ *std::get<1>(subschema));
|
|
|
}
|
|
|
|
|
|
/**
|