204 lines
8.3 KiB
C++
204 lines
8.3 KiB
C++
#pragma once
|
|
#include <concepts>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <vector>
|
|
namespace adminive {
|
|
template <class T>
|
|
struct Reflection_Adapter;
|
|
template <class T>
|
|
struct Object_Adapter {
|
|
using model_type = std::remove_cvref_t<T>;
|
|
static model_type snapshot(const model_type& value) requires std::copy_constructible<model_type> {
|
|
return value;
|
|
}
|
|
static model_type create() requires std::default_initializable<model_type> {
|
|
return {};
|
|
}
|
|
static void commit(model_type& target, model_type value) requires std::assignable_from<model_type&, model_type> {
|
|
target = std::move(value);
|
|
}
|
|
};
|
|
template <class T>
|
|
using Object_Model_Type = typename Object_Adapter<std::remove_cvref_t<T>>::model_type;
|
|
template <class T>
|
|
concept Object_Adapter_With_Snapshot = requires(const std::remove_cvref_t<T>& value) {
|
|
{ Object_Adapter<std::remove_cvref_t<T>>::snapshot(value) } -> std::same_as<Object_Model_Type<T>>;
|
|
};
|
|
template <class T>
|
|
concept Object_Adapter_With_Create = requires {
|
|
{ Object_Adapter<std::remove_cvref_t<T>>::create() } -> std::same_as<Object_Model_Type<T>>;
|
|
};
|
|
template <class T>
|
|
concept Object_Adapter_With_Commit = requires(std::remove_cvref_t<T>& target, Object_Model_Type<T> value) {
|
|
Object_Adapter<std::remove_cvref_t<T>>::commit(target, std::move(value));
|
|
};
|
|
template <class Json>
|
|
struct Json_Adapter;
|
|
template <class Json>
|
|
concept Json_Type = requires(Json value, const Json const_value, std::string key, std::string_view text, std::size_t index) {
|
|
{ Json_Adapter<Json>::object() } -> std::same_as<Json>;
|
|
{ Json_Adapter<Json>::array() } -> std::same_as<Json>;
|
|
{ Json_Adapter<Json>::parse(text) } -> std::same_as<Json>;
|
|
{ Json_Adapter<Json>::dump(const_value, 2) } -> std::same_as<std::string>;
|
|
{ Json_Adapter<Json>::is_object(const_value) } -> std::same_as<bool>;
|
|
{ Json_Adapter<Json>::is_array(const_value) } -> std::same_as<bool>;
|
|
{ Json_Adapter<Json>::is_string(const_value) } -> std::same_as<bool>;
|
|
{ Json_Adapter<Json>::is_number(const_value) } -> std::same_as<bool>;
|
|
{ Json_Adapter<Json>::is_boolean(const_value) } -> std::same_as<bool>;
|
|
{ Json_Adapter<Json>::number(const_value) } -> std::convertible_to<long double>;
|
|
{ Json_Adapter<Json>::contains(const_value, text) } -> std::same_as<bool>;
|
|
{ Json_Adapter<Json>::size(const_value) } -> std::convertible_to<std::size_t>;
|
|
{ Json_Adapter<Json>::keys(const_value) } -> std::same_as<std::vector<std::string>>;
|
|
{ Json_Adapter<Json>::at(value, text) } -> std::same_as<Json&>;
|
|
{ Json_Adapter<Json>::at(const_value, text) } -> std::same_as<const Json&>;
|
|
{ Json_Adapter<Json>::at(value, index) } -> std::same_as<Json&>;
|
|
{ Json_Adapter<Json>::at(const_value, index) } -> std::same_as<const Json&>;
|
|
Json_Adapter<Json>::set(value, text, Json{});
|
|
Json_Adapter<Json>::append(value, Json{});
|
|
Json_Adapter<Json>::erase(value, text);
|
|
};
|
|
template <class Json>
|
|
Json json_object() {
|
|
return Json_Adapter<Json>::object();
|
|
}
|
|
template <class Json>
|
|
Json json_array() {
|
|
return Json_Adapter<Json>::array();
|
|
}
|
|
template <class Json, class T>
|
|
Json json_scalar(T&& value) {
|
|
return Json_Adapter<Json>::make(std::forward<T>(value));
|
|
}
|
|
template <class Json, class T>
|
|
void json_set(Json& object, std::string_view name, T&& value) {
|
|
if constexpr(std::same_as<std::remove_cvref_t<T>, Json>) {
|
|
Json_Adapter<Json>::set(object, name, std::forward<T>(value));
|
|
} else {
|
|
Json_Adapter<Json>::set(object, name, json_scalar<Json>(std::forward<T>(value)));
|
|
}
|
|
}
|
|
template <class Json, class T>
|
|
void json_append(Json& array, T&& value) {
|
|
if constexpr(std::same_as<std::remove_cvref_t<T>, Json>) {
|
|
Json_Adapter<Json>::append(array, std::forward<T>(value));
|
|
} else {
|
|
Json_Adapter<Json>::append(array, json_scalar<Json>(std::forward<T>(value)));
|
|
}
|
|
}
|
|
template <class Json, class T>
|
|
T json_get(const Json& value) {
|
|
return Json_Adapter<Json>::template get<T>(value);
|
|
}
|
|
template <class Json>
|
|
Json parse_json(std::string_view value) {
|
|
return Json_Adapter<Json>::parse(value);
|
|
}
|
|
template <class Json>
|
|
std::string dump_json(const Json& value, int indent = -1) {
|
|
return Json_Adapter<Json>::dump(value, indent);
|
|
}
|
|
template <class T, class Json>
|
|
struct Value_Adapter {
|
|
using value_type = std::remove_cvref_t<T>;
|
|
static const value_type& read(const value_type& value) noexcept {
|
|
return value;
|
|
}
|
|
static void write(value_type& target, value_type value) {
|
|
target = std::move(value);
|
|
}
|
|
};
|
|
template <class T, class Json>
|
|
using Adapted_Value_Type = typename Value_Adapter<std::remove_cvref_t<T>, Json>::value_type;
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Encode = requires(const std::remove_cvref_t<T>& value) {
|
|
{ Value_Adapter<std::remove_cvref_t<T>, Json>::encode(value) } -> std::same_as<Json>;
|
|
};
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Decode = requires(std::remove_cvref_t<T>& target, const Json& value) {
|
|
Value_Adapter<std::remove_cvref_t<T>, Json>::decode(target, value);
|
|
};
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Type_Name = requires {
|
|
{ Value_Adapter<std::remove_cvref_t<T>, Json>::type_name } -> std::convertible_to<std::string_view>;
|
|
};
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Schema = requires(Json& value) {
|
|
Value_Adapter<std::remove_cvref_t<T>, Json>::append_schema(value);
|
|
};
|
|
template <class T, class Json>
|
|
decltype(auto) read_adapted_value(const T& value) {
|
|
return Value_Adapter<std::remove_cvref_t<T>, Json>::read(value);
|
|
}
|
|
template <class T, class Json>
|
|
void write_adapted_value(T& target, Adapted_Value_Type<T, Json> value) {
|
|
Value_Adapter<std::remove_cvref_t<T>, Json>::write(target, std::move(value));
|
|
}
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Minimum = requires {
|
|
{ Value_Adapter<std::remove_cvref_t<T>, Json>::minimum };
|
|
};
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Maximum = requires {
|
|
{ Value_Adapter<std::remove_cvref_t<T>, Json>::maximum };
|
|
};
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Multiple_Of = requires {
|
|
{ Value_Adapter<std::remove_cvref_t<T>, Json>::multiple_of };
|
|
};
|
|
template <class T, class Json>
|
|
concept Value_Adapter_With_Validation_Message = requires {
|
|
{ Value_Adapter<std::remove_cvref_t<T>, Json>::validation_message } -> std::convertible_to<std::string_view>;
|
|
};
|
|
template <class T, class Json>
|
|
struct Control_Adapter {};
|
|
struct Control_Context {
|
|
std::string_view permission;
|
|
std::string_view prefix;
|
|
};
|
|
template <class T, class Json>
|
|
concept Control_Adapter_With_Control = requires(const Json& field, Control_Context context) {
|
|
{ Control_Adapter<std::remove_cvref_t<T>, Json>::make_control(field, context) } -> std::same_as<Json>;
|
|
};
|
|
template <class T, class Json>
|
|
concept Control_Adapter_With_Column = requires(const Json& field) {
|
|
{ Control_Adapter<std::remove_cvref_t<T>, Json>::make_column(field) } -> std::same_as<Json>;
|
|
};
|
|
template <class T, class Json>
|
|
struct Polymorphic_Adapter;
|
|
template <class T, class Json>
|
|
concept Polymorphic_Type = requires(const std::remove_cvref_t<T>& value, std::remove_cvref_t<T>& target, const Json& input) {
|
|
{ Polymorphic_Adapter<std::remove_cvref_t<T>, Json>::descriptor() } -> std::same_as<Json>;
|
|
{ Polymorphic_Adapter<std::remove_cvref_t<T>, Json>::encode(value) } -> std::same_as<Json>;
|
|
Polymorphic_Adapter<std::remove_cvref_t<T>, Json>::decode(target, input);
|
|
};
|
|
template <class Enum>
|
|
struct Enum_Adapter;
|
|
template <class Enum>
|
|
concept Enum_Type = std::is_enum_v<Enum> && requires(Enum value, std::string_view name) {
|
|
{ Enum_Adapter<Enum>::values() };
|
|
{ Enum_Adapter<Enum>::name(value) } -> std::convertible_to<std::string_view>;
|
|
{ Enum_Adapter<Enum>::cast(name) } -> std::same_as<std::optional<Enum>>;
|
|
};
|
|
template <Enum_Type Enum>
|
|
auto enum_values() {
|
|
return Enum_Adapter<Enum>::values();
|
|
}
|
|
template <Enum_Type Enum>
|
|
std::string_view enum_name(Enum value) {
|
|
return Enum_Adapter<Enum>::name(value);
|
|
}
|
|
template <Enum_Type Enum>
|
|
std::optional<Enum> enum_cast(std::string_view value) {
|
|
return Enum_Adapter<Enum>::cast(value);
|
|
}
|
|
template <class Enum>
|
|
concept Enum_Adapter_With_Underlying_Cast = Enum_Type<Enum> && requires(std::underlying_type_t<Enum> value) {
|
|
{ Enum_Adapter<Enum>::cast(value) } -> std::same_as<std::optional<Enum>>;
|
|
};
|
|
}
|