userver: userver/formats/yaml/value_builder.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
value_builder.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/formats/yaml/value_builder.hpp
4/// @brief @copybrief formats::yaml::ValueBuilder
5
6#include <userver/formats/common/transfer_tag.hpp>
7#include <userver/formats/serialize/to.hpp>
8#include <userver/formats/yaml/value.hpp>
9#include <userver/utils/strong_typedef.hpp>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace formats::yaml {
14
15// clang-format off
16
17/// @ingroup userver_universal userver_containers userver_formats
18///
19/// @brief Builder for YAML.
20///
21/// Class provides methods for building YAML. For read only access to the
22/// existing YAML values use formats::yaml::Value.
23///
24/// ## Example usage:
25///
26/// @snippet formats/yaml/value_builder_test.cpp Sample formats::yaml::ValueBuilder usage
27///
28/// ## Customization example:
29///
30/// @snippet formats/json/value_builder_test.cpp Sample Customization formats::json::ValueBuilder usage
31///
32/// @see @ref scripts/docs/en/userver/formats.md
33
34// clang-format on
35
36class ValueBuilder final {
37 public:
38 struct IterTraits {
39 using native_iter = YAML::iterator;
40 using value_type = formats::yaml::ValueBuilder;
41 using reference = formats::yaml::ValueBuilder&;
42 using pointer = formats::yaml::ValueBuilder*;
43 };
44
45 using iterator = Iterator<IterTraits>;
46
47 /// Constructs a valueBuilder that holds kNull
49
50 /// Constructs a valueBuilder that holds default value for provided `type`.
52
53 ValueBuilder(const ValueBuilder& other);
54 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
55 ValueBuilder(ValueBuilder&& other);
56 ValueBuilder& operator=(const ValueBuilder& other);
57 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
58 ValueBuilder& operator=(ValueBuilder&& other);
59
60 ValueBuilder(const formats::yaml::Value& other);
61 ValueBuilder(formats::yaml::Value&& other);
62
63 /// Converting constructors.
64 ValueBuilder(bool t);
65 ValueBuilder(const char* str);
66 ValueBuilder(const std::string& str);
67 ValueBuilder(int t);
68 ValueBuilder(unsigned int t);
69 ValueBuilder(long t);
70 ValueBuilder(unsigned long t);
71 ValueBuilder(long long t);
72 ValueBuilder(unsigned long long t);
73 ValueBuilder(float t);
74 ValueBuilder(double t);
75
76 /// @brief Transfers the `ValueBuilder` object
77 /// @see formats::common::TransferTag for the transfer semantics
78 ValueBuilder(common::TransferTag, ValueBuilder&&) noexcept;
79
80 /// Universal constructor using Serialize
81 template <typename T>
82 ValueBuilder(const T& t) : ValueBuilder(DoSerialize(t)) {}
83
84 /// @brief Access member by key for modification.
85 /// @throw `TypeMismatchException` if not object or null value.
86 ValueBuilder operator[](const std::string& key);
87 /// @brief Access array member by index for modification.
88 /// @throw `TypeMismatchException` if not an array value.
89 /// @throw `OutOfBoundsException` if index is greater than size.
90 ValueBuilder operator[](std::size_t index);
91 /// @brief Access member by key for modification.
92 /// @throw `TypeMismatchException` if not object or null value.
93 template <
94 typename Tag, utils::StrongTypedefOps Ops,
95 typename Enable = std::enable_if_t<utils::IsStrongTypedefLoggable(Ops)>>
96 ValueBuilder operator[](
97 const utils::StrongTypedef<Tag, std::string, Ops>& key);
98
99 /// @brief Remove key from object. If key is missing nothing happens.
100 /// @throw `TypeMismatchException` if value is not an object.
101 void Remove(const std::string& key);
102
103 iterator begin();
104 iterator end();
105
106 /// @brief Returns whether the array or object is empty.
107 /// @throw `TypeMismatchException` if not an array or an object.
108 bool IsEmpty() const;
109
110 /// @brief Returns true if *this holds a Null (Type::kNull).
111 bool IsNull() const noexcept;
112
113 /// @brief Returns true if *this is convertible to bool.
114 bool IsBool() const noexcept;
115
116 /// @brief Returns true if *this is convertible to int.
117 bool IsInt() const noexcept;
118
119 /// @brief Returns true if *this is convertible to int64_t.
120 bool IsInt64() const noexcept;
121
122 /// @brief Returns true if *this is convertible to uint64_t.
123 bool IsUInt64() const noexcept;
124
125 /// @brief Returns true if *this is convertible to double.
126 bool IsDouble() const noexcept;
127
128 /// @brief Returns true if *this is convertible to std::string.
129 bool IsString() const noexcept;
130
131 /// @brief Returns true if *this is an array (Type::kArray).
132 bool IsArray() const noexcept;
133
134 /// @brief Returns true if *this holds a map (Type::kObject).
135 bool IsObject() const noexcept;
136
137 /// @brief Returns array size or object members count.
138 /// @throw `TypeMismatchException` if not an array or an object.
139 std::size_t GetSize() const;
140
141 /// @brief Returns true if value holds a `key`.
142 bool HasMember(const char* key) const;
143
144 /// @brief Returns true if value holds a `key`.
145 bool HasMember(const std::string& key) const;
146
147 /// @brief Resize the array value or convert null value
148 /// into an array of requested size.
149 /// @throw `TypeMismatchException` if not an array or null.
150 void Resize(std::size_t size);
151
152 /// @brief Add element into the last position of array.
153 /// @throw `TypeMismatchException` if not an array or null.
154 void PushBack(ValueBuilder&& bld);
155
156 /// @brief Take out the resulting `Value` object.
157 /// After calling this method the object is in unspecified
158 /// (but valid - possibly null) state.
159 /// @throw `YamlException` if called not from the root builder.
160 formats::yaml::Value ExtractValue();
161
162 private:
163 class EmplaceEnabler {};
164
165 public:
166 /// @cond
167 ValueBuilder(EmplaceEnabler, const YAML::Node& value,
168 const formats::yaml::Path& path, const std::string& key);
169
170 ValueBuilder(EmplaceEnabler, const YAML::Node& value,
171 const formats::yaml::Path& path, size_t index);
172 /// @endcond
173
174 private:
175 static ValueBuilder MakeNonRoot(const YAML::Node& val,
176 const formats::yaml::Path& path,
177 const std::string& key);
178 static ValueBuilder MakeNonRoot(const YAML::Node& val,
179 const formats::yaml::Path& path,
180 size_t index);
181
182 void Copy(const ValueBuilder& from);
183 void Move(ValueBuilder&& from);
184 void NodeDataAssign(const formats::yaml::Value& from);
185
186 template <typename T>
187 static Value DoSerialize(const T& t);
188
189 formats::yaml::Value value_;
190
191 friend class Iterator<IterTraits>;
192};
193
194template <typename Tag, utils::StrongTypedefOps Ops, typename Enable>
195ValueBuilder ValueBuilder::operator[](
196 const utils::StrongTypedef<Tag, std::string, Ops>& key) {
197 return (*this)[key.GetUnderlying()];
198}
199
200template <typename T>
201Value ValueBuilder::DoSerialize(const T& t) {
202 static_assert(
203 formats::common::impl::kHasSerialize<Value, T>,
204 "There is no `Serialize(const T&, formats::serialize::To<yaml::Value>)` "
205 "in namespace of `T` or `formats::serizalize`. "
206 ""
207 "Probably you forgot to include the "
208 "<userver/formats/serialize/common_containers.hpp> or you "
209 "have not provided a `Serialize` function overload.");
210
211 return Serialize(t, formats::serialize::To<Value>());
212}
213
214template <typename T>
215std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= sizeof(long long),
216 Value>
217Serialize(T value, formats::serialize::To<Value>) {
218 using Type = std::conditional_t<std::is_signed<T>::value, long long,
219 unsigned long long>;
220 return yaml::ValueBuilder(static_cast<Type>(value)).ExtractValue();
221}
222
223} // namespace formats::yaml
224
225USERVER_NAMESPACE_END