#pragma once #include #include #include #include #include #include #include #include #include namespace adminive { enum class Write_Mode { internal, create, update }; struct Write_Context { Write_Mode mode{Write_Mode::internal}; bool complete{true}; }; template struct Reflection_Adapter; template struct Object_Adapter { using model_type = std::remove_cvref_t; static model_type snapshot(const model_type& value) requires std::copy_constructible { return value; } static model_type create() requires std::default_initializable { return {}; } static void commit(model_type& target, model_type value) requires std::assignable_from { target = std::move(value); } }; template using Object_Model_Type = typename Object_Adapter>::model_type; template concept Object_Adapter_With_Snapshot = requires(const std::remove_cvref_t& value) { { Object_Adapter>::snapshot(value) } -> std::same_as>; }; template concept Object_Adapter_With_Create = requires { { Object_Adapter>::create() } -> std::same_as>; }; template concept Object_Adapter_With_Commit = requires(std::remove_cvref_t& target, Object_Model_Type value) { Object_Adapter>::commit(target, std::move(value)); }; template struct Json_Adapter; template concept Json_Scalar_Makeable = requires(T value) { { Json_Adapter::make(std::move(value)) } -> std::same_as; }; template concept Json_Scalar_Gettable = requires(const Json& value) { { Json_Adapter::template get(value) } -> std::same_as; }; template concept Json_Type = requires(Json value, const Json const_value, std::string_view text, std::size_t index) { { Json_Adapter::object() } -> std::same_as; { Json_Adapter::array() } -> std::same_as; { Json_Adapter::null() } -> std::same_as; { Json_Adapter::parse(text) } -> std::same_as; { Json_Adapter::dump(const_value, 2) } -> std::same_as; { Json_Adapter::is_null(const_value) } -> std::same_as; { Json_Adapter::is_object(const_value) } -> std::same_as; { Json_Adapter::is_array(const_value) } -> std::same_as; { Json_Adapter::is_string(const_value) } -> std::same_as; { Json_Adapter::is_signed_integer(const_value) } -> std::same_as; { Json_Adapter::is_unsigned_integer(const_value) } -> std::same_as; { Json_Adapter::is_floating_point(const_value) } -> std::same_as; { Json_Adapter::is_number(const_value) } -> std::same_as; { Json_Adapter::is_boolean(const_value) } -> std::same_as; { Json_Adapter::signed_integer(const_value) } -> std::same_as; { Json_Adapter::unsigned_integer(const_value) } -> std::same_as; { Json_Adapter::number(const_value) } -> std::convertible_to; { Json_Adapter::contains(const_value, text) } -> std::same_as; { Json_Adapter::size(const_value) } -> std::convertible_to; { Json_Adapter::keys(const_value) } -> std::same_as>; { Json_Adapter::at(value, text) } -> std::same_as; { Json_Adapter::at(const_value, text) } -> std::same_as; { Json_Adapter::at(value, index) } -> std::same_as; { Json_Adapter::at(const_value, index) } -> std::same_as; Json_Adapter::set(value, text, Json{}); Json_Adapter::append(value, Json{}); Json_Adapter::erase(value, text); } && Json_Scalar_Makeable && Json_Scalar_Makeable && Json_Scalar_Makeable && Json_Scalar_Makeable && Json_Scalar_Makeable && Json_Scalar_Gettable && Json_Scalar_Gettable && Json_Scalar_Gettable && Json_Scalar_Gettable && Json_Scalar_Gettable; template Json json_object() { return Json_Adapter::object(); } template Json json_array() { return Json_Adapter::array(); } template Json json_null() { return Json_Adapter::null(); } template Json json_scalar(T&& value) { using Value = std::remove_cvref_t; if constexpr(std::is_array_v && std::same_as>, char>) { return Json_Adapter::make(std::string(value)); } else if constexpr(std::same_as || std::same_as || std::same_as) { return Json_Adapter::make(std::string(value)); } else if constexpr(std::signed_integral && !std::same_as) { return Json_Adapter::make(static_cast(value)); } else if constexpr(std::unsigned_integral && !std::same_as) { return Json_Adapter::make(static_cast(value)); } else if constexpr(std::floating_point) { return Json_Adapter::make(static_cast(value)); } else { static_assert(Json_Scalar_Makeable, "JSON adapter cannot construct this scalar type"); return Json_Adapter::make(std::forward(value)); } } template void json_set(Json& object, std::string_view name, T&& value) { if constexpr(std::same_as, Json>) { Json_Adapter::set(object, name, std::forward(value)); } else { Json_Adapter::set(object, name, json_scalar(std::forward(value))); } } template void json_append(Json& array, T&& value) { if constexpr(std::same_as, Json>) { Json_Adapter::append(array, std::forward(value)); } else { Json_Adapter::append(array, json_scalar(std::forward(value))); } } template T json_get(const Json& value) { if constexpr(std::signed_integral && !std::same_as) { return static_cast(Json_Adapter::template get(value)); } else if constexpr(std::unsigned_integral && !std::same_as) { return static_cast(Json_Adapter::template get(value)); } else if constexpr(std::floating_point) { return static_cast(Json_Adapter::template get(value)); } else { static_assert(Json_Scalar_Gettable, "JSON adapter cannot extract this scalar type"); return Json_Adapter::template get(value); } } template Json parse_json(std::string_view value) { return Json_Adapter::parse(value); } template std::string dump_json(const Json& value, int indent = -1) { return Json_Adapter::dump(value, indent); } template struct Value_Adapter { using value_type = std::remove_cvref_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 using Adapted_Value_Type = typename Value_Adapter, Json>::value_type; template concept Value_Adapter_With_Encode = requires(const std::remove_cvref_t& value) { { Value_Adapter, Json>::encode(value) } -> std::same_as; }; template concept Value_Adapter_With_Decode = requires(std::remove_cvref_t& target, const Json& value) { Value_Adapter, Json>::decode(target, value); }; template concept Value_Adapter_With_Type_Name = requires { { Value_Adapter, Json>::type_name } -> std::convertible_to; }; template concept Value_Adapter_With_Schema = requires(Json& value) { Value_Adapter, Json>::append_schema(value); }; template decltype(auto) read_adapted_value(const T& value) { return Value_Adapter, Json>::read(value); } template void write_adapted_value(T& target, Adapted_Value_Type value) { Value_Adapter, Json>::write(target, std::move(value)); } template concept Value_Adapter_With_Minimum = requires { { Value_Adapter, Json>::minimum }; }; template concept Value_Adapter_With_Maximum = requires { { Value_Adapter, Json>::maximum }; }; template concept Value_Adapter_With_Multiple_Of = requires { { Value_Adapter, Json>::multiple_of }; }; template concept Value_Adapter_With_Validation_Message = requires { { Value_Adapter, Json>::validation_message } -> std::convertible_to; }; template struct Control_Adapter {}; struct Control_Context { std::string_view permission; std::string_view prefix; }; template concept Control_Adapter_With_Control = requires(const Json& field, Control_Context context) { { Control_Adapter, Json>::make_control(field, context) } -> std::same_as; }; template concept Control_Adapter_With_Column = requires(const Json& field) { { Control_Adapter, Json>::make_column(field) } -> std::same_as; }; template struct Polymorphic_Variant { using type = T; std::string value; std::string label; }; template auto polymorphic_variant(std::string value, std::string label) { return Polymorphic_Variant{std::move(value), std::move(label)}; } template struct Polymorphic_Adapter; template concept Polymorphic_Type = requires(const std::remove_cvref_t& value, std::remove_cvref_t& target, const Json& input, Write_Context context) { { Polymorphic_Adapter, Json>::discriminator() } -> std::convertible_to; { Polymorphic_Adapter, Json>::discriminator_label() } -> std::convertible_to; { Polymorphic_Adapter, Json>::variants() }; { Polymorphic_Adapter, Json>::encode(value) } -> std::same_as; Polymorphic_Adapter, Json>::decode(target, input, context); }; template struct Enum_Adapter; template concept Enum_Type = std::is_enum_v && requires(Enum value, std::string_view name) { { Enum_Adapter::values() }; { Enum_Adapter::name(value) } -> std::convertible_to; { Enum_Adapter::cast(name) } -> std::same_as>; }; template auto enum_values() { return Enum_Adapter::values(); } template std::string_view enum_name(Enum value) { return Enum_Adapter::name(value); } template std::optional enum_cast(std::string_view value) { return Enum_Adapter::cast(value); } template concept Enum_Adapter_With_Underlying_Cast = Enum_Type && requires(std::underlying_type_t value) { { Enum_Adapter::cast(value) } -> std::same_as>; }; }