Blender V4.3
serialize.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_fileops.hh"
6#include "BLI_serialize.hh"
7
8#include "json.hpp"
9
10namespace blender::io::serialize {
11
13{
14 if (type_ != eValueType::String) {
15 return nullptr;
16 }
17 return static_cast<const StringValue *>(this);
18}
19
21{
22 if (type_ != eValueType::Int) {
23 return nullptr;
24 }
25 return static_cast<const IntValue *>(this);
26}
27
29{
30 if (type_ != eValueType::Double) {
31 return nullptr;
32 }
33 return static_cast<const DoubleValue *>(this);
34}
35
37{
38 if (type_ != eValueType::Boolean) {
39 return nullptr;
40 }
41 return static_cast<const BooleanValue *>(this);
42}
43
45{
46 if (type_ != eValueType::Enum) {
47 return nullptr;
48 }
49 return static_cast<const EnumValue *>(this);
50}
51
53{
54 if (type_ != eValueType::Array) {
55 return nullptr;
56 }
57 return static_cast<const ArrayValue *>(this);
58}
59
61{
62 if (type_ != eValueType::Dictionary) {
63 return nullptr;
64 }
65 return static_cast<const DictionaryValue *>(this);
66}
67
68static void convert_to_json(nlohmann::ordered_json &j, const Value &value);
69static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
70{
71 /* Create a json array to store the elements. If this isn't done and items is empty it would
72 * return use a null value, in stead of an empty array. */
73 j = "[]"_json;
74 for (const std::shared_ptr<Value> &item_value : value.elements()) {
75 nlohmann::ordered_json json_item;
76 convert_to_json(json_item, *item_value);
77 j.push_back(json_item);
78 }
79}
80
81static void convert_to_json(nlohmann::ordered_json &j, const DictionaryValue &value)
82{
83 /* Create a json object to store the attributes. If this isn't done and attributes is empty it
84 * would return use a null value, in stead of an empty object. */
85 j = "{}"_json;
86 for (const DictionaryValue::Item &attribute : value.elements()) {
87 nlohmann::ordered_json json_item;
88 convert_to_json(json_item, *attribute.second);
89 j[attribute.first] = json_item;
90 }
91}
92
93static void convert_to_json(nlohmann::ordered_json &j, const Value &value)
94{
95 switch (value.type()) {
96 case eValueType::String: {
97 j = value.as_string_value()->value();
98 break;
99 }
100
101 case eValueType::Int: {
102 j = value.as_int_value()->value();
103 break;
104 }
105
106 case eValueType::Array: {
107 const ArrayValue &array = *value.as_array_value();
109 break;
110 }
111
113 const DictionaryValue &object = *value.as_dictionary_value();
114 convert_to_json(j, object);
115 break;
116 }
117
118 case eValueType::Null: {
119 j = nullptr;
120 break;
121 }
122
123 case eValueType::Boolean: {
124 j = value.as_boolean_value()->value();
125 break;
126 }
127
128 case eValueType::Double: {
129 j = value.as_double_value()->value();
130 break;
131 }
132
133 case eValueType::Enum: {
134 j = value.as_enum_value()->value();
135 break;
136 }
137 }
138}
139
140static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j);
141static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::ordered_json &j)
142{
143 std::unique_ptr<ArrayValue> array = std::make_unique<ArrayValue>();
144 for (auto element : j.items()) {
145 array->append(convert_from_json(element.value()));
146 }
147 return array;
148}
149
150static std::unique_ptr<DictionaryValue> convert_from_json_to_object(
151 const nlohmann::ordered_json &j)
152{
153 std::unique_ptr<DictionaryValue> object = std::make_unique<DictionaryValue>();
154 for (auto element : j.items()) {
155 object->append(element.key(), convert_from_json(element.value()));
156 }
157 return object;
158}
159
160static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
161{
162 switch (j.type()) {
163 case nlohmann::json::value_t::array: {
165 }
166
167 case nlohmann::json::value_t::object: {
169 }
170
171 case nlohmann::json::value_t::string: {
172 std::string value = j;
173 return std::make_unique<StringValue>(value);
174 }
175
176 case nlohmann::json::value_t::null: {
177 return std::make_unique<NullValue>();
178 }
179
180 case nlohmann::json::value_t::boolean: {
181 return std::make_unique<BooleanValue>(j);
182 }
183 case nlohmann::json::value_t::number_integer:
184 case nlohmann::json::value_t::number_unsigned: {
185 return std::make_unique<IntValue>(j);
186 }
187
188 case nlohmann::json::value_t::number_float: {
189 return std::make_unique<DoubleValue>(j);
190 }
191
192 case nlohmann::json::value_t::binary:
193 case nlohmann::json::value_t::discarded:
194 /*
195 * Binary data isn't supported.
196 * Discarded is an internal type of nlohmann.
197 *
198 * Assert in case we need to parse them.
199 */
201 return std::make_unique<NullValue>();
202 }
203
205 return std::make_unique<NullValue>();
206}
207
208void ArrayValue::append(std::shared_ptr<Value> value)
209{
210 values_.append(std::move(value));
211}
212
213void ArrayValue::append_bool(const bool value)
214{
215 this->append(std::make_shared<BooleanValue>(value));
216}
217
218void ArrayValue::append_int(const int value)
219{
220 this->append(std::make_shared<IntValue>(value));
221}
222
223void ArrayValue::append_double(const double value)
224{
225 this->append(std::make_shared<DoubleValue>(value));
226}
227
228void ArrayValue::append_str(std::string value)
229{
230 this->append(std::make_shared<StringValue>(std::move(value)));
231}
232
234{
235 this->append(std::make_shared<NullValue>());
236}
237
238std::shared_ptr<DictionaryValue> ArrayValue::append_dict()
239{
240 auto value = std::make_shared<DictionaryValue>();
241 this->append(value);
242 return value;
243}
244
245std::shared_ptr<ArrayValue> ArrayValue::append_array()
246{
247 auto value = std::make_shared<ArrayValue>();
248 this->append(value);
249 return value;
250}
251
253{
255 for (const Item &item : values_) {
256 result.add_as(item.first, item.second);
257 }
258 return result;
259}
260
261const std::shared_ptr<Value> *DictionaryValue::lookup(const StringRef key) const
262{
263 for (const auto &item : values_) {
264 if (item.first == key) {
265 return &item.second;
266 }
267 }
268 return nullptr;
269}
270
271std::optional<StringRefNull> DictionaryValue::lookup_str(const StringRef key) const
272{
273 if (const std::shared_ptr<Value> *value = this->lookup(key)) {
274 if (const StringValue *str_value = (*value)->as_string_value()) {
275 return StringRefNull(str_value->value());
276 }
277 }
278 return std::nullopt;
279}
280
281std::optional<int64_t> DictionaryValue::lookup_int(const StringRef key) const
282{
283 if (const std::shared_ptr<Value> *value = this->lookup(key)) {
284 if (const IntValue *int_value = (*value)->as_int_value()) {
285 return int_value->value();
286 }
287 }
288 return std::nullopt;
289}
290
291std::optional<double> DictionaryValue::lookup_double(const StringRef key) const
292{
293 if (const std::shared_ptr<Value> *value = this->lookup(key)) {
294 if (const DoubleValue *double_value = (*value)->as_double_value()) {
295 return double_value->value();
296 }
297 }
298 return std::nullopt;
299}
300
302{
303 if (const std::shared_ptr<Value> *value = this->lookup(key)) {
304 return (*value)->as_dictionary_value();
305 }
306 return nullptr;
307}
308
310{
311 if (const std::shared_ptr<Value> *value = this->lookup(key)) {
312 return (*value)->as_array_value();
313 }
314 return nullptr;
315}
316
317void DictionaryValue::append(std::string key, std::shared_ptr<Value> value)
318{
319 values_.append({std::move(key), std::move(value)});
320}
321
322void DictionaryValue::append_int(std::string key, const int64_t value)
323{
324 this->append(std::move(key), std::make_shared<IntValue>(value));
325}
326
327void DictionaryValue::append_double(std::string key, const double value)
328{
329 this->append(std::move(key), std::make_shared<DoubleValue>(value));
330}
331
332void DictionaryValue::append_str(std::string key, std::string value)
333{
334 this->append(std::move(key), std::make_shared<StringValue>(std::move(value)));
335}
336
337std::shared_ptr<DictionaryValue> DictionaryValue::append_dict(std::string key)
338{
339 auto value = std::make_shared<DictionaryValue>();
340 this->append(std::move(key), value);
341 return value;
342}
343
344std::shared_ptr<ArrayValue> DictionaryValue::append_array(std::string key)
345{
346 auto value = std::make_shared<ArrayValue>();
347 this->append(std::move(key), value);
348 return value;
349}
350
351void JsonFormatter::serialize(std::ostream &os, const Value &value)
352{
353 nlohmann::ordered_json j;
354 convert_to_json(j, value);
355 if (indentation_len) {
356 os << j.dump(indentation_len);
357 }
358 else {
359 os << j.dump();
360 }
361}
362
363std::unique_ptr<Value> JsonFormatter::deserialize(std::istream &is)
364{
365 nlohmann::ordered_json j;
366 try {
367 is >> j;
368 return convert_from_json(j);
369 }
370 catch (...) {
371 return nullptr;
372 }
373}
374
375void write_json_file(const StringRef path, const Value &value)
376{
377 JsonFormatter formatter;
378 fstream stream(path, std::ios::out);
379 formatter.serialize(stream, value);
380}
381
382std::shared_ptr<Value> read_json_file(const StringRef path)
383{
384 JsonFormatter formatter;
385 fstream stream(path, std::ios::in);
386 return formatter.deserialize(stream);
387}
388
389} // namespace blender::io::serialize
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
File and directory operations.
void append(const array< T > &from)
bool add_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:288
void append(const T &value)
void append(std::shared_ptr< Value > value)
Definition serialize.cc:208
std::shared_ptr< ArrayValue > append_array()
Definition serialize.cc:245
void append_str(std::string value)
Definition serialize.cc:228
std::shared_ptr< DictionaryValue > append_dict()
Definition serialize.cc:238
void append(std::string key, std::shared_ptr< Value > value)
Definition serialize.cc:317
const std::shared_ptr< Value > * lookup(const StringRef key) const
Definition serialize.cc:261
void append_str(std::string key, std::string value)
Definition serialize.cc:332
std::shared_ptr< DictionaryValue > append_dict(std::string key)
Definition serialize.cc:337
std::pair< std::string, std::shared_ptr< Value > > Item
const DictionaryValue * lookup_dict(const StringRef key) const
Definition serialize.cc:301
void append_double(std::string key, double value)
Definition serialize.cc:327
void append_int(std::string key, int64_t value)
Definition serialize.cc:322
const ArrayValue * lookup_array(const StringRef key) const
Definition serialize.cc:309
std::optional< int64_t > lookup_int(const StringRef key) const
Definition serialize.cc:281
std::shared_ptr< ArrayValue > append_array(std::string key)
Definition serialize.cc:344
std::optional< StringRefNull > lookup_str(const StringRef key) const
Definition serialize.cc:271
std::optional< double > lookup_double(const StringRef key) const
Definition serialize.cc:291
std::unique_ptr< Value > deserialize(std::istream &is) override
Definition serialize.cc:363
void serialize(std::ostream &os, const Value &value) override
Definition serialize.cc:351
const EnumValue * as_enum_value() const
Definition serialize.cc:44
const BooleanValue * as_boolean_value() const
Definition serialize.cc:36
const ArrayValue * as_array_value() const
Definition serialize.cc:52
const StringValue * as_string_value() const
Definition serialize.cc:12
const IntValue * as_int_value() const
Definition serialize.cc:20
const DoubleValue * as_double_value() const
Definition serialize.cc:28
const DictionaryValue * as_dictionary_value() const
Definition serialize.cc:60
append
static std::unique_ptr< DictionaryValue > convert_from_json_to_object(const nlohmann::ordered_json &j)
Definition serialize.cc:150
void write_json_file(StringRef path, const Value &value)
Definition serialize.cc:375
static std::unique_ptr< Value > convert_from_json(const nlohmann::ordered_json &j)
Definition serialize.cc:160
static void convert_to_json(nlohmann::ordered_json &j, const Value &value)
Definition serialize.cc:93
static std::unique_ptr< ArrayValue > convert_from_json_to_array(const nlohmann::ordered_json &j)
Definition serialize.cc:141
std::shared_ptr< Value > read_json_file(StringRef path)
Definition serialize.cc:382
__int64 int64_t
Definition stdint.h:89