Skip to content

Commit 3734a3a

Browse files
committed
Add universal serialization and deserialization
1 parent 65d318c commit 3734a3a

File tree

11 files changed

+661
-0
lines changed

11 files changed

+661
-0
lines changed

universal/include/userver/formats/common/meta.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,14 @@ template <typename Value, typename T>
3232
using HasConvert =
3333
decltype(Convert(std::declval<const Value&>(), parse::To<T>{}));
3434

35+
template <typename Value, typename T>
36+
using HasTryParse =
37+
decltype(TryParse(std::declval<const Value&>(), parse::To<T>{}));
38+
3539
template <typename Value>
3640
using IsFormatValue = typename Value::ParseException;
3741

42+
3843
template <class Value, class T>
3944
constexpr inline bool kHasParse = meta::kIsDetected<HasParse, Value, T>;
4045

@@ -44,6 +49,9 @@ constexpr inline bool kHasSerialize = meta::kIsDetected<HasSerialize, Value, T>;
4449
template <class Value, class T>
4550
constexpr inline bool kHasConvert = meta::kIsDetected<HasConvert, Value, T>;
4651

52+
template <class Value, class T>
53+
constexpr inline bool kHasTryParse = meta::kIsDetected<HasTryParse, Value, T>;
54+
4755
} // namespace impl
4856

4957
/// Used in `Parse` overloads that are templated on `Value`, avoids clashing

universal/include/userver/formats/json.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <userver/formats/json/serialize.hpp>
1111
#include <userver/formats/json/value.hpp>
1212
#include <userver/formats/json/value_builder.hpp>
13+
#include <userver/formats/json/universal.hpp>
1314

1415
USERVER_NAMESPACE_BEGIN
1516

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
#pragma once
3+
#include <userver/formats/universal/universal.hpp>
4+
#include <userver/formats/json.hpp>
5+
#include <type_traits>
6+
7+
USERVER_NAMESPACE_BEGIN
8+
namespace formats::json {
9+
10+
template <typename T>
11+
inline constexpr
12+
std::enable_if_t<!std::is_same_v<decltype(universal::kSerialization<std::remove_cvref_t<T>>), const universal::detail::Disabled>, Value>
13+
Serialize(T&& obj,
14+
serialize::To<Value>) {
15+
using Config = std::remove_const_t<decltype(universal::kSerialization<std::remove_cvref_t<T>>)>;
16+
using Type = std::remove_cvref_t<T>;
17+
return [&]<typename... Params>
18+
(universal::SerializationConfig<Type, Params...>){
19+
ValueBuilder builder;
20+
(universal::detail::UniversalSerializeField(Params{}, builder, obj), ...);
21+
return builder.ExtractValue();
22+
}(Config{});
23+
};
24+
25+
26+
} // namespace formats::json
27+
USERVER_NAMESPACE_END

universal/include/userver/formats/parse/common.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <userver/utils/datetime/from_string_saturating.hpp>
1919
#include <userver/utils/meta.hpp>
2020
#include <userver/utils/string_to_duration.hpp>
21+
#include <userver/formats/parse/try_parse.hpp>
2122

2223
USERVER_NAMESPACE_BEGIN
2324

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
#include <type_traits>
3+
#include <string>
4+
#include <cstdint>
5+
#include <userver/formats/parse/to.hpp>
6+
#include <userver/utils/meta.hpp>
7+
#include <userver/utils/type_list.hpp>
8+
#include <userver/formats/common/meta.hpp>
9+
10+
USERVER_NAMESPACE_BEGIN
11+
12+
namespace formats::parse {
13+
14+
namespace impl {
15+
16+
template <typename T, typename Value>
17+
inline bool Is(Value&& value) {
18+
if constexpr(std::is_convertible_v<T, std::int64_t>) {
19+
return value.IsInt();
20+
} else if constexpr(std::is_convertible_v<T, std::string>) {
21+
return value.IsString();
22+
} else if constexpr(requires {std::begin(std::declval<T>());}) {
23+
return value.IsArray();
24+
} else if constexpr(std::is_convertible_v<bool, T>) {
25+
return value.IsBool();
26+
} else {
27+
return value.IsObject();
28+
}
29+
}
30+
31+
inline constexpr utils::TypeList<bool, int, std::int64_t, std::uint64_t, double, std::string> kBaseTypes;
32+
33+
34+
} // namespace impl
35+
36+
37+
template <typename T, typename Value>
38+
inline std::enable_if_t<utils::AnyOf(utils::IsSameCarried<T>(), impl::kBaseTypes), std::optional<T>>
39+
TryParse(Value&& value, userver::formats::parse::To<T>) {
40+
if(value.IsMissing() || value.IsNull() || !impl::Is<T>(value)) {
41+
return std::nullopt;
42+
}
43+
return value.template As<T>();
44+
}
45+
46+
template <typename T, typename Value>
47+
inline std::optional<T> TryParse(Value&& value, userver::formats::parse::To<std::optional<T>>) {
48+
return TryParse(std::forward<Value>(value), userver::formats::parse::To<T>{});
49+
};
50+
51+
} // namespace formats::parse
52+
53+
USERVER_NAMESPACE_END
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
2+
#pragma once
3+
#include <userver/formats/universal/universal.hpp>
4+
#include <userver/utils/regex.hpp>
5+
#include <fmt/format.h>
6+
#include <map>
7+
8+
USERVER_NAMESPACE_BEGIN
9+
namespace formats::universal {
10+
11+
template <auto Value>
12+
struct Min {
13+
static constexpr auto kValue = Value;
14+
};
15+
16+
template <auto Value>
17+
struct Max {
18+
static constexpr auto kValue = Value;
19+
};
20+
21+
template <auto Value>
22+
struct Default {
23+
static constexpr auto kValue = Value;
24+
};
25+
26+
template <utils::ConstexprString Regex>
27+
struct Pattern {
28+
static constexpr auto kValue = Regex;
29+
};
30+
31+
struct Additional {};
32+
33+
template <typename Field, auto Value>
34+
constexpr inline auto Check(const Field& field, Max<Value>) noexcept {
35+
return Value >= field;
36+
};
37+
38+
template <typename Field, auto Value>
39+
constexpr inline auto Check(const Field& field, Min<Value>) noexcept {
40+
return field >= Value;
41+
};
42+
43+
template <typename Field, auto Value>
44+
constexpr inline auto Check(const Field&, Default<Value>) noexcept {
45+
return true;
46+
};
47+
48+
template <utils::ConstexprString Regex>
49+
static const userver::utils::regex kRegex(Regex);
50+
51+
template <utils::ConstexprString Regex>
52+
constexpr inline auto Check(const std::string& field, Pattern<Regex>) noexcept {
53+
return utils::regex_match(field, kRegex<Regex>);
54+
};
55+
56+
template <typename Field, auto Value>
57+
constexpr inline auto Check(const std::optional<Field>&, Default<Value>) noexcept {
58+
return true;
59+
};
60+
61+
template <typename Field>
62+
constexpr inline auto Check(const Field&, Additional) noexcept {
63+
return true;
64+
};
65+
66+
template <typename Key, auto Value>
67+
constexpr inline auto Check(const std::vector<Key>& field, Max<Value>) noexcept {
68+
return Value >= field.size();
69+
};
70+
71+
template <typename Key, typename Tp, auto Value>
72+
constexpr inline auto Check(const std::map<Key, Tp>& field, Max<Value>) noexcept {
73+
return Value >= field.size();
74+
};
75+
76+
template <typename Key, typename Tp, auto Value>
77+
constexpr inline auto Check(const std::unordered_map<Key, Tp>& field, Max<Value>) noexcept {
78+
return Value >= field.size();
79+
};
80+
81+
template <typename Field, typename CheckT>
82+
constexpr inline bool Check(const std::optional<Field>& field, CheckT check) noexcept {
83+
if(field.has_value()) {
84+
return Check(*field, check);
85+
};
86+
return true;
87+
};
88+
89+
template <typename T, auto I, typename Key, typename Value, auto Maximum>
90+
constexpr inline auto ErrorMessage(const std::unordered_map<Key, Value>& field, Max<Maximum>) {
91+
return fmt::format("Error with field {0} Map size: {1} Maximum Size: {2}", boost::pfr::get_name<I, T>(), field.size(), Maximum);
92+
};
93+
94+
template <typename T, auto I, typename Field, template <auto> typename Check, auto Value>
95+
constexpr inline auto ErrorMessage(const Field& field, Check<Value>) {
96+
return fmt::format("Error with field {0} Field value: {1} Check Value: {2}", boost::pfr::get_name<I, T>(), field, Value);
97+
};
98+
99+
100+
template <typename T, auto I, typename Value, typename Check>
101+
constexpr inline auto ErrorMessage(const std::unordered_map<std::string, Value>&, Additional) {
102+
return "Error";
103+
};
104+
105+
template <typename T, auto I, typename Field, typename Check>
106+
constexpr inline auto ErrorMessage(const Field&, Check) {
107+
return "Error";
108+
};
109+
110+
template <typename T, auto I, typename Field, template <auto> typename Check, auto Value>
111+
constexpr inline auto ErrorMessage(const std::optional<Field>& field, Check<Value> check) {
112+
return ErrorMessage<T, I>(*field, check);
113+
};
114+
115+
} // namespace formats::universal
116+
117+
USERVER_NAMESPACE_END
118+

0 commit comments

Comments
 (0)