draconisplusplus/include/rfl/Validator.hpp

124 lines
3.7 KiB
C++
Raw Normal View History

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