Files
Adminive/backend/library/include/adminive/adapter.hpp
T
2026-08-07 09:25:55 +08:00

268 lines
12 KiB
C++

#pragma once
#include <concepts>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
namespace adminive {
enum class Write_Mode {
internal,
create,
update
};
struct Write_Context {
Write_Mode mode{Write_Mode::internal};
bool complete{true};
};
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, class T>
concept Json_Scalar_Makeable = requires(T value) {
{ Json_Adapter<Json>::make(std::move(value)) } -> std::same_as<Json>;
};
template <class Json, class T>
concept Json_Scalar_Gettable = requires(const Json& value) {
{ Json_Adapter<Json>::template get<T>(value) } -> std::same_as<T>;
};
template <class Json>
concept Json_Type = requires(Json value, const Json const_value, 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>::null() } -> 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_null(const_value) } -> std::same_as<bool>;
{ 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_signed_integer(const_value) } -> std::same_as<bool>;
{ Json_Adapter<Json>::is_unsigned_integer(const_value) } -> std::same_as<bool>;
{ Json_Adapter<Json>::is_floating_point(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>::signed_integer(const_value) } -> std::same_as<std::int64_t>;
{ Json_Adapter<Json>::unsigned_integer(const_value) } -> std::same_as<std::uint64_t>;
{ 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);
} && Json_Scalar_Makeable<Json, bool> && Json_Scalar_Makeable<Json, std::int64_t> && Json_Scalar_Makeable<Json, std::uint64_t> && Json_Scalar_Makeable<Json, double> && Json_Scalar_Makeable<Json, std::string> && Json_Scalar_Gettable<Json, bool> && Json_Scalar_Gettable<Json, std::int64_t> && Json_Scalar_Gettable<Json, std::uint64_t> && Json_Scalar_Gettable<Json, double> && Json_Scalar_Gettable<Json, std::string>;
template <Json_Type Json>
Json json_object() {
return Json_Adapter<Json>::object();
}
template <Json_Type Json>
Json json_array() {
return Json_Adapter<Json>::array();
}
template <Json_Type Json>
Json json_null() {
return Json_Adapter<Json>::null();
}
template <Json_Type Json, class T>
Json json_scalar(T&& value) {
using Value = std::remove_cvref_t<T>;
if constexpr(std::is_array_v<Value> && std::same_as<std::remove_cv_t<std::remove_extent_t<Value>>, char>) {
return Json_Adapter<Json>::make(std::string(value));
} else if constexpr(std::same_as<Value, const char*> || std::same_as<Value, char*> || std::same_as<Value, std::string_view>) {
return Json_Adapter<Json>::make(std::string(value));
} else if constexpr(std::signed_integral<Value> && !std::same_as<Value, bool>) {
return Json_Adapter<Json>::make(static_cast<std::int64_t>(value));
} else if constexpr(std::unsigned_integral<Value> && !std::same_as<Value, bool>) {
return Json_Adapter<Json>::make(static_cast<std::uint64_t>(value));
} else if constexpr(std::floating_point<Value>) {
return Json_Adapter<Json>::make(static_cast<double>(value));
} else {
static_assert(Json_Scalar_Makeable<Json, Value>, "JSON adapter cannot construct this scalar type");
return Json_Adapter<Json>::make(std::forward<T>(value));
}
}
template <Json_Type 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 <Json_Type 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 <Json_Type Json, class T>
T json_get(const Json& value) {
if constexpr(std::signed_integral<T> && !std::same_as<T, bool>) {
return static_cast<T>(Json_Adapter<Json>::template get<std::int64_t>(value));
} else if constexpr(std::unsigned_integral<T> && !std::same_as<T, bool>) {
return static_cast<T>(Json_Adapter<Json>::template get<std::uint64_t>(value));
} else if constexpr(std::floating_point<T>) {
return static_cast<T>(Json_Adapter<Json>::template get<double>(value));
} else {
static_assert(Json_Scalar_Gettable<Json, T>, "JSON adapter cannot extract this scalar type");
return Json_Adapter<Json>::template get<T>(value);
}
}
template <Json_Type Json>
Json parse_json(std::string_view value) {
return Json_Adapter<Json>::parse(value);
}
template <Json_Type 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>
struct Polymorphic_Variant {
using type = T;
std::string value;
std::string label;
};
template <class T>
auto polymorphic_variant(std::string value, std::string label) {
return Polymorphic_Variant<T>{std::move(value), std::move(label)};
}
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, Write_Context context) {
{ Polymorphic_Adapter<std::remove_cvref_t<T>, Json>::discriminator() } -> std::convertible_to<std::string_view>;
{ Polymorphic_Adapter<std::remove_cvref_t<T>, Json>::discriminator_label() } -> std::convertible_to<std::string_view>;
{ Polymorphic_Adapter<std::remove_cvref_t<T>, Json>::variants() };
{ 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, context);
};
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>>;
};
}