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