-
Notifications
You must be signed in to change notification settings - Fork 350
feat formats: automatic serialization/deserialization based on Boost.PFR #469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
3734a3a
98cbcd5
a81e72c
0713f28
ae1a121
ae50c13
3bc80be
f10b540
f26b380
14b391b
2c4db8d
7307548
564d424
ec4360f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
|
|
||
linuxnyasha marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #pragma once | ||
| #include <userver/formats/universal/universal.hpp> | ||
| #include <userver/formats/json.hpp> | ||
linuxnyasha marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #include <type_traits> | ||
|
|
||
| USERVER_NAMESPACE_BEGIN | ||
| namespace formats::json { | ||
|
|
||
| template <typename T> | ||
| inline constexpr | ||
| std::enable_if_t<!std::is_same_v<decltype(universal::kSerialization<std::remove_cvref_t<T>>), const universal::detail::Disabled>, Value> | ||
| Serialize(T&& obj, | ||
| serialize::To<Value>) { | ||
| using Config = std::remove_const_t<decltype(universal::kSerialization<std::remove_cvref_t<T>>)>; | ||
| using Type = std::remove_cvref_t<T>; | ||
| return [&]<typename... Params> | ||
| (universal::SerializationConfig<Type, Params...>){ | ||
| ValueBuilder builder; | ||
| (universal::detail::UniversalSerializeField(Params{}, builder, obj), ...); | ||
| return builder.ExtractValue(); | ||
| }(Config{}); | ||
| }; | ||
|
|
||
|
|
||
| } // namespace formats::json | ||
| USERVER_NAMESPACE_END | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #pragma once | ||
| #include <type_traits> | ||
| #include <string> | ||
| #include <cstdint> | ||
| #include <userver/formats/parse/to.hpp> | ||
| #include <userver/utils/meta.hpp> | ||
| #include <userver/utils/type_list.hpp> | ||
| #include <userver/formats/common/meta.hpp> | ||
|
|
||
| USERVER_NAMESPACE_BEGIN | ||
|
|
||
| namespace formats::parse { | ||
|
|
||
| namespace impl { | ||
|
|
||
| template <typename T, typename Value> | ||
| inline bool Is(Value&& value) { | ||
| if constexpr(std::is_convertible_v<T, std::int64_t>) { | ||
linuxnyasha marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return value.IsInt(); | ||
| } else if constexpr(std::is_convertible_v<T, std::string>) { | ||
| return value.IsString(); | ||
| } else if constexpr(requires {std::begin(std::declval<T>());}) { | ||
| return value.IsArray(); | ||
| } else if constexpr(std::is_convertible_v<bool, T>) { | ||
| return value.IsBool(); | ||
| } else { | ||
| return value.IsObject(); | ||
| } | ||
| } | ||
|
|
||
| inline constexpr utils::TypeList<bool, int, std::int64_t, std::uint64_t, double, std::string> kBaseTypes; | ||
|
|
||
|
|
||
| } // namespace impl | ||
|
|
||
|
|
||
| template <typename T, typename Value> | ||
| inline std::enable_if_t<utils::AnyOf(utils::IsSameCarried<T>(), impl::kBaseTypes), std::optional<T>> | ||
Anton3 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| TryParse(Value&& value, userver::formats::parse::To<T>) { | ||
| if(value.IsMissing() || value.IsNull() || !impl::Is<T>(value)) { | ||
Anton3 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return std::nullopt; | ||
| } | ||
| return value.template As<T>(); | ||
| } | ||
|
|
||
| template <typename T, typename Value> | ||
| inline std::optional<T> TryParse(Value&& value, userver::formats::parse::To<std::optional<T>>) { | ||
| return TryParse(std::forward<Value>(value), userver::formats::parse::To<T>{}); | ||
Anton3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }; | ||
|
|
||
| } // namespace formats::parse | ||
|
|
||
| USERVER_NAMESPACE_END | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
|
|
||
| #pragma once | ||
| #include <userver/formats/universal/universal.hpp> | ||
| #include <userver/utils/regex.hpp> | ||
| #include <fmt/format.h> | ||
| #include <map> | ||
|
|
||
| USERVER_NAMESPACE_BEGIN | ||
| namespace formats::universal { | ||
|
|
||
| template <auto Value> | ||
| struct Min { | ||
linuxnyasha marked this conversation as resolved.
Show resolved
Hide resolved
Anton3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| static constexpr auto kValue = Value; | ||
| }; | ||
|
|
||
| template <auto Value> | ||
| struct Max { | ||
| static constexpr auto kValue = Value; | ||
| }; | ||
|
|
||
| template <auto Value> | ||
| struct Default { | ||
| static constexpr auto kValue = Value; | ||
| }; | ||
|
|
||
| template <utils::ConstexprString Regex> | ||
| struct Pattern { | ||
| static constexpr auto kValue = Regex; | ||
| }; | ||
|
|
||
| struct Additional {}; | ||
|
|
||
| template <typename Field, auto Value> | ||
| constexpr inline auto Check(const Field& field, Max<Value>) noexcept { | ||
| return Value >= field; | ||
| }; | ||
|
|
||
| template <typename Field, auto Value> | ||
| constexpr inline auto Check(const Field& field, Min<Value>) noexcept { | ||
| return field >= Value; | ||
| }; | ||
|
|
||
| template <typename Field, auto Value> | ||
| constexpr inline auto Check(const Field&, Default<Value>) noexcept { | ||
| return true; | ||
| }; | ||
|
|
||
| template <utils::ConstexprString Regex> | ||
| static const userver::utils::regex kRegex(Regex); | ||
|
|
||
| template <utils::ConstexprString Regex> | ||
| constexpr inline auto Check(const std::string& field, Pattern<Regex>) noexcept { | ||
| return utils::regex_match(field, kRegex<Regex>); | ||
| }; | ||
|
|
||
| template <typename Field, auto Value> | ||
| constexpr inline auto Check(const std::optional<Field>&, Default<Value>) noexcept { | ||
| return true; | ||
| }; | ||
|
|
||
| template <typename Field> | ||
| constexpr inline auto Check(const Field&, Additional) noexcept { | ||
| return true; | ||
| }; | ||
|
|
||
| template <typename Key, auto Value> | ||
| constexpr inline auto Check(const std::vector<Key>& field, Max<Value>) noexcept { | ||
| return Value >= field.size(); | ||
| }; | ||
|
|
||
| template <typename Key, typename Tp, auto Value> | ||
| constexpr inline auto Check(const std::map<Key, Tp>& field, Max<Value>) noexcept { | ||
| return Value >= field.size(); | ||
| }; | ||
|
|
||
| template <typename Key, typename Tp, auto Value> | ||
| constexpr inline auto Check(const std::unordered_map<Key, Tp>& field, Max<Value>) noexcept { | ||
| return Value >= field.size(); | ||
| }; | ||
|
|
||
| template <typename Field, typename CheckT> | ||
| constexpr inline bool Check(const std::optional<Field>& field, CheckT check) noexcept { | ||
| if(field.has_value()) { | ||
| return Check(*field, check); | ||
| }; | ||
| return true; | ||
| }; | ||
|
|
||
| template <typename T, auto I, typename Key, typename Value, auto Maximum> | ||
| constexpr inline auto ErrorMessage(const std::unordered_map<Key, Value>& field, Max<Maximum>) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Everything that is not used by the user of the library, should be moved into Everything that IS used, should be documented. Let's at least add some brief single-phrase |
||
| return fmt::format("Error with field {0} Map size: {1} Maximum Size: {2}", boost::pfr::get_name<I, T>(), field.size(), Maximum); | ||
| }; | ||
|
|
||
| template <typename T, auto I, typename Field, template <auto> typename Check, auto Value> | ||
| constexpr inline auto ErrorMessage(const Field& field, Check<Value>) { | ||
| return fmt::format("Error with field {0} Field value: {1} Check Value: {2}", boost::pfr::get_name<I, T>(), field, Value); | ||
| }; | ||
|
|
||
|
|
||
| template <typename T, auto I, typename Value, typename Check> | ||
| constexpr inline auto ErrorMessage(const std::unordered_map<std::string, Value>&, Additional) { | ||
| return "Error"; | ||
| }; | ||
|
|
||
| template <typename T, auto I, typename Field, typename Check> | ||
| constexpr inline auto ErrorMessage(const Field&, Check) { | ||
| return "Error"; | ||
| }; | ||
|
|
||
| template <typename T, auto I, typename Field, template <auto> typename Check, auto Value> | ||
| constexpr inline auto ErrorMessage(const std::optional<Field>& field, Check<Value> check) { | ||
| return ErrorMessage<T, I>(*field, check); | ||
| }; | ||
|
|
||
| } // namespace formats::universal | ||
|
|
||
| USERVER_NAMESPACE_END | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.