Files
2026-08-07 09:25:55 +08:00

125 lines
4.7 KiB
C++

#pragma once
#include "adminive/adapter.hpp"
#include <concepts>
#include <stdexcept>
#include <string_view>
#include <type_traits>
#include <utility>
namespace adminive {
template <class T, T Minimum, T Maximum>
requires std::totally_ordered<T> && (Minimum <= Maximum)
class Range_Value {
public:
using value_type = T;
static constexpr T minimum = Minimum;
static constexpr T maximum = Maximum;
constexpr explicit Range_Value(const T& value) : value_(checked(value)) {}
constexpr Range_Value(const Range_Value&) = default;
constexpr Range_Value(Range_Value&&) noexcept(std::is_nothrow_move_constructible_v<T>) = default;
constexpr Range_Value& operator=(const Range_Value&) = default;
constexpr Range_Value& operator=(Range_Value&&) noexcept(std::is_nothrow_move_assignable_v<T>) = default;
constexpr Range_Value& operator=(const T& value) {
value_ = checked(value);
return *this;
}
constexpr const T& value() const noexcept {
return value_;
}
constexpr operator const T&() const noexcept {
return value_;
}
private:
static constexpr T checked(const T& value) {
if (value < Minimum || value > Maximum) {
throw std::out_of_range("value is outside the declared range");
}
return value;
}
T value_;
};
template <class T, class Validator>
requires std::default_initializable<Validator> && std::invocable<const Validator&, const T&>
class Validated_Value {
public:
using value_type = T;
using validator_type = Validator;
constexpr explicit Validated_Value(const T& value) : value_(checked(value)) {}
constexpr Validated_Value(const Validated_Value&) = default;
constexpr Validated_Value(Validated_Value&&) noexcept(std::is_nothrow_move_constructible_v<T>) = default;
constexpr Validated_Value& operator=(const Validated_Value&) = default;
constexpr Validated_Value& operator=(Validated_Value&&) noexcept(std::is_nothrow_move_assignable_v<T>) = default;
constexpr Validated_Value& operator=(const T& value) {
value_ = checked(value);
return *this;
}
constexpr const T& value() const noexcept {
return value_;
}
constexpr operator const T&() const noexcept {
return value_;
}
private:
static constexpr T checked(const T& value) {
Validator{}(value);
return value;
}
T value_;
};
template <class T>
struct Is_Range_Value : std::false_type {};
template <class T, T Minimum, T Maximum>
struct Is_Range_Value<Range_Value<T, Minimum, Maximum>> : std::true_type {};
template <class T>
concept Range_Value_Type = Is_Range_Value<std::remove_cvref_t<T>>::value;
template <class T>
struct Is_Validated_Value : std::false_type {};
template <class T, class Validator>
struct Is_Validated_Value<Validated_Value<T, Validator>> : std::true_type {};
template <class T>
concept Validated_Value_Type = Is_Validated_Value<std::remove_cvref_t<T>>::value;
template <class T>
struct Unwrapped_Value {
using type = std::remove_cvref_t<T>;
};
template <class T, T Minimum, T Maximum>
struct Unwrapped_Value<Range_Value<T, Minimum, Maximum>> : Unwrapped_Value<T> {};
template <class T, class Validator>
struct Unwrapped_Value<Validated_Value<T, Validator>> : Unwrapped_Value<T> {};
template <class T>
using Unwrapped_Value_Type = typename Unwrapped_Value<std::remove_cvref_t<T>>::type;
template <class T, T Minimum, T Maximum, class Json>
struct Value_Adapter<Range_Value<T, Minimum, Maximum>, Json> {
using value_type = T;
static constexpr T minimum = Minimum;
static constexpr T maximum = Maximum;
static const T& read(const Range_Value<T, Minimum, Maximum>& value) noexcept {
return value.value();
}
static void write(Range_Value<T, Minimum, Maximum>& target, T value) {
target = value;
}
};
template <class Validator, class = void>
struct Validator_Multiple_Of_Metadata {};
template <class Validator>
struct Validator_Multiple_Of_Metadata<Validator, std::void_t<decltype(Validator::multiple_of)>> {
static constexpr auto multiple_of = Validator::multiple_of;
};
template <class Validator, class = void>
struct Validator_Message_Metadata {};
template <class Validator>
struct Validator_Message_Metadata<Validator, std::void_t<decltype(Validator::message)>> {
static constexpr std::string_view validation_message = Validator::message;
};
template <class T, class Validator, class Json>
struct Value_Adapter<Validated_Value<T, Validator>, Json> : Validator_Multiple_Of_Metadata<Validator>, Validator_Message_Metadata<Validator> {
using value_type = T;
static const T& read(const Validated_Value<T, Validator>& value) noexcept {
return value.value();
}
static void write(Validated_Value<T, Validator>& target, T value) {
target = value;
}
};
}