Skip to content

Commit

Permalink
Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
linuxnyasha committed Mar 11, 2024
1 parent 8986d53 commit 8e942ae
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 44 deletions.
49 changes: 25 additions & 24 deletions universal/include/userver/formats/universal/common_containers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <userver/formats/common/items.hpp>
#include <userver/formats/parse/try_parse.hpp>
#include <format>
#include <unordered_map>
#include <userver/utils/regex.hpp>

USERVER_NAMESPACE_BEGIN
Expand Down Expand Up @@ -123,8 +124,8 @@ struct Pattern : public impl::EmptyCheck, public impl::Param<const utils::regex*
}
};

struct Additional : public impl::EmptyCheck, public impl::Param<bool> {
constexpr inline Additional(const bool& value) :
struct AdditionalProperties : public impl::EmptyCheck, public impl::Param<bool> {
constexpr inline AdditionalProperties(const bool& value) :
impl::Param<bool>(value) {}
};

Expand All @@ -147,13 +148,13 @@ struct FieldConfig<std::optional<T>> {
};
return std::nullopt;
}
constexpr auto Write(const std::optional<T>& value, std::string_view fieldName, const auto& names, auto& builder) const {
constexpr auto Write(const std::optional<T>& value, std::string_view field_name, const auto& names, auto& builder) const {
if(value) {
this->Main.Write(*value, fieldName, names, builder);
this->Main.Write(*value, field_name, names, builder);
return;
}
if(this->Default) {
this->Main.Write(this->Default->value(), fieldName, names, builder);
this->Main.Write(this->Default->value(), field_name, names, builder);
return;
}
}
Expand Down Expand Up @@ -202,22 +203,22 @@ struct FieldConfig<std::optional<T>> {
}
};

template <>
struct FieldConfig<int> {
std::optional<Max<int>> Maximum = std::nullopt;
std::optional<Min<int>> Minimum = std::nullopt;
template <typename T>
struct FieldConfig<T, std::enable_if_t<meta::kIsInteger<T> || std::is_floating_point_v<T>>> {
std::optional<Max<T>> Maximum = std::nullopt;
std::optional<Min<T>> Minimum = std::nullopt;
template <typename MainClass, auto I, typename Value>
constexpr int Read(Value&& value) const {
constexpr auto name = boost::pfr::get_name<I, MainClass>();
return value[name].template As<int>();
return value[name].template As<T>();
}
template <typename MainClass, auto I, typename Value>
constexpr std::optional<int> TryRead(Value&& value) const {
constexpr std::optional<T> TryRead(Value&& value) const {
constexpr auto name = boost::pfr::get_name<I, MainClass>();
return parse::TryParse(value[name], parse::To<int>{});
return parse::TryParse(value[name], parse::To<T>{});
}
constexpr auto Write(const int& value, std::string_view fieldName, const auto&, auto& builder) const {
builder[static_cast<std::string>(fieldName)] = value;
constexpr auto Write(const int& value, std::string_view field_name, const auto&, auto& builder) const {
builder[static_cast<std::string>(field_name)] = value;
}
inline constexpr std::optional<std::string> Check(const int&) const {
return std::nullopt;
Expand All @@ -236,8 +237,8 @@ struct FieldConfig<std::string> {
constexpr auto name = boost::pfr::get_name<I, MainClass>();
return parse::TryParse(value[name], parse::To<std::string>{});
}
constexpr auto Write(std::string_view value, std::string_view fieldName, const auto&, auto& builder) const {
builder[static_cast<std::string>(fieldName)] = value;
constexpr auto Write(std::string_view value, std::string_view field_name, const auto&, auto& builder) const {
builder[static_cast<std::string>(field_name)] = value;
}
inline constexpr std::optional<std::string> Check(std::string_view) const {
return std::nullopt;
Expand All @@ -247,13 +248,13 @@ struct FieldConfig<std::string> {

template <typename Value>
struct FieldConfig<std::unordered_map<std::string, Value>> {
std::optional<Additional> Additional = std::nullopt;
std::optional<AdditionalProperties> AdditionalProperties = std::nullopt;
FieldConfig<Value> Items = {};
using Type = std::unordered_map<std::string, Value>;
template <typename MainClass, auto I, typename Value2>
inline constexpr Type Read(Value2&& value) const {
Type response;
if(this->Additional) {
if(this->AdditionalProperties) {
constexpr auto fields = boost::pfr::names_as_array<MainClass>();
for(const auto& [name, value] : userver::formats::common::Items(std::forward<Value2>(value))) {
auto it = std::find(fields.begin(), fields.end(), name);
Expand All @@ -272,7 +273,7 @@ struct FieldConfig<std::unordered_map<std::string, Value>> {
template <typename MainClass, auto I, typename Value2>
inline constexpr std::optional<Type> TryRead(Value2&& value) const {
Type response;
if(this->Additional) {
if(this->AdditionalProperties) {
constexpr auto fields = boost::pfr::names_as_array<MainClass>();
for(const auto& [name, value] : userver::formats::common::Items(std::forward<Value2>(value))) {
if(std::find(fields.begin(), fields.end(), name) == fields.end()) {
Expand All @@ -285,8 +286,8 @@ struct FieldConfig<std::unordered_map<std::string, Value>> {
}
return response;
}
constexpr auto fieldName = boost::pfr::get_name<I, MainClass>();
for(const auto& [name, value] : userver::formats::common::Items(value[fieldName])) {
constexpr auto field_name = boost::pfr::get_name<I, MainClass>();
for(const auto& [name, value] : userver::formats::common::Items(value[field_name])) {
auto New = parse::TryParse(value, parse::To<Value>{});
if(!New) {
return std::nullopt;
Expand All @@ -310,8 +311,8 @@ struct FieldConfig<std::unordered_map<std::string, Value>> {
return error;
}
template <typename Builder>
constexpr auto Write(const Type& value, std::string_view fieldName, const auto&, Builder& builder) const {
if(this->Additional) {
constexpr auto Write(const Type& value, std::string_view field_name, const auto&, Builder& builder) const {
if(this->AdditionalProperties) {
for(const auto& [name, value2] : value) {
builder[name] = value2;
}
Expand All @@ -321,7 +322,7 @@ struct FieldConfig<std::unordered_map<std::string, Value>> {
for(const auto& [name, value2] : value) {
newBuilder[name] = value2;
}
builder[static_cast<std::string>(fieldName)] = newBuilder.ExtractValue();
builder[static_cast<std::string>(field_name)] = newBuilder.ExtractValue();
}
};
template <typename Element>
Expand Down
46 changes: 31 additions & 15 deletions universal/include/userver/formats/universal/universal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,24 @@
#include <userver/formats/serialize/to.hpp>
#include <userver/utils/meta.hpp>
#include <userver/utils/overloaded.hpp>
#include <variant>
#include <type_traits>
#include <boost/pfr.hpp>
#include <boost/pfr/core.hpp>
#include <boost/pfr/core_name.hpp>


USERVER_NAMESPACE_BEGIN

namespace formats::universal {


template <typename T>
template <typename T, typename Enable = void>
struct FieldConfig {
constexpr inline std::optional<std::string> Check(const T&) const {
return std::nullopt;
}
constexpr auto Write(const T& value, std::string_view fieldName, const auto&, auto& builder) const {
builder[static_cast<std::string>(fieldName)] = value;
constexpr auto Write(const T& value, std::string_view field_name, const auto&, auto& builder) const {
builder[static_cast<std::string>(field_name)] = value;
}
template <typename MainClass, auto I, typename Value>
constexpr T Read(Value&& value) const {
Expand All @@ -40,9 +42,9 @@ template <typename T, std::size_t I>
using kFieldTypeOnIndex = std::remove_reference_t<decltype(boost::pfr::get<I>(std::declval<T>()))>;

template <typename T>
consteval std::size_t getFieldIndexByName(std::string_view fieldName) {
consteval std::size_t getFieldIndexByName(std::string_view field_name) {
constexpr auto names = boost::pfr::names_as_array<T>();
return std::find(names.begin(), names.end(), fieldName) - names.begin();
return std::find(names.begin(), names.end(), field_name) - names.begin();
}

struct Disabled {};
Expand Down Expand Up @@ -198,30 +200,44 @@ inline constexpr auto kDeserialization = kSerialization<T>;


template <typename T>
struct SerializationConfig {
using kFieldsConfigType = decltype([]<auto... I>(std::index_sequence<I...>){
class SerializationConfig {
using FieldsConfigType = decltype([]<auto... I>(std::index_sequence<I...>){
return std::type_identity<std::tuple<FieldConfig<impl::kFieldTypeOnIndex<T, I>>...>>();
}(std::make_index_sequence<boost::pfr::tuple_size_v<T>>()))::type;

public:
template <utils::ConstexprString fieldName>
inline constexpr auto& With(FieldConfig<impl::kFieldTypeOnIndex<T, impl::getFieldIndexByName<T>(fieldName)>>&& fieldConfig) {
inline constexpr auto& With(FieldConfig<impl::kFieldTypeOnIndex<T, impl::getFieldIndexByName<T>(fieldName)>>&& field_config) {
constexpr auto Index = impl::getFieldIndexByName<T>(fieldName);
static_assert(Index != boost::pfr::tuple_size_v<T>, "Field Not Found");
std::get<Index>(this->fieldsConfig) = std::move(fieldConfig);
std::get<Index>(this->fields_config) = std::move(field_config);
return *this;
}
constexpr SerializationConfig() : fieldsConfig({}) {}
inline constexpr SerializationConfig() = default;

template <std::size_t I>
constexpr auto Get() const {
return std::get<I>(this->fieldsConfig);
inline constexpr auto Get() const {
return std::get<I>(this->fields_config);
}
private:
kFieldsConfigType fieldsConfig;

FieldsConfigType fields_config = {};
};

template <typename... Ts>
class SerializationConfig<std::variant<Ts...>> {
public:
template <std::size_t I>
inline constexpr auto& With(FieldConfig<decltype(Get<I>(utils::impl::TypeList<Ts...>{}))>&& field_config) {
std::get<I>(this->variant_config) = std::move(field_config);
return *this;
}
template <typename T>
inline constexpr auto& With(FieldConfig<T>&& field_config) {
return this->With<Find<T>(utils::impl::TypeList<Ts...>{})>(std::move(field_config));
}
private:
std::tuple<FieldConfig<Ts>...> variant_config;
};


} // namespace formats::universal
Expand Down
20 changes: 16 additions & 4 deletions universal/include/userver/utils/impl/type_list.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once
#include <type_traits>

#include <utility>

USERVER_NAMESPACE_BEGIN

Expand All @@ -11,13 +11,12 @@ struct TypeList {};


template <typename... Ts>
consteval auto size(TypeList<Ts...>) {
consteval auto Size(TypeList<Ts...>) {
return sizeof...(Ts);
}


template <template <typename...> typename Check, typename... Ts>
consteval auto anyOf(TypeList<Ts...>) {
consteval auto AnyOf(TypeList<Ts...>) {
return (Check<Ts>::value || ...);
}

Expand All @@ -40,6 +39,19 @@ consteval auto IsConvertableCarried() {
};
}

struct Caster {
inline constexpr Caster(auto) {}
inline constexpr Caster() = default;
};

template <std::size_t... Is, typename T>
consteval auto Get(std::index_sequence<Is...>, decltype(Is, Caster())..., T&& arg, ...) -> T;

template <std::size_t I, typename... Ts>
consteval auto Get(const TypeList<Ts...>&) -> decltype(Get(std::make_index_sequence<I>(), std::declval<Ts>()...));



} // namespace utils::impl

USERVER_NAMESPACE_END
Expand Down
2 changes: 1 addition & 1 deletion universal/src/formats/json/universal_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct SomeStruct3 {
template <>
inline constexpr auto formats::universal::kSerialization<SomeStruct3> =
SerializationConfig<SomeStruct3>()
.With<"field">({.Additional = true});
.With<"field">({.AdditionalProperties = true});

TEST(Serialize, Additional) {
std::unordered_map<std::string, int> value;
Expand Down

0 comments on commit 8e942ae

Please sign in to comment.