forward.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #pragma once
  2. #include <concepts>
  3. #include <cstdint>
  4. #include <cstdlib>
  5. #include <functional>
  6. #include <iosfwd>
  7. #include <iterator>
  8. #include <memory>
  9. #include <string>
  10. #include <string_view>
  11. #include <type_traits>
  12. #include <utility>
  13. #include <variant>
  14. #include <jvalidate/compat/expected.h>
  15. #define DISCARD1_IMPL(_, ...) __VA_ARGS__
  16. #define DISCARD1(...) DISCARD1_IMPL(__VA_ARGS__)
  17. #define FORWARD_DECLARE_STRUCT(TYPE) struct TYPE;
  18. #define COMMA_NAME(X) , X
  19. namespace jvalidate::detail {
  20. }
  21. namespace jvalidate::adapter::detail {
  22. using namespace jvalidate::detail;
  23. }
  24. namespace jvalidate::format::detail {
  25. using namespace jvalidate::detail;
  26. }
  27. namespace jvalidate {
  28. class Schema;
  29. class Status;
  30. class URI;
  31. struct ValidationConfig;
  32. class ValidationResult;
  33. }
  34. namespace jvalidate::adapter {
  35. enum class Type : int8_t;
  36. class Adapter;
  37. class Const;
  38. using AdapterCallback = std::function<Status(adapter::Adapter const &)>;
  39. using ObjectAdapterCallback = std::function<Status(std::string const &, adapter::Adapter const &)>;
  40. template <typename> struct AdapterTraits;
  41. template <typename V> struct AdapterTraits<V const> : AdapterTraits<V> {};
  42. template <typename JSON> using AdapterFor = AdapterTraits<JSON>::template Adapter<JSON>;
  43. template <typename JSON>
  44. auto load_stream(std::istream & in, JSON & out) noexcept -> detail::expected<void, std::string>;
  45. }
  46. namespace jvalidate::schema {
  47. enum class Version : int8_t;
  48. class Node;
  49. }
  50. namespace jvalidate::constraint {
  51. #define CONSTRAINT_IMPLEMENTATION_LIST(X) \
  52. /* General Constraints - See jvalidate/constraint/general_constraint.h */ \
  53. X(TypeConstraint) \
  54. X(ConstConstraint) \
  55. X(EnumConstraint) \
  56. X(AllOfConstraint) \
  57. X(AnyOfConstraint) \
  58. X(OneOfConstraint) \
  59. X(NotConstraint) \
  60. X(ConditionalConstraint) \
  61. /* Number Constraints - See jvalidate/constraint/number_constraint.h */ \
  62. X(MaximumConstraint) \
  63. X(MinimumConstraint) \
  64. X(MultipleOfConstraint) \
  65. /* String Constraints - See jvalidate/constraint/string_constraint.h */ \
  66. X(MaxLengthConstraint) \
  67. X(MinLengthConstraint) \
  68. X(PatternConstraint) \
  69. X(FormatConstraint) \
  70. /* Array Constraints - See jvalidate/constraint/array_constraint.h */ \
  71. X(AdditionalItemsConstraint) \
  72. X(ContainsConstraint) \
  73. X(MaxItemsConstraint) \
  74. X(MinItemsConstraint) \
  75. X(TupleConstraint) \
  76. X(UnevaluatedItemsConstraint) \
  77. X(UniqueItemsConstraint) \
  78. /* Object Constraints - See jvalidate/constraint/object_constraint.h */ \
  79. X(AdditionalPropertiesConstraint) \
  80. X(DependenciesConstraint) \
  81. X(MaxPropertiesConstraint) \
  82. X(MinPropertiesConstraint) \
  83. X(PatternPropertiesConstraint) \
  84. X(PropertiesConstraint) \
  85. X(PropertyNamesConstraint) \
  86. X(RequiredConstraint) \
  87. X(UnevaluatedPropertiesConstraint) \
  88. /* ExtensionConstraint - A special constraint for all user-defined constraints */ \
  89. X(ExtensionConstraint)
  90. CONSTRAINT_IMPLEMENTATION_LIST(FORWARD_DECLARE_STRUCT);
  91. using Constraint = std::variant<DISCARD1(CONSTRAINT_IMPLEMENTATION_LIST(COMMA_NAME))>;
  92. using SubConstraint = std::variant<schema::Node const *, std::unique_ptr<Constraint>>;
  93. }
  94. namespace jvalidate {
  95. template <typename It>
  96. concept ArrayIterator =
  97. std::forward_iterator<It> and std::is_default_constructible_v<It> and requires(It const it) {
  98. { *it } -> std::convertible_to<adapter::Adapter const &>;
  99. };
  100. template <typename It>
  101. concept ObjectIterator =
  102. std::forward_iterator<It> and std::is_default_constructible_v<It> and requires(It const it) {
  103. { it->first } -> std::convertible_to<std::string_view>;
  104. { it->second } -> std::convertible_to<adapter::Adapter const &>;
  105. };
  106. template <typename A, typename Reentrant>
  107. concept ArrayAdapter = requires(A const adapter) {
  108. { adapter.size() } -> std::convertible_to<size_t>;
  109. { adapter[0UL] } -> std::same_as<Reentrant>;
  110. { adapter.begin() } -> ArrayIterator;
  111. { adapter.end() } -> ArrayIterator;
  112. };
  113. template <typename A, typename Reentrant>
  114. concept ObjectAdapter = requires(A const adapter) {
  115. { adapter.size() } -> std::convertible_to<size_t>;
  116. { adapter.contains("") } -> std::same_as<bool>;
  117. { adapter[""] } -> std::same_as<Reentrant>;
  118. { adapter.begin() } -> ObjectIterator;
  119. { adapter.end() } -> ObjectIterator;
  120. };
  121. /**
  122. * @brief A concept representing the actual adapter form. Used in most code
  123. * that actually cares to interact with JSON, instead of having to define a
  124. * template like AdapterInterface<ArrayAdapter, ObjectAdapter> for the basic
  125. * adapter, or return pointers-to-interfaces in order to access array/object
  126. * data.
  127. *
  128. * This concept functionally defines an Adapter being an AdapterInterface with
  129. * an as_array and as_object method added on.
  130. */
  131. template <typename A>
  132. concept Adapter = std::is_base_of_v<adapter::Adapter, A> && requires(A const adapter) {
  133. typename A::value_type;
  134. { adapter.type() } -> std::same_as<adapter::Type>;
  135. { adapter.as_boolean() } -> std::same_as<bool>;
  136. { adapter.as_integer() } -> std::convertible_to<int64_t>;
  137. { adapter.as_number() } -> std::convertible_to<double>;
  138. { adapter.as_number() } -> std::floating_point;
  139. { adapter.as_object() } -> ObjectAdapter<A>;
  140. { adapter.as_array() } -> ArrayAdapter<A>;
  141. { adapter.array_size() } -> std::convertible_to<size_t>;
  142. { adapter.object_size() } -> std::convertible_to<size_t>;
  143. };
  144. template <typename A, typename Reentrant>
  145. concept MutableObject = ObjectAdapter<A, Reentrant> && requires(A const adapter) {
  146. { adapter.assign("", std::declval<adapter::Const>()) };
  147. };
  148. template <typename A>
  149. concept HasMutableObject = MutableObject<decltype(std::declval<A>().as_object()), A>;
  150. /**
  151. * @brief An extension of Adapter that is capable of altering the underlying
  152. * JSON node. In general, that means that a non-const ref is captured when
  153. * building an Adapter.
  154. *
  155. * Requires that we can assign both to "this", and to values at a key (in the
  156. * case of object type).
  157. * Implies that as_array is also a wrapper for mutable JSON.
  158. */
  159. template <typename A>
  160. concept MutableAdapter = Adapter<A> && requires(A const adapter) {
  161. { adapter.assign(std::declval<adapter::Const>()) };
  162. { adapter.assign(std::declval<adapter::Adapter>()) };
  163. { adapter.as_object() } -> MutableObject<A>;
  164. };
  165. template <typename R>
  166. concept RegexEngine = requires(R & engine) {
  167. { R::engine_name() } -> std::convertible_to<std::string_view>;
  168. { R::is_regex("") } -> std::same_as<bool>;
  169. { engine.search("" /* pattern */, "" /* text */) } -> std::same_as<bool>;
  170. };
  171. template <typename E, typename A, typename B, typename V>
  172. concept Visitable =
  173. Adapter<A> && requires(V & visitor, E const & constraint, A const & doc, B const & base) {
  174. { visitor.visit(constraint, doc, base) } -> std::same_as<Status>;
  175. };
  176. template <typename T, typename S>
  177. concept Not = not std::is_same_v<std::decay_t<T>, std::decay_t<S>>;
  178. }
  179. namespace jvalidate {
  180. template <Adapter A> class ConstraintFactory;
  181. template <Adapter A> class DocumentCache;
  182. template <Adapter Root, RegexEngine RE, typename ExtensionVisitor> class ValidationVisitor;
  183. template <RegexEngine RE, typename ExtensionVisitor> class Validator;
  184. template <Adapter A>
  185. using URIResolver = auto (*)(URI const &, typename A::value_type &) noexcept
  186. -> detail::expected<void, std::string>;
  187. }
  188. namespace jvalidate::extension {
  189. struct VisitorBase;
  190. template <typename CRTP, typename... Es> class Visitor;
  191. }
  192. #undef FORWARD_DECLARE_STRUCT
  193. #undef COMMA_NAME
  194. #undef DISCARD1_IMPL
  195. #undef DISCARD1