// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "nlohmann_json_serializer.h" #include "null_json_serializer.h" // Disable JSON exceptions. We should be guarding against any exceptions being // fired in this file. #define JSON_NOEXCEPTION 1 #include <nlohmann/json.hpp> namespace dap { namespace json { NlohmannDeserializer::NlohmannDeserializer(const std::string& str) : json(new nlohmann::json(nlohmann::json::parse(str, nullptr, false))), ownsJson(true) {} NlohmannDeserializer::NlohmannDeserializer(const nlohmann::json* json) : json(json), ownsJson(false) {} NlohmannDeserializer::~NlohmannDeserializer() { if (ownsJson) { delete json; } } bool NlohmannDeserializer::deserialize(dap::boolean* v) const { if (!json->is_boolean()) { return false; } *v = json->get<bool>(); return true; } bool NlohmannDeserializer::deserialize(dap::integer* v) const { if (!json->is_number_integer()) { return false; } *v = json->get<int64_t>(); return true; } bool NlohmannDeserializer::deserialize(dap::number* v) const { if (!json->is_number()) { return false; } *v = json->get<double>(); return true; } bool NlohmannDeserializer::deserialize(dap::string* v) const { if (!json->is_string()) { return false; } *v = json->get<std::string>(); return true; } bool NlohmannDeserializer::deserialize(dap::object* v) const { v->reserve(json->size()); for (auto& el : json->items()) { NlohmannDeserializer d(&el.value()); dap::any val; if (!d.deserialize(&val)) { return false; } (*v)[el.key()] = val; } return true; } bool NlohmannDeserializer::deserialize(dap::any* v) const { if (json->is_boolean()) { *v = dap::boolean(json->get<bool>()); } else if (json->is_number_float()) { *v = dap::number(json->get<double>()); } else if (json->is_number_integer()) { *v = dap::integer(json->get<int64_t>()); } else if (json->is_string()) { *v = json->get<std::string>(); } else if (json->is_object()) { dap::object obj; if (!deserialize(&obj)) { return false; } *v = obj; } else if (json->is_array()) { dap::array<any> arr; if (!deserialize(&arr)) { return false; } *v = arr; } else if (json->is_null()) { *v = null(); } else { return false; } return true; } size_t NlohmannDeserializer::count() const { return json->size(); } bool NlohmannDeserializer::array( const std::function<bool(dap::Deserializer*)>& cb) const { if (!json->is_array()) { return false; } for (size_t i = 0; i < json->size(); i++) { NlohmannDeserializer d(&(*json)[i]); if (!cb(&d)) { return false; } } return true; } bool NlohmannDeserializer::field( const std::string& name, const std::function<bool(dap::Deserializer*)>& cb) const { if (!json->is_structured()) { return false; } auto it = json->find(name); if (it == json->end()) { return cb(&NullDeserializer::instance); } auto obj = *it; NlohmannDeserializer d(&obj); return cb(&d); } NlohmannSerializer::NlohmannSerializer() : json(new nlohmann::json()), ownsJson(true) {} NlohmannSerializer::NlohmannSerializer(nlohmann::json* json) : json(json), ownsJson(false) {} NlohmannSerializer::~NlohmannSerializer() { if (ownsJson) { delete json; } } std::string NlohmannSerializer::dump() const { return json->dump(); } bool NlohmannSerializer::serialize(dap::boolean v) { *json = (bool)v; return true; } bool NlohmannSerializer::serialize(dap::integer v) { *json = (int64_t)v; return true; } bool NlohmannSerializer::serialize(dap::number v) { *json = (double)v; return true; } bool NlohmannSerializer::serialize(const dap::string& v) { *json = v; return true; } bool NlohmannSerializer::serialize(const dap::object& v) { if (!json->is_object()) { *json = nlohmann::json::object(); } for (auto& it : v) { NlohmannSerializer s(&(*json)[it.first]); if (!s.serialize(it.second)) { return false; } } return true; } bool NlohmannSerializer::serialize(const dap::any& v) { if (v.is<dap::boolean>()) { *json = (bool)v.get<dap::boolean>(); } else if (v.is<dap::integer>()) { *json = (int64_t)v.get<dap::integer>(); } else if (v.is<dap::number>()) { *json = (double)v.get<dap::number>(); } else if (v.is<dap::string>()) { *json = v.get<dap::string>(); } else if (v.is<dap::object>()) { // reachable if dap::object nested is inside other dap::object return serialize(v.get<dap::object>()); } else if (v.is<dap::null>()) { } else { // reachable if array or custom serialized type is nested inside other auto type = get_any_type(v); auto value = get_any_val(v); if (type && value) { return type->serialize(this, value); } return false; } return true; } bool NlohmannSerializer::array( size_t count, const std::function<bool(dap::Serializer*)>& cb) { *json = std::vector<int>(); for (size_t i = 0; i < count; i++) { NlohmannSerializer s(&(*json)[i]); if (!cb(&s)) { return false; } } return true; } bool NlohmannSerializer::object( const std::function<bool(dap::FieldSerializer*)>& cb) { struct FS : public FieldSerializer { nlohmann::json* const json; FS(nlohmann::json* json) : json(json) {} bool field(const std::string& name, const SerializeFunc& cb) override { NlohmannSerializer s(&(*json)[name]); auto res = cb(&s); if (s.removed) { json->erase(name); } return res; } }; *json = nlohmann::json({}, false, nlohmann::json::value_t::object); FS fs{json}; return cb(&fs); } void NlohmannSerializer::remove() { removed = true; } } // namespace json } // namespace dap