2024-05-31 22:59:00 -04:00
|
|
|
#ifndef RFL_VALIDATOR_HPP_
|
|
|
|
#define RFL_VALIDATOR_HPP_
|
|
|
|
|
|
|
|
#include <concepts>
|
|
|
|
#include <functional>
|
|
|
|
#include <optional>
|
|
|
|
#include <regex>
|
|
|
|
#include <string>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include "AllOf.hpp"
|
|
|
|
#include "Result.hpp"
|
|
|
|
#include "internal/HasValidation.hpp"
|
|
|
|
#include "internal/StringLiteral.hpp"
|
|
|
|
|
|
|
|
namespace rfl {
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
template <class T, class V, class... Vs>
|
|
|
|
requires internal::HasValidation<AllOf<V, Vs...>, T>
|
|
|
|
struct Validator {
|
|
|
|
public:
|
|
|
|
using ReflectionType = T;
|
2024-06-16 00:13:15 -04:00
|
|
|
using ValidationType = std::conditional_t<sizeof...(Vs) == 0, V, AllOf<V, Vs...>>;
|
2024-06-08 14:10:59 -04:00
|
|
|
|
|
|
|
/// Exception-free validation.
|
|
|
|
static Result<Validator<T, V, Vs...>> from_value(const T& _value) noexcept {
|
|
|
|
try {
|
|
|
|
return Validator<T, V, Vs...>(_value);
|
|
|
|
} catch (std::exception& e) { return Error(e.what()); }
|
2024-05-31 22:59:00 -04:00
|
|
|
}
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Validator() : value_(ValidationType::validate(T()).value()) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Validator(Validator<T, V, Vs...>&& _other) noexcept = default;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Validator(const Validator<T, V, Vs...>& _other) = default;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Validator(T&& _value) : value_(ValidationType::validate(_value).value()) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-16 00:13:15 -04:00
|
|
|
Validator(const T& _value) : value_(ValidationType::validate(_value).value()) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-16 00:13:15 -04:00
|
|
|
template <class U, typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
|
|
|
Validator(U&& _value) : value_(ValidationType::validate(T(std::forward<U>(_value))).value()) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-16 00:13:15 -04:00
|
|
|
template <class U, typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
|
|
|
Validator(const U& _value) : value_(ValidationType::validate(T(_value)).value()) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
~Validator() = default;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Assigns the underlying object.
|
|
|
|
auto& operator=(const T& _value) {
|
|
|
|
value_ = ValidationType::validate(_value).value();
|
|
|
|
return *this;
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Assigns the underlying object.
|
|
|
|
auto& operator=(T&& _value) {
|
|
|
|
value_ = ValidationType::validate(std::forward<T>(_value)).value();
|
|
|
|
return *this;
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Assigns the underlying object.
|
2024-06-16 00:13:15 -04:00
|
|
|
Validator<T, V, Vs...>& operator=(const Validator<T, V, Vs...>& _other) = default;
|
2024-06-08 14:10:59 -04:00
|
|
|
|
|
|
|
/// Assigns the underlying object.
|
2024-06-16 00:13:15 -04:00
|
|
|
Validator<T, V, Vs...>& operator=(Validator<T, V, Vs...>&& _other) noexcept = default;
|
2024-06-08 14:10:59 -04:00
|
|
|
|
|
|
|
/// Assigns the underlying object.
|
2024-06-16 00:13:15 -04:00
|
|
|
template <class U, typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
2024-06-08 14:10:59 -04:00
|
|
|
auto& operator=(U&& _value) noexcept {
|
|
|
|
value_ = ValidationType::validate(T(std::forward<U>(_value))).value();
|
|
|
|
return *this;
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Assigns the underlying object.
|
2024-06-16 00:13:15 -04:00
|
|
|
template <class U, typename std::enable_if<std::is_convertible_v<U, T>, bool>::type = true>
|
2024-06-08 14:10:59 -04:00
|
|
|
auto& operator=(const U& _value) {
|
|
|
|
value_ = ValidationType::validate(T(_value)).value();
|
|
|
|
return *this;
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Equality operator other Validators.
|
|
|
|
bool operator==(const Validator<T, V, Vs...>& _other) const {
|
|
|
|
return value() == _other.value();
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Exposes the underlying value.
|
|
|
|
T& value() { return value_; }
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Exposes the underlying value.
|
|
|
|
const T& value() const { return value_; }
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Necessary for the serialization to work.
|
|
|
|
const T& reflection() const { return value_; }
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
private:
|
|
|
|
/// The underlying value.
|
|
|
|
T value_;
|
|
|
|
};
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
template <class T, class V, class... Vs>
|
2024-06-16 00:13:15 -04:00
|
|
|
inline auto operator<=>(const Validator<T, V, Vs...>& _v1, const Validator<T, V, Vs...>& _v2) {
|
2024-06-08 14:10:59 -04:00
|
|
|
return _v1.value() <=> _v2.value();
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
template <class T, class V, class... Vs>
|
|
|
|
inline auto operator<=>(const Validator<T, V, Vs...>& _v, const T& _t) {
|
|
|
|
return _v.value() <=> _t;
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
} // namespace rfl
|
2024-05-31 22:59:00 -04:00
|
|
|
|
|
|
|
namespace std {
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
template <class T, class V, class... Vs>
|
|
|
|
struct hash<rfl::Validator<T, V, Vs...>> {
|
2024-06-16 00:13:15 -04:00
|
|
|
size_t operator()(const rfl::Validator<T, V, Vs...>& _v) const { return hash<T>()(_v.value()); }
|
2024-06-08 14:10:59 -04:00
|
|
|
};
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
} // namespace std
|
2024-05-31 22:59:00 -04:00
|
|
|
|
|
|
|
#endif
|