Pārlūkot izejas kodu

feat: implement visitor system for ExtensionConstraints

Sam Jaffe 3 mēneši atpakaļ
vecāks
revīzija
f23ab19891

+ 1 - 0
include/jvalidate/constraint.h

@@ -9,6 +9,7 @@
 #include <unordered_set>
 
 #include <jvalidate/constraint/array_constraint.h>
+#include <jvalidate/constraint/extension_constraint.h>
 #include <jvalidate/constraint/general_constraint.h>
 #include <jvalidate/constraint/number_constraint.h>
 #include <jvalidate/constraint/object_constraint.h>

+ 19 - 0
include/jvalidate/constraint/extension_constraint.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include <memory>
+
+#include <jvalidate/forward.h>
+#include <jvalidate/status.h>
+
+namespace jvalidate::constraint {
+class ExtensionConstraint {
+public:
+  struct Impl {
+    virtual ~Impl() = default;
+    virtual Status visit(extension::VisitorBase const &) const = 0;
+  };
+
+public:
+  std::unique_ptr<Impl> pimpl;
+};
+}

+ 0 - 2
include/jvalidate/constraint/general_constraint.h

@@ -37,6 +37,4 @@ struct NotConstraint {
 struct TypeConstraint {
   std::set<adapter::Type> types;
 };
-
-struct ExtensionConstraint {};
 }

+ 61 - 0
include/jvalidate/extension.h

@@ -0,0 +1,61 @@
+#pragma once
+
+#include <type_traits>
+
+#include <jvalidate/constraint/extension_constraint.h>
+#include <jvalidate/forward.h>
+#include <jvalidate/status.h>
+
+namespace jvalidate::extension {
+struct VisitorBase {
+  virtual ~VisitorBase() = default;
+};
+
+template <typename E>
+concept Constraint = std::is_base_of_v<constraint::ExtensionConstraint::Impl, E>;
+
+namespace detail {
+template <Constraint E> struct TypedVisitor : VisitorBase {
+  virtual Status visit(E const & cons) const = 0;
+};
+
+template <Constraint E, typename CRTP> struct TypedVisitorImpl : TypedVisitor<E> {
+  Status visit(E const & cons) const final { static_cast<CRTP const *>(this)->dispatch(cons); }
+};
+}
+
+template <typename CRTP> struct ConstraintBase : constraint::ExtensionConstraint::Impl {
+  Status visit(VisitorBase const & visitor) const final {
+    return dynamic_cast<detail::TypedVisitor<CRTP> const &>(visitor).visit(
+        static_cast<CRTP const &>(*this));
+  }
+};
+
+template <typename CRTP, typename... Es> class Visitor {
+private:
+  template <Adapter A, typename V> class Impl : public detail::TypedVisitorImpl<Es, Impl<A, V>>... {
+  public:
+    Impl(Visitor const * self, A const & document, V const & visitor)
+        : self_(self), document_(document), visitor_(visitor) {}
+
+    using detail::TypedVisitorImpl<Es, Impl>::visit...;
+
+    template <Constraint E> Status dispatch(E const & cons) const {
+      // static_assert(Visitable<CRTP, E, A, V>, "Must implement all visitation functions");
+      static_cast<CRTP const *>(self_)->visit(cons, document_, visitor_);
+    }
+
+  private:
+    Visitor const * self_;
+    A const & document_;
+    V const & visitor_;
+  };
+
+public:
+  template <Adapter A, typename V>
+  Status operator()(constraint::ExtensionConstraint const & cons, A const & document,
+                    V const & visitor) const {
+    return cons.pimpl->visit(Impl<A, V>{this, document, visitor});
+  }
+};
+}

+ 12 - 2
include/jvalidate/forward.h

@@ -166,6 +166,14 @@ template <typename R>
 concept RegexEngine = requires(R & regex) {
   { regex.search("" /* pattern */, "" /* text */) } -> std::same_as<bool>;
 };
+
+template <typename E, typename A, typename B, typename V>
+concept Visitable = Adapter<A> && requires(V & v, E const & c, A const & doc, B const & base) {
+  { v.visit(c, doc, base) } -> std::same_as<Status>;
+};
+
+template <typename T, typename S>
+concept Not = not std::is_convertible_v<std::decay_t<S>, T>;
 }
 
 namespace jvalidate {
@@ -177,9 +185,11 @@ template <RegexEngine RE, typename ExtensionVisitor> class ValidationVisitor;
 template <RegexEngine RE, typename ExtensionVisitor> class Validator;
 
 template <Adapter A> using URIResolver = bool (*)(URI const &, typename A::value_type &);
+}
 
-template <typename T, typename S>
-concept Not = not std::is_convertible_v<std::decay_t<S>, T>;
+namespace jvalidate::extension {
+struct VisitorBase;
+template <typename CRTP, typename... Es> class Visitor;
 }
 
 #undef FORWARD_DECLARE_STRUCT