125 lines
4.7 KiB
C++
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;
|
|
}
|
|
};
|
|
}
|