| // 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 "rapid_json_serializer.h" |
| |
| #include "null_json_serializer.h" |
| |
| #include <rapidjson/document.h> |
| #include <rapidjson/prettywriter.h> |
| |
| namespace dap { |
| namespace json { |
| |
| RapidDeserializer::RapidDeserializer(const std::string& str) |
| : doc(new rapidjson::Document()) { |
| doc->Parse(str.c_str()); |
| } |
| |
| RapidDeserializer::RapidDeserializer(rapidjson::Value* json) : val(json) {} |
| |
| RapidDeserializer::~RapidDeserializer() { |
| delete doc; |
| } |
| |
| bool RapidDeserializer::deserialize(dap::boolean* v) const { |
| if (!json()->IsBool()) { |
| return false; |
| } |
| *v = json()->GetBool(); |
| return true; |
| } |
| |
| bool RapidDeserializer::deserialize(dap::integer* v) const { |
| if (json()->IsInt()) { |
| *v = json()->GetInt(); |
| return true; |
| } else if (json()->IsUint()) { |
| *v = static_cast<int64_t>(json()->GetUint()); |
| return true; |
| } else if (json()->IsInt64()) { |
| *v = json()->GetInt64(); |
| return true; |
| } else if (json()->IsUint64()) { |
| *v = static_cast<int64_t>(json()->GetUint64()); |
| return true; |
| } |
| return false; |
| } |
| |
| bool RapidDeserializer::deserialize(dap::number* v) const { |
| if (!json()->IsNumber()) { |
| return false; |
| } |
| *v = json()->GetDouble(); |
| return true; |
| } |
| |
| bool RapidDeserializer::deserialize(dap::string* v) const { |
| if (!json()->IsString()) { |
| return false; |
| } |
| *v = json()->GetString(); |
| return true; |
| } |
| |
| bool RapidDeserializer::deserialize(dap::object* v) const { |
| v->reserve(json()->MemberCount()); |
| for (auto el = json()->MemberBegin(); el != json()->MemberEnd(); el++) { |
| dap::any el_val; |
| RapidDeserializer d(&(el->value)); |
| if (!d.deserialize(&el_val)) { |
| return false; |
| } |
| (*v)[el->name.GetString()] = el_val; |
| } |
| return true; |
| } |
| |
| bool RapidDeserializer::deserialize(dap::any* v) const { |
| if (json()->IsBool()) { |
| *v = dap::boolean(json()->GetBool()); |
| } else if (json()->IsDouble()) { |
| *v = dap::number(json()->GetDouble()); |
| } else if (json()->IsInt()) { |
| *v = dap::integer(json()->GetInt()); |
| } else if (json()->IsString()) { |
| *v = dap::string(json()->GetString()); |
| } else if (json()->IsNull()) { |
| *v = null(); |
| } else if (json()->IsObject()) { |
| dap::object obj; |
| if (!deserialize(&obj)) { |
| return false; |
| } |
| *v = obj; |
| } else if (json()->IsArray()){ |
| dap::array<any> arr; |
| if (!deserialize(&arr)){ |
| return false; |
| } |
| *v = arr; |
| } else { |
| return false; |
| } |
| return true; |
| } |
| |
| size_t RapidDeserializer::count() const { |
| return json()->Size(); |
| } |
| |
| bool RapidDeserializer::array( |
| const std::function<bool(dap::Deserializer*)>& cb) const { |
| if (!json()->IsArray()) { |
| return false; |
| } |
| for (uint32_t i = 0; i < json()->Size(); i++) { |
| RapidDeserializer d(&(*json())[i]); |
| if (!cb(&d)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool RapidDeserializer::field( |
| const std::string& name, |
| const std::function<bool(dap::Deserializer*)>& cb) const { |
| if (!json()->IsObject()) { |
| return false; |
| } |
| auto it = json()->FindMember(name.c_str()); |
| if (it == json()->MemberEnd()) { |
| return cb(&NullDeserializer::instance); |
| } |
| RapidDeserializer d(&(it->value)); |
| return cb(&d); |
| } |
| |
| RapidSerializer::RapidSerializer() |
| : doc(new rapidjson::Document(rapidjson::kObjectType)), |
| allocator(doc->GetAllocator()) {} |
| |
| RapidSerializer::RapidSerializer(rapidjson::Value* json, |
| rapidjson::Document::AllocatorType& allocator) |
| : val(json), allocator(allocator) {} |
| |
| RapidSerializer::~RapidSerializer() { |
| delete doc; |
| } |
| |
| std::string RapidSerializer::dump() const { |
| rapidjson::StringBuffer sb; |
| rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); |
| json()->Accept(writer); |
| return sb.GetString(); |
| } |
| |
| bool RapidSerializer::serialize(dap::boolean v) { |
| json()->SetBool(v); |
| return true; |
| } |
| |
| bool RapidSerializer::serialize(dap::integer v) { |
| json()->SetInt64(v); |
| return true; |
| } |
| |
| bool RapidSerializer::serialize(dap::number v) { |
| json()->SetDouble(v); |
| return true; |
| } |
| |
| bool RapidSerializer::serialize(const dap::string& v) { |
| json()->SetString(v.data(), static_cast<uint32_t>(v.length()), allocator); |
| return true; |
| } |
| |
| bool RapidSerializer::serialize(const dap::object& v) { |
| if (!json()->IsObject()) { |
| json()->SetObject(); |
| } |
| for (auto& it : v) { |
| if (!json()->HasMember(it.first.c_str())) { |
| rapidjson::Value name_value{it.first.c_str(), allocator}; |
| json()->AddMember(name_value, rapidjson::Value(), allocator); |
| } |
| rapidjson::Value& member = (*json())[it.first.c_str()]; |
| RapidSerializer s(&member, allocator); |
| if (!s.serialize(it.second)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool RapidSerializer::serialize(const dap::any& v) { |
| if (v.is<dap::boolean>()) { |
| json()->SetBool((bool)v.get<dap::boolean>()); |
| } else if (v.is<dap::integer>()) { |
| json()->SetInt64(v.get<dap::integer>()); |
| } else if (v.is<dap::number>()) { |
| json()->SetDouble((double)v.get<dap::number>()); |
| } else if (v.is<dap::string>()) { |
| auto s = v.get<dap::string>(); |
| json()->SetString(s.data(), static_cast<uint32_t>(s.length()), allocator); |
| } 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 dap::object |
| 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 RapidSerializer::array(size_t count, |
| const std::function<bool(dap::Serializer*)>& cb) { |
| if (!json()->IsArray()) { |
| json()->SetArray(); |
| } |
| |
| while (count > json()->Size()) { |
| json()->PushBack(rapidjson::Value(), allocator); |
| } |
| |
| for (uint32_t i = 0; i < count; i++) { |
| RapidSerializer s(&(*json())[i], allocator); |
| if (!cb(&s)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool RapidSerializer::object( |
| const std::function<bool(dap::FieldSerializer*)>& cb) { |
| struct FS : public FieldSerializer { |
| rapidjson::Value* const json; |
| rapidjson::Document::AllocatorType& allocator; |
| |
| FS(rapidjson::Value* json, rapidjson::Document::AllocatorType& allocator) |
| : json(json), allocator(allocator) {} |
| bool field(const std::string& name, const SerializeFunc& cb) override { |
| if (!json->HasMember(name.c_str())) { |
| rapidjson::Value name_value{name.c_str(), allocator}; |
| json->AddMember(name_value, rapidjson::Value(), allocator); |
| } |
| rapidjson::Value& member = (*json)[name.c_str()]; |
| RapidSerializer s(&member, allocator); |
| auto res = cb(&s); |
| if (s.removed) { |
| json->RemoveMember(name.c_str()); |
| } |
| return res; |
| } |
| }; |
| |
| if (!json()->IsObject()) { |
| json()->SetObject(); |
| } |
| FS fs{json(), allocator}; |
| return cb(&fs); |
| } |
| |
| void RapidSerializer::remove() { |
| removed = true; |
| } |
| |
| } // namespace json |
| } // namespace dap |