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
73} // namespace impl
74
75template <typename T, typename Value>
76std::enable_if_t<
77 common::kIsFormatValue<Value> && meta::kIsRange<T> && !meta::kIsMap<T> && !std::is_same_v<T, boost::uuids::uuid> &&
78 !std::is_convertible_v<T&, utils::impl::strong_typedef::StrongTypedefTag&>,
79 T>
80Parse(const Value& value, To<T>) {
81 return impl::ParseArray<T>(value, &impl::AsExtractor<meta::RangeValueType<T>, Value>);
82}
83
84template <typename T, typename Value>
85std::enable_if_t<common::kIsFormatValue<Value> && meta::kIsMap<T>, T> Parse(const Value& value, To<T>) {
86 return impl::ParseObject<T>(value, &impl::AsExtractor<typename T::mapped_type, Value>);
87}
88
89template <typename T, typename Value>
90std::optional<decltype(Parse(std::declval<Value>(), To<T>{}))> Parse(const Value& value, To<std::optional<T>>) {
91 if (value.IsMissing() || value.IsNull()) {
92 return std::nullopt;
93 }
94 return value.template As<T>();
95}
96
97template <class Value>
98std::optional<std::nullptr_t> Parse(const Value&, To<std::optional<std::nullptr_t>>) {
99 static_assert(!sizeof(Value), "optional<nullptr_t> is forbidden, check IsNull() instead");
100 return nullptr;
101}
102
103template <typename T, typename Value>
104std::enable_if_t<
105 meta::kIsRange<T> && !meta::kIsMap<T> && !std::is_same_v<T, boost::uuids::uuid> &&
106 !std::is_convertible_v<T&, utils::impl::strong_typedef::StrongTypedefTag&>,
107 T>
108Convert(const Value& value, To<T>) {
109 if (value.IsMissing()) {
110 return {};
111 }
112 return impl::ParseArray<T>(value, &impl::ConvertToExtractor<meta::RangeValueType<T>, Value>);
113}
114
115template <typename T, typename Value>
116std::enable_if_t<meta::kIsMap<T>, T> Convert(const Value& value, To<T>) {
117 if (value.IsMissing()) {
118 return {};
119 }
120 return impl::ParseObject<T>(value, &impl::ConvertToExtractor<typename T::mapped_type, Value>);
121}
122
123template <typename T, typename Value>
124std::optional<T> Convert(const Value& value, To<std::optional<T>>) {
125 if (value.IsMissing() || value.IsNull()) {
126 return std::nullopt;
127 }
128 return value.template ConvertTo<T>();
129}
130
131template <class Value>
132std::optional<std::nullptr_t> Convert(const Value&, To<std::optional<std::nullptr_t>>) {
133 static_assert(!sizeof(Value), "optional<nullptr_t> is forbidden, check IsNull() instead");
134 return nullptr;
135}
136
137} // namespace formats::parse
138
139USERVER_NAMESPACE_END