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