Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenlib/intern/serialize.cc
- This file was added.
| #include "BLI_serialize.hh" | |||||
| #include "json.hpp" | |||||
| namespace blender::io::serialize { | |||||
| const StringValue *Value::as_string_value() const | |||||
| { | |||||
| if (_type != eValueType::String) { | |||||
| return nullptr; | |||||
| } | |||||
| return static_cast<const StringValue *>(this); | |||||
Severin: Didn't the documentation for this function say that there will be an assert for the type-match… | |||||
Done Inline ActionsWill adapt the documentation. seems like I had a different implementation in my head when writing the docs :-) jbakker: Will adapt the documentation. seems like I had a different implementation in my head when… | |||||
| } | |||||
Done Inline ActionsThis assumes that any Value with type_ == eValueType::String is a StringValue. This tight coupling is not documented at all! sybren: This assumes that any `Value` with `type_ == eValueType::String` is a `StringValue`. This tight… | |||||
| const IntValue *Value::as_int_value() const | |||||
| { | |||||
| if (_type != eValueType::Int) { | |||||
| return nullptr; | |||||
| } | |||||
| return static_cast<const IntValue *>(this); | |||||
| } | |||||
| const FloatValue *Value::as_float_value() const | |||||
| { | |||||
| if (_type != eValueType::Float) { | |||||
| return nullptr; | |||||
| } | |||||
| return static_cast<const FloatValue *>(this); | |||||
| } | |||||
| const BooleanValue *Value::as_boolean_value() const | |||||
| { | |||||
| if (_type != eValueType::Boolean) { | |||||
| return nullptr; | |||||
| } | |||||
| return static_cast<const BooleanValue *>(this); | |||||
| } | |||||
| const ArrayValue *Value::as_array_value() const | |||||
| { | |||||
| if (_type != eValueType::Array) { | |||||
| return nullptr; | |||||
| } | |||||
| return static_cast<const ArrayValue *>(this); | |||||
| } | |||||
| const ObjectValue *Value::as_object_value() const | |||||
| { | |||||
| if (_type != eValueType::Object) { | |||||
| return nullptr; | |||||
| } | |||||
| return static_cast<const ObjectValue *>(this); | |||||
| } | |||||
| static void convert_to_json(nlohmann::ordered_json &j, const Value &value) | |||||
| { | |||||
| switch (value.type()) { | |||||
| case eValueType::String: { | |||||
| j = value.as_string_value()->string_value(); | |||||
| break; | |||||
Done Inline Actionswill → would sybren: will → would | |||||
| } | |||||
| case eValueType::Int: { | |||||
| j = value.as_int_value()->value(); | |||||
| break; | |||||
| } | |||||
| case eValueType::Array: { | |||||
| const ArrayValue::Items &items = value.as_array_value()->elements(); | |||||
| /* Force to use array in case we don't have any items. */ | |||||
| j = "[]"_json; | |||||
Done Inline ActionsWhy is this necessary at all? sybren: Why is this necessary at all? | |||||
| for (const ArrayValue::Item &item_value : items) { | |||||
Done Inline ActionsWhat is this notation? sybren: What is this notation? | |||||
| nlohmann::ordered_json json_item; | |||||
| convert_to_json(json_item, *item_value); | |||||
Done Inline Actionswill → would sybren: will → would | |||||
| j.push_back(json_item); | |||||
| } | |||||
| break; | |||||
| } | |||||
| case eValueType::Object: { | |||||
| const ObjectValue::Items &attributes = value.as_object_value()->elements(); | |||||
| j = "{}"_json; | |||||
| for (const ObjectValue::Item &attribute : attributes) { | |||||
| nlohmann::ordered_json json_item; | |||||
| convert_to_json(json_item, *attribute.second); | |||||
| j[attribute.first] = json_item; | |||||
| } | |||||
| break; | |||||
Done Inline ActionsThese should be extracted to their own functions. sybren: These should be extracted to their own functions. | |||||
| } | |||||
| case eValueType::Null: { | |||||
| j = nullptr; | |||||
| break; | |||||
| } | |||||
| case eValueType::Boolean: { | |||||
| j = value.as_boolean_value()->value(); | |||||
| break; | |||||
| } | |||||
| case eValueType::Float: { | |||||
| j = value.as_float_value()->value(); | |||||
| } | |||||
| } | |||||
| } | |||||
| static Value *convert_from_json(const nlohmann::ordered_json &j) | |||||
| { | |||||
Done Inline ActionsI would much prefer returning std::unique_ptrs here, rather than raw owning pointers. Especially since it's not documented that they are owning and need freeing :) Severin: I would much prefer returning `std::unique_ptr`s here, rather than raw owning pointers. | |||||
| switch (j.type()) { | |||||
| case nlohmann::json::value_t::array: { | |||||
| ArrayValue *array = new ArrayValue(); | |||||
| ArrayValue::Items &elements = array->elements(); | |||||
| for (auto element : j.items()) { | |||||
| nlohmann::ordered_json element_json = element.value(); | |||||
| Value *value = convert_from_json(element_json); | |||||
| elements.append_as(value); | |||||
| } | |||||
| return array; | |||||
Done Inline ActionsSuch blocks should be their own function sybren: Such blocks should be their own function | |||||
| } | |||||
| case nlohmann::json::value_t::object: { | |||||
| ObjectValue *object = new ObjectValue(); | |||||
| ObjectValue::Items &elements = object->elements(); | |||||
| for (auto element : j.items()) { | |||||
| std::string key = element.key(); | |||||
| nlohmann::ordered_json element_json = element.value(); | |||||
| Value *value = convert_from_json(element_json); | |||||
| elements.append_as(std::pair(key, value)); | |||||
| } | |||||
| return object; | |||||
| } | |||||
| case nlohmann::json::value_t::string: { | |||||
| std::string value = j; | |||||
| return new StringValue(value); | |||||
| } | |||||
| case nlohmann::json::value_t::null: { | |||||
| return new NullValue(); | |||||
| } | |||||
| case nlohmann::json::value_t::boolean: { | |||||
| return new BooleanValue(j); | |||||
| } | |||||
| case nlohmann::json::value_t::number_integer: | |||||
| case nlohmann::json::value_t::number_unsigned: { | |||||
| return new IntValue(j); | |||||
| } | |||||
| case nlohmann::json::value_t::number_float: { | |||||
| return new FloatValue(j); | |||||
| } | |||||
| case nlohmann::json::value_t::binary: | |||||
| case nlohmann::json::value_t::discarded: | |||||
| /* Binary and discarded are not actual json elements. */ | |||||
| BLI_assert_unreachable(); | |||||
Done Inline ActionsThen why are they (and this code) even here? sybren: Then why are they (and this code) even here? | |||||
| return nullptr; | |||||
| } | |||||
| BLI_assert_unreachable(); | |||||
| return nullptr; | |||||
| } | |||||
| void JsonFormatter::serialize(std::ostream &os, Value &value) | |||||
| { | |||||
| nlohmann::ordered_json j; | |||||
| convert_to_json(j, value); | |||||
| if (indentation_len) { | |||||
| os << j.dump(indentation_len); | |||||
| } | |||||
| else { | |||||
| os << j.dump(); | |||||
| } | |||||
| } | |||||
| Value *JsonFormatter::deserialize(std::istream &is) | |||||
| { | |||||
| nlohmann::ordered_json j; | |||||
| is >> j; | |||||
| Value *value = convert_from_json(j); | |||||
| return value; | |||||
| } | |||||
| } // namespace blender::io::serialize | |||||
Didn't the documentation for this function say that there will be an assert for the type-match as well?