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