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