userver: userver/formats/json/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/json/value_builder.hpp
4/// @brief @copybrief formats::json::ValueBuilder
5
6#include <chrono>
7#include <string_view>
8#include <vector>
9
10#include <userver/formats/common/meta.hpp>
11#include <userver/formats/common/transfer_tag.hpp>
12#include <userver/formats/json/impl/mutable_value_wrapper.hpp>
13#include <userver/formats/json/value.hpp>
14#include <userver/utils/strong_typedef.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace formats::json {
19
20// clang-format off
21
22/// @ingroup userver_universal userver_containers userver_formats
23///
24/// @brief Builder for JSON.
25///
26/// Class provides methods for building JSON. For read only access to the
27/// existing JSON values use formats::json::Value.
28///
29/// ## Example usage:
30///
31/// @snippet formats/json/value_builder_test.cpp Sample formats::json::ValueBuilder usage
32///
33/// ## Customization example:
34///
35/// @snippet formats/json/value_builder_test.cpp Sample Customization formats::json::ValueBuilder usage
36///
37/// @see @ref scripts/docs/en/userver/formats.md
38
39// clang-format on
40
41class ValueBuilder final {
42 public:
43 struct IterTraits {
44 using ValueType = formats::json::ValueBuilder;
45 using Reference = formats::json::ValueBuilder&;
46 using Pointer = formats::json::ValueBuilder*;
47 using ContainerType = impl::MutableValueWrapper;
48 };
49
50 using iterator = Iterator<IterTraits>;
51
52 /// Constructs a ValueBuilder that holds kNull
53 ValueBuilder() = default;
54
55 /// Constructs a valueBuilder that holds default value for provided `type`.
56 ValueBuilder(formats::common::Type type);
57
58 /// @brief Transfers the `ValueBuilder` object
59 /// @see formats::common::TransferTag for the transfer semantics
60 ValueBuilder(common::TransferTag, ValueBuilder&&) noexcept;
61
62 ValueBuilder(const ValueBuilder& other);
63 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
64 ValueBuilder(ValueBuilder&& other);
65 ValueBuilder& operator=(const ValueBuilder& other);
66 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
67 ValueBuilder& operator=(ValueBuilder&& other);
68
69 ValueBuilder(const formats::json::Value& other);
70 ValueBuilder(formats::json::Value&& other);
71
72 /// @name Concrete type constructors
73 /// @{
74 ValueBuilder(std::nullptr_t) : ValueBuilder() {}
75 ValueBuilder(bool t);
76 ValueBuilder(const char* str);
77 ValueBuilder(char* str);
78 ValueBuilder(const std::string& str);
79 ValueBuilder(std::string_view str);
80 ValueBuilder(int t);
81 ValueBuilder(unsigned int t);
82 ValueBuilder(uint64_t t);
83 ValueBuilder(int64_t t);
84 ValueBuilder(float t);
85 ValueBuilder(double t);
86 /// @}
87
88 /// Universal constructor using Serialize
89 template <typename T>
90 ValueBuilder(const T& t) : ValueBuilder(DoSerialize(t)) {}
91
92 /// @brief Access member by key for modification.
93 /// @throw `TypeMismatchException` if not object or null value.
94 ValueBuilder operator[](std::string key);
95 /// @brief Access array member by index for modification.
96 /// @throw `TypeMismatchException` if not an array value.
97 /// @throw `OutOfBoundsException` if index is greater than size.
98 ValueBuilder operator[](std::size_t index);
99 /// @brief Access member by key for modification.
100 /// @throw `TypeMismatchException` if not object or null value.
101 template <
102 typename Tag, utils::StrongTypedefOps Ops,
103 typename Enable = std::enable_if_t<utils::IsStrongTypedefLoggable(Ops)>>
104 ValueBuilder operator[](utils::StrongTypedef<Tag, std::string, Ops> key);
105
106 /// @brief Emplaces new member w/o a check whether the key already exists.
107 /// @warning May create invalid JSON with duplicate key.
108 /// @throw `TypeMismatchException` if not object or null value.
109 void EmplaceNocheck(std::string_view key, ValueBuilder value);
110
111 /// @brief Remove key from object. If key is missing nothing happens.
112 /// @throw `TypeMismatchException` if value is not an object.
113 void Remove(std::string_view key);
114
115 iterator begin();
116 iterator end();
117
118 /// @brief Returns whether the array or object is empty.
119 /// @throw `TypeMismatchException` if not an array or an object.
120 bool IsEmpty() const;
121
122 /// @brief Returns true if *this holds a Null (Type::kNull).
123 bool IsNull() const noexcept;
124
125 /// @brief Returns true if *this is convertible to bool.
126 bool IsBool() const noexcept;
127
128 /// @brief Returns true if *this is convertible to int.
129 bool IsInt() const noexcept;
130
131 /// @brief Returns true if *this is convertible to int64_t.
132 bool IsInt64() const noexcept;
133
134 /// @brief Returns true if *this is convertible to uint64_t.
135 bool IsUInt64() const noexcept;
136
137 /// @brief Returns true if *this is convertible to double.
138 bool IsDouble() const noexcept;
139
140 /// @brief Returns true if *this is convertible to std::string.
141 bool IsString() const noexcept;
142
143 /// @brief Returns true if *this is an array (Type::kArray).
144 bool IsArray() const noexcept;
145
146 /// @brief Returns true if *this holds a map (Type::kObject).
147 bool IsObject() const noexcept;
148
149 /// @brief Returns array size or object members count.
150 /// @throw `TypeMismatchException` if not an array or an object.
151 std::size_t GetSize() const;
152
153 /// @brief Returns true if value holds a `key`.
154 /// @throw `TypeMismatchException` if `*this` is not a map or null.
155 bool HasMember(std::string_view key) const;
156
157 /// @brief Returns full path to this value.
158 std::string GetPath() const;
159
160 /// @brief Resize the array value or convert null value
161 /// into an array of requested size.
162 /// @throw `TypeMismatchException` if not an array or null.
163 void Resize(std::size_t size);
164
165 /// @brief Add element into the last position of array.
166 /// @throw `TypeMismatchException` if not an array or null.
167 void PushBack(ValueBuilder&& bld);
168
169 /// @brief Take out the resulting `Value` object.
170 /// After calling this method the object is in unspecified
171 /// (but valid - possibly null) state.
172 /// @throw `JsonException` if called not from the root builder.
173 formats::json::Value ExtractValue();
174
175 private:
176 class EmplaceEnabler {};
177
178 public:
179 /// @cond
180 ValueBuilder(EmplaceEnabler, impl::MutableValueWrapper) noexcept;
181 /// @endcond
182
183 private:
184 enum class CheckMemberExists { kYes, kNo };
185
186 explicit ValueBuilder(impl::MutableValueWrapper) noexcept;
187
188 static void Copy(impl::Value& to, const ValueBuilder& from);
189 static void Move(impl::Value& to, ValueBuilder&& from);
190
191 impl::Value& AddMember(std::string_view key, CheckMemberExists);
192
193 template <typename T>
194 static Value DoSerialize(const T& t);
195
196 impl::MutableValueWrapper value_;
197
198 friend class Iterator<IterTraits, common::IteratorDirection::kForward>;
199 friend class Iterator<IterTraits, common::IteratorDirection::kReverse>;
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<json::Value>)` "
207 "in namespace of `T` or `formats::serialize`. "
208 ""
209 "Probably you forgot to include the "
210 "<userver/formats/serialize/common_containers.hpp> header "
211 "or one of the <formats/json/serialize_*.hpp> headers or you "
212 "have not provided a `Serialize` function overload.");
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(int64_t),
219 Value>
220Serialize(T value, formats::serialize::To<Value>) {
221 using Type = std::conditional_t<std::is_signed<T>::value, int64_t, uint64_t>;
222 return json::ValueBuilder(static_cast<Type>(value)).ExtractValue();
223}
224
225json::Value Serialize(std::chrono::system_clock::time_point tp,
226 formats::serialize::To<Value>);
227
228template <typename Tag, utils::StrongTypedefOps Ops, typename Enable>
229ValueBuilder ValueBuilder::operator[](
230 utils::StrongTypedef<Tag, std::string, Ops> key) {
231 return (*this)[std::move(key.GetUnderlying())];
232}
233
234/// Optimized maps of StrongTypedefs serialization for JSON
235template <typename T>
238 Value>
240 json::ValueBuilder builder(formats::common::Type::kObject);
241 for (const auto& [key, value] : value) {
242 builder.EmplaceNocheck(key.GetUnderlying(), value);
243 }
244 return builder.ExtractValue();
245}
246
247/// Optimized maps serialization for JSON
248template <typename T>
250 std::is_convertible_v<typename T::key_type, std::string>,
251 Value>
253 json::ValueBuilder builder(formats::common::Type::kObject);
254 for (const auto& [key, value] : value) {
255 builder.EmplaceNocheck(key, value);
256 }
257 return builder.ExtractValue();
258}
259
260} // namespace formats::json
261
262USERVER_NAMESPACE_END