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`.
51 ValueBuilder(formats::common::Type 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 /// @name Concrete type constructors
64 /// @{
65 ValueBuilder(std::nullptr_t) : ValueBuilder() {}
66 ValueBuilder(bool t);
67 ValueBuilder(const char* str);
68 ValueBuilder(char* str);
69 ValueBuilder(const std::string& str);
70 ValueBuilder(std::string_view str);
71 ValueBuilder(int t);
72 ValueBuilder(unsigned int t);
73 ValueBuilder(long t);
74 ValueBuilder(unsigned long t);
75 ValueBuilder(long long t);
76 ValueBuilder(unsigned long long t);
77 ValueBuilder(float t);
78 ValueBuilder(double t);
79 /// @}
80
81 /// @brief Transfers the `ValueBuilder` object
82 /// @see formats::common::TransferTag for the transfer semantics
83 ValueBuilder(common::TransferTag, ValueBuilder&&) noexcept;
84
85 /// Universal constructor using Serialize
86 template <typename T>
87 ValueBuilder(const T& t) : ValueBuilder(DoSerialize(t)) {}
88
89 /// @brief Access member by key for modification.
90 /// @throw `TypeMismatchException` if not object or null value.
91 ValueBuilder operator[](const std::string& key);
92 /// @brief Access array member by index for modification.
93 /// @throw `TypeMismatchException` if not an array value.
94 /// @throw `OutOfBoundsException` if index is greater than size.
95 ValueBuilder operator[](std::size_t index);
96 /// @brief Access member by key for modification.
97 /// @throw `TypeMismatchException` if not object or null value.
98 template <
99 typename Tag, utils::StrongTypedefOps Ops,
100 typename Enable = std::enable_if_t<utils::IsStrongTypedefLoggable(Ops)>>
101 ValueBuilder operator[](
102 const utils::StrongTypedef<Tag, std::string, Ops>& key);
103
104 /// @brief Remove key from object. If key is missing nothing happens.
105 /// @throw `TypeMismatchException` if value is not an object.
106 void Remove(const std::string& key);
107
108 iterator begin();
109 iterator end();
110
111 /// @brief Returns whether the array or object is empty.
112 /// @throw `TypeMismatchException` if not an array or an object.
113 bool IsEmpty() const;
114
115 /// @brief Returns true if *this holds a Null (Type::kNull).
116 bool IsNull() const noexcept;
117
118 /// @brief Returns true if *this is convertible to bool.
119 bool IsBool() const noexcept;
120
121 /// @brief Returns true if *this is convertible to int.
122 bool IsInt() const noexcept;
123
124 /// @brief Returns true if *this is convertible to int64_t.
125 bool IsInt64() const noexcept;
126
127 /// @brief Returns true if *this is convertible to uint64_t.
128 bool IsUInt64() const noexcept;
129
130 /// @brief Returns true if *this is convertible to double.
131 bool IsDouble() const noexcept;
132
133 /// @brief Returns true if *this is convertible to std::string.
134 bool IsString() const noexcept;
135
136 /// @brief Returns true if *this is an array (Type::kArray).
137 bool IsArray() const noexcept;
138
139 /// @brief Returns true if *this holds a map (Type::kObject).
140 bool IsObject() const noexcept;
141
142 /// @brief Returns array size or object members count.
143 /// @throw `TypeMismatchException` if not an array or an object.
144 std::size_t GetSize() const;
145
146 /// @brief Returns true if value holds a `key`.
147 bool HasMember(const char* key) const;
148
149 /// @brief Returns true if value holds a `key`.
150 bool HasMember(const std::string& key) const;
151
152 /// @brief Resize the array value or convert null value
153 /// into an array of requested size.
154 /// @throw `TypeMismatchException` if not an array or null.
155 void Resize(std::size_t size);
156
157 /// @brief Add element into the last position of array.
158 /// @throw `TypeMismatchException` if not an array or null.
159 void PushBack(ValueBuilder&& bld);
160
161 /// @brief Take out the resulting `Value` object.
162 /// After calling this method the object is in unspecified
163 /// (but valid - possibly null) state.
164 /// @throw `YamlException` if called not from the root builder.
165 formats::yaml::Value ExtractValue();
166
167 private:
168 class EmplaceEnabler {};
169
170 public:
171 /// @cond
172 ValueBuilder(EmplaceEnabler, const YAML::Node& value,
173 const formats::yaml::Path& path, const std::string& key);
174
175 ValueBuilder(EmplaceEnabler, const YAML::Node& value,
176 const formats::yaml::Path& path, size_t index);
177 /// @endcond
178
179 private:
180 static ValueBuilder MakeNonRoot(const YAML::Node& val,
181 const formats::yaml::Path& path,
182 const std::string& key);
183 static ValueBuilder MakeNonRoot(const YAML::Node& val,
184 const formats::yaml::Path& path,
185 size_t index);
186
187 void Copy(const ValueBuilder& from);
188 void Move(ValueBuilder&& from);
189 void NodeDataAssign(const formats::yaml::Value& from);
190
191 template <typename T>
192 static Value DoSerialize(const T& t);
193
194 formats::yaml::Value value_;
195
196 friend class Iterator<IterTraits>;
197};
198
199template <typename Tag, utils::StrongTypedefOps Ops, typename Enable>
200ValueBuilder ValueBuilder::operator[](
201 const utils::StrongTypedef<Tag, std::string, Ops>& key) {
202 return (*this)[key.GetUnderlying()];
203}
204
205template <typename T>
206Value ValueBuilder::DoSerialize(const T& t) {
207 static_assert(
208 formats::common::impl::kHasSerialize<Value, T>,
209 "There is no `Serialize(const T&, formats::serialize::To<yaml::Value>)` "
210 "in namespace of `T` or `formats::serialize`. "
211 ""
212 "Probably you forgot to include the "
213 "<userver/formats/serialize/common_containers.hpp> or you "
214 "have not provided a `Serialize` function overload.");
215
216 return Serialize(t, formats::serialize::To<Value>());
217}
218
219template <typename T>
220std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= sizeof(long long),
221 Value>
222Serialize(T value, formats::serialize::To<Value>) {
223 using Type = std::conditional_t<std::is_signed<T>::value, long long,
224 unsigned long long>;
225 return yaml::ValueBuilder(static_cast<Type>(value)).ExtractValue();
226}
227
228} // namespace formats::yaml
229
230USERVER_NAMESPACE_END