|
|
@@ -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});
|
|
|
+ }
|
|
|
+};
|
|
|
+}
|