userver: userver/formats/parse/common_containers.hpp Source File
Loading...
Searching...
No Matches
common_containers.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/formats/parse/common_containers.hpp
4/// @brief Parsers and converters for Standard Library containers and
5/// std::optional
6///
7/// @ingroup userver_universal userver_formats_parse
8
9#include <optional>
10#include <type_traits>
11
12#include <userver/formats/common/meta.hpp>
13#include <userver/formats/parse/to.hpp>
14#include <userver/utils/meta.hpp>
15
16namespace boost::uuids {
17struct uuid;
18}
19
20USERVER_NAMESPACE_BEGIN
21
22namespace utils::impl::strong_typedef {
23struct StrongTypedefTag;
24}
25
26namespace formats::parse {
27
28namespace impl {
29
30template <typename T, class Value>
31inline T AsExtractor(const Value& value) {
32 return value.template As<T>();
33}
34
35template <typename T, class Value>
36inline T ConvertToExtractor(const Value& value) {
37 return value.template ConvertTo<T>();
38}
39
40template <typename ArrayType, class Value, typename ExtractFunc>
41ArrayType ParseArray(const Value& value, ExtractFunc&& extract_func) {
42 value.CheckArrayOrNull();
43 ArrayType response;
44 auto inserter = std::inserter(response, response.end());
45
46 for (const auto& subitem : value) {
47 *inserter = extract_func(subitem);
48 ++inserter;
49 }
50
51 return response;
52}
53
54template <typename ObjectType, class Value, typename ExtractFunc>
55ObjectType ParseObject(const Value& value, ExtractFunc&& extract_func) {
56 value.CheckObjectOrNull();
57 ObjectType result;
58
59 for (auto it = value.begin(); it != value.end(); ++it) {
60 result.emplace(it.GetName(), extract_func(*it));
61 }
62
63 return result;
64}
65
66} // namespace impl
67
68template <typename T, typename Value>
69std::enable_if_t<
70 common::kIsFormatValue<Value> && meta::kIsRange<T> && !meta::kIsMap<T> && !std::is_same_v<T, boost::uuids::uuid> &&
71 !std::is_convertible_v<T&, utils::impl::strong_typedef::StrongTypedefTag&>,
72 T>
73Parse(const Value& value, To<T>) {
74 return impl::ParseArray<T>(value, &impl::AsExtractor<meta::RangeValueType<T>, Value>);
75}
76
77template <typename T, typename Value>
78std::enable_if_t<common::kIsFormatValue<Value> && meta::kIsMap<T>, T> Parse(const Value& value, To<T>) {
79 return impl::ParseObject<T>(value, &impl::AsExtractor<typename T::mapped_type, Value>);
80}
81
82template <typename T, typename Value>
83std::optional<decltype(Parse(std::declval<Value>(), To<T>{}))> Parse(const Value& value, To<std::optional<T>>) {
84 if (value.IsMissing() || value.IsNull()) {
85 return std::nullopt;
86 }
87 return value.template As<T>();
88}
89
90template <class Value>
91std::optional<std::nullptr_t> Parse(const Value&, To<std::optional<std::nullptr_t>>) {
92 static_assert(!sizeof(Value), "optional<nullptr_t> is forbidden, check IsNull() instead");
93 return nullptr;
94}
95
96template <typename T, typename Value>
97std::enable_if_t<
98 meta::kIsRange<T> && !meta::kIsMap<T> && !std::is_same_v<T, boost::uuids::uuid> &&
99 !std::is_convertible_v<T&, utils::impl::strong_typedef::StrongTypedefTag&>,
100 T>
101Convert(const Value& value, To<T>) {
102 if (value.IsMissing()) {
103 return {};
104 }
105 return impl::ParseArray<T>(value, &impl::ConvertToExtractor<meta::RangeValueType<T>, Value>);
106}
107
108template <typename T, typename Value>
109std::enable_if_t<meta::kIsMap<T>, T> Convert(const Value& value, To<T>) {
110 if (value.IsMissing()) {
111 return {};
112 }
113 return impl::ParseObject<T>(value, &impl::ConvertToExtractor<typename T::mapped_type, Value>);
114}
115
116template <typename T, typename Value>
117std::optional<T> Convert(const Value& value, To<std::optional<T>>) {
118 if (value.IsMissing() || value.IsNull()) {
119 return std::nullopt;
120 }
121 return value.template ConvertTo<T>();
122}
123
124template <class Value>
125std::optional<std::nullptr_t> Convert(const Value&, To<std::optional<std::nullptr_t>>) {
126 static_assert(!sizeof(Value), "optional<nullptr_t> is forbidden, check IsNull() instead");
127 return nullptr;
128}
129
130} // namespace formats::parse
131
132USERVER_NAMESPACE_END