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/compiler/impl/nodebug.hpp>
7#include <userver/formats/common/transfer_tag.hpp>
8#include <userver/formats/serialize/to.hpp>
9#include <userver/formats/yaml/value.hpp>
10#include <userver/utils/strong_typedef.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace formats::yaml {
15
16/// @ingroup userver_universal userver_containers userver_formats
17///
18/// @brief Builder for YAML.
19///
20/// Class provides methods for building YAML. For read only access to the
21/// existing YAML values use formats::yaml::Value.
22///
23/// ## Example usage:
24///
25/// @snippet formats/yaml/value_builder_test.cpp Sample formats::yaml::ValueBuilder usage
26///
27/// ## Customization example:
28///
29/// @snippet formats/json/value_builder_test.cpp Sample Customization formats::json::ValueBuilder usage
30///
31/// @see @ref scripts/docs/en/userver/formats.md
32class ValueBuilder final {
33public:
34 struct IterTraits {
35 using native_iter = YAML::iterator;
36 using value_type = formats::yaml::ValueBuilder;
37 using reference = formats::yaml::ValueBuilder&;
38 using pointer = formats::yaml::ValueBuilder*;
39 };
40
41 using iterator = Iterator<IterTraits>;
42
43 /// Constructs a valueBuilder that holds kNull
45
46 /// Constructs a valueBuilder that holds default value for provided `type`.
47 ValueBuilder(formats::common::Type type);
48
49 ValueBuilder(const ValueBuilder& other);
50 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
51 ValueBuilder(ValueBuilder&& other);
52 ValueBuilder& operator=(const ValueBuilder& other);
53 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
54 ValueBuilder& operator=(ValueBuilder&& other);
55
56 ValueBuilder(const formats::yaml::Value& other);
57 ValueBuilder(formats::yaml::Value&& other);
58
59 /// @name Concrete type constructors
60 /// @{
61 ValueBuilder(std::nullptr_t)
62 : ValueBuilder()
63 {}
64 ValueBuilder(bool t);
65 ValueBuilder(const char* str);
66 ValueBuilder(char* str);
67 ValueBuilder(const std::string& str);
68 ValueBuilder(std::string_view str);
69 ValueBuilder(int t);
70 ValueBuilder(unsigned int t);
71 ValueBuilder(long t);
72 ValueBuilder(unsigned long t);
73 ValueBuilder(long long t);
74 ValueBuilder(unsigned long long t);
75 ValueBuilder(float t);
76 ValueBuilder(double t);
77 /// @}
78
79 /// @brief Transfers the `ValueBuilder` object
80 /// @see formats::common::TransferTag for the transfer semantics
81 ValueBuilder(common::TransferTag, ValueBuilder&&) noexcept;
82
83 /// Universal constructor using Serialize
84 template <typename T>
85 ValueBuilder(const T& t)
86 : ValueBuilder(DoSerialize(t))
87 {}
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 <typename Tag, utils::StrongTypedefOps Ops>
99 requires(utils::IsStrongTypedefLoggable(Ops))
100 ValueBuilder operator[](const utils::StrongTypedef<Tag, std::string, Ops>& key) {
101 return (*this)[key.GetUnderlying()];
102 }
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
167private:
168 class EmplaceEnabler {};
169
170public:
171 /// @cond
172 ValueBuilder(EmplaceEnabler, const YAML::Node& value, const formats::yaml::Path& path, const std::string& key);
173
174 ValueBuilder(EmplaceEnabler, const YAML::Node& value, const formats::yaml::Path& path, size_t index);
175 /// @endcond
176
177private:
178 static ValueBuilder MakeNonRoot(const YAML::Node& val, const formats::yaml::Path& path, const std::string& key);
179 static ValueBuilder MakeNonRoot(const YAML::Node& val, const formats::yaml::Path& path, size_t index);
180
181 void Copy(const ValueBuilder& from);
182 void Move(ValueBuilder&& from);
183 void NodeDataAssign(const formats::yaml::Value& from);
184
185 template <typename T>
186 USERVER_IMPL_NODEBUG_INLINE_FUNC static Value DoSerialize(const T& t) {
187 static_assert(
188 formats::common::impl::HasSerialize<Value, T>,
189 "There is no `Serialize(const T&, formats::serialize::To<yaml::Value>)` "
190 "in namespace of `T` or `formats::serialize`. "
191 ""
192 "Probably you forgot to include the <userver/formats/serialize/common_containers.hpp> or you "
193 "have not provided a `Serialize` function overload."
194 );
195
196 return Serialize(t, formats::serialize::To<Value>());
197 }
198
199 formats::yaml::Value value_;
200
201 friend class Iterator<IterTraits>;
202};
203
204template <typename T>
205requires(std::is_integral<T>::value && sizeof(T) <= sizeof(long long))
206Value Serialize(T value, formats::serialize::To<Value>) {
207 using Type = std::conditional_t<std::is_signed<T>::value, long long, unsigned long long>;
208 return yaml::ValueBuilder(static_cast<Type>(value)).ExtractValue();
209}
210
211} // namespace formats::yaml
212
213USERVER_NAMESPACE_END