| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- #pragma once
- #include <type_traits>
- #include <jvalidate/constraint/extension_constraint.h>
- #include <jvalidate/forward.h>
- #include <jvalidate/status.h>
- namespace jvalidate::extension {
- /**
- * @brief A stub visitor type for building the ExtensionConstraint processing
- * hierarchy. Exposed for use with {@see ConstraintBase::visit}.
- */
- struct VisitorBase {
- virtual ~VisitorBase() = default;
- };
- template <typename E>
- concept Constraint = std::is_base_of_v<constraint::ExtensionConstraint::Impl, E>;
- namespace detail {
- /**
- * @brief A stub visitor type for proxying the ExtensionConstraint concrete
- * implementation type into a visitor.
- * Exists as a base class so that {@see jvalidate::extension::ConstraintBase}
- * can cast a VisitorBase to this.
- *
- * The call graph (including abstract -> virtual resolution) is as follows:
- * ExtensionConstraint::Impl::visit(VisitorBase const &)
- * -> ConstraintBase<E>::visit(VisitorBase const &)
- * ---> TypedVisitor<E>::visit(E const &)
- * -----> TypedVisitorImpl<E, V>::visit(E const &)
- * -------> Visitor::Impl::dispatch(E const &)
- * ---------> Visitor::visit<Adapter, ValidationVisitor>(E const &, ...)
- *
- * @tparam E The ExtensionConstraint type that this visitor applies to
- */
- template <Constraint E> struct TypedVisitor : VisitorBase {
- virtual Status visit(E const & cons) const = 0;
- };
- /**
- * @brief The cleverness of this virtual class hierarchy.
- * Connects {@see jvalidate::extension::Visitor::Impl} to one of the extension
- * constraint types provided in its type signature.
- *
- * The call graph (including abstract -> virtual resolution) is as follows:
- * ExtensionConstraint::Impl::visit(VisitorBase const &)
- * -> ConstraintBase<E>::visit(VisitorBase const &)
- * ---> TypedVisitor<E>::visit(E const &)
- * -----> TypedVisitorImpl<E, V>::visit(E const &)
- * -------> Visitor::Impl::dispatch(E const &)
- * ---------> Visitor::visit<Adapter, ValidationVisitor>(E const &, ...)
- *
- * @tparam E The ExtensionConstraint type that this visitor applies to
- * @tparam CRTP A "Curiously Recurring Template Pattern" class (the actually
- * concrete class implementation of this Visitor).
- * Must implement a function "dispatch" which can accept at least E.
- */
- template <Constraint E, typename CRTP> struct TypedVisitorImpl : TypedVisitor<E> {
- Status visit(E const & cons) const final {
- return static_cast<CRTP const *>(this)->dispatch(cons);
- }
- };
- }
- /**
- * @brief The preferred base class of all user-defined constraints. Using the
- * "Curiously Recurring Template Pattern", it is able to unwrap RTTI (Run Time
- * Type Information) through {@see TypedVisitor}.
- *
- * The call graph (including abstract -> virtual resolution) is as follows:
- * ExtensionConstraint::Impl::visit(VisitorBase const &)
- * -> ConstraintBase<E>::visit(VisitorBase const &)
- * ---> TypedVisitor<E>::visit(E const &)
- * -----> TypedVisitorImpl<E, V>::visit(E const &)
- * -------> Visitor::Impl::dispatch(E const &)
- * ---------> Visitor::visit<Adapter, ValidationVisitor>(E const &, ...)
- *
- * @tparam CRTP A "Curiously Recurring Template Pattern" class (the actually
- * concrete class implementation of this ExtensionConstraint).
- */
- 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));
- }
- };
- /**
- * @brief The visitor class responsible for performing validation on some list
- * of ExtensionConstraints as desired by the user.
- *
- * @tparam CRTP A "Curiously Recurring Template Pattern" class (the actually
- * concrete class implementation of this Visitor).
- * This class must implement the visit function for each extension constraint
- * in the Es... type list, as described by Visitor::Impl::dispatch.
- *
- * @tparam Es... A number of ExtensionConstraint implementations. Each of these
- * must fulfill the {@see jvalidate::extension::Constraint} contract.
- */
- 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");
- return 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});
- }
- };
- }
|