Program Listing for File validate_detail.hpp

Return to documentation for file (include/eat/process/validate_detail.hpp)

#pragma once
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>

namespace eat::process::validation::detail {
// implementation of ToMessages, which makes a variant of messages given a
// variant of checks, where the message types aredetermined by looking at the
// return type of check.run(), which can be either a single message or a
// variant

template <typename... T>
struct TypeList {};

template <typename Ts, typename U>
struct Contains;

template <typename T, typename... Ts, typename U>
struct Contains<TypeList<T, Ts...>, U>
    : std::conditional_t<std::is_same_v<T, U>, std::true_type, Contains<TypeList<Ts...>, U>> {};

template <typename U>
struct Contains<TypeList<>, U> : std::false_type {};

template <typename Ts, typename U>
struct AddUnique;

template <typename... Ts, typename U>
struct AddUnique<TypeList<Ts...>, U> {
  using type = std::conditional_t<Contains<TypeList<Ts...>, U>::value, TypeList<Ts...>, TypeList<U, Ts...>>;
};

template <typename Ts, typename Us>
struct AddUniqueList;

template <typename Ts, typename U, typename... Us>
struct AddUniqueList<Ts, TypeList<U, Us...>> {
  using type = typename AddUnique<typename AddUniqueList<Ts, TypeList<Us...>>::type, U>::type;
};

template <typename Ts>
struct AddUniqueList<Ts, TypeList<>> {
  using type = Ts;
};

template <typename T>
struct ToTypeList;

template <typename... Ts>
struct ToTypeList<std::variant<Ts...>> {
  using type = TypeList<Ts...>;
};

template <typename... Ts>
struct ToTypeList<std::vector<std::variant<Ts...>>> {
  using type = TypeList<Ts...>;
};

template <typename T>
struct ToTypeList<std::vector<T>> {
  using type = TypeList<T>;
};

template <typename Check>
using MessageTypes = typename ToTypeList<decltype(std::declval<Check>().run(std::declval<ADMData>()))>::type;

template <typename Checks>
struct ToMessagesHelper;

template <typename Check, typename... Checks>
struct ToMessagesHelper<TypeList<Check, Checks...>> {
  using type = typename AddUniqueList<typename ToMessagesHelper<TypeList<Checks...>>::type, MessageTypes<Check>>::type;
};

template <>
struct ToMessagesHelper<TypeList<>> {
  using type = TypeList<>;
};

template <typename T>
struct TypeListToVariant;

template <typename... Ts>
struct TypeListToVariant<TypeList<Ts...>> {
  using type = std::variant<Ts...>;
};

template <typename Checks>
using ToMessages = typename detail::TypeListToVariant<
    typename detail::ToMessagesHelper<typename detail::ToTypeList<Checks>::type>::type>::type;

template <typename Variant, typename T>
struct ToVariantHelper {
  template <typename U>
  Variant operator()(U &&value) {
    return Variant{std::forward<U>(value)};
  }
};

template <typename Variant, typename... Ts>
struct ToVariantHelper<Variant, std::variant<Ts...>> {
  template <typename U>
  Variant operator()(U &&value) {
    return std::visit([](auto &&value_t) { return Variant{std::forward<decltype(value_t)>(value_t)}; },
                      std::forward<U>(value));
  }
};

template <typename Variant, typename T>
Variant to_variant(T &&value) {
  return ToVariantHelper<Variant, T>{}(std::forward<T>(value));
}

template <typename T>
struct TypeName;

template <>
struct TypeName<std::string> {
  static constexpr std::string_view name = "string";
};

template <>
struct TypeName<float> {
  static constexpr std::string_view name = "float";
};

template <typename T>
const std::string type_name = std::string{TypeName<T>::name};

}  // namespace eat::process::validation::detail