userver: userver/formats/parse/common_containers.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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<common::kIsFormatValue<Value> && meta::kIsRange<T> &&
70 !meta::kIsMap<T> &&
71 !std::is_same_v<T, boost::uuids::uuid> &&
72 !std::is_convertible_v<
73 T&, utils::impl::strong_typedef::StrongTypedefTag&>,
74 T>
75Parse(const Value& value, To<T>) {
76 return impl::ParseArray<T>(
77 value, &impl::AsExtractor<meta::RangeValueType<T>, Value>);
78}
79
80template <typename T, typename Value>
81std::enable_if_t<common::kIsFormatValue<Value> && meta::kIsMap<T>, T> Parse(
82 const Value& value, To<T>) {
83 return impl::ParseObject<T>(
84 value, &impl::AsExtractor<typename T::mapped_type, Value>);
85}
86
87template <typename T, typename Value>
88std::optional<decltype(Parse(std::declval<Value>(), To<T>{}))> Parse(
89 const Value& value, To<std::optional<T>>) {
90 if (value.IsMissing() || value.IsNull()) {
91 return std::nullopt;
92 }
93 return value.template As<T>();
94}
95
96template <class Value>
97std::optional<std::nullptr_t> Parse(const Value&,
98 To<std::optional<std::nullptr_t>>) {
99 static_assert(!sizeof(Value),
100 "optional<nullptr_t> is forbidden, check IsNull() instead");
101 return nullptr;
102}
103
104template <typename T, typename Value>
105std::enable_if_t<meta::kIsRange<T> && !meta::kIsMap<T> &&
106 !std::is_same_v<T, boost::uuids::uuid> &&
107 !std::is_convertible_v<
108 T&, utils::impl::strong_typedef::StrongTypedefTag&>,
109 T>
110Convert(const Value& value, To<T>) {
111 if (value.IsMissing()) {
112 return {};
113 }
114 return impl::ParseArray<T>(
115 value, &impl::ConvertToExtractor<meta::RangeValueType<T>, Value>);
116}
117
118template <typename T, typename Value>
119std::enable_if_t<meta::kIsMap<T>, T> Convert(const Value& value, To<T>) {
120 if (value.IsMissing()) {
121 return {};
122 }
123 return impl::ParseObject<T>(
124 value, &impl::ConvertToExtractor<typename T::mapped_type, Value>);
125}
126
127template <typename T, typename Value>
128std::optional<T> Convert(const Value& value, To<std::optional<T>>) {
129 if (value.IsMissing() || value.IsNull()) {
130 return std::nullopt;
131 }
132 return value.template ConvertTo<T>();
133}
134
135template <class Value>
136std::optional<std::nullptr_t> Convert(const Value&,
137 To<std::optional<std::nullptr_t>>) {
138 static_assert(!sizeof(Value),
139 "optional<nullptr_t> is forbidden, check IsNull() instead");
140 return nullptr;
141}
142
143} // namespace formats::parse
144
145USERVER_NAMESPACE_END