From 6d6cbf17d7d783777a6756008982e99bef6e316f Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 1 Dec 2020 16:30:45 +0000 Subject: [PATCH] Add support for rapidjson as the JSON library nlohmann is still the default, but if `CPPDAP_JSON_DIR` points to rapidjson, then this will be used instead Most of this was upstreamed from: https://fuchsia-review.googlesource.com/c/third_party/github.com/google/cppdap/+/456566 --- CMakeLists.txt | 31 ++- src/chan.h | 2 +- src/io.cpp | 4 +- src/json_serializer.h | 127 ++------- ...lizer.cpp => nlohmann_json_serializer.cpp} | 97 +++---- src/nlohmann_json_serializer.h | 133 +++++++++ src/null_json_serializer.cpp | 23 ++ src/null_json_serializer.h | 47 ++++ src/rapid_json_serializer.cpp | 259 ++++++++++++++++++ src/rapid_json_serializer.h | 138 ++++++++++ src/socket.cpp | 2 +- src/typeof.cpp | 2 +- 12 files changed, 689 insertions(+), 176 deletions(-) rename src/{json_serializer.cpp => nlohmann_json_serializer.cpp} (61%) create mode 100644 src/nlohmann_json_serializer.h create mode 100644 src/null_json_serializer.cpp create mode 100644 src/null_json_serializer.h create mode 100644 src/rapid_json_serializer.cpp create mode 100644 src/rapid_json_serializer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a41d6ae..2ec3ac0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,14 +64,34 @@ if(CPPDAP_BUILD_TESTS) endif() endif(CPPDAP_BUILD_TESTS) +########################################################### +# JSON library +########################################################### +if(NOT DEFINED CPPDAP_JSON_LIBRARY) + # Attempt to detect JSON library from CPPDAP_JSON_DIR + if(NOT EXISTS "${CPPDAP_JSON_DIR}") + message(FATAL_ERROR "CPPDAP_JSON_DIR '${CPPDAP_JSON_DIR}' does not exist") + endif() + + if(EXISTS "${CPPDAP_JSON_DIR}/include/nlohmann") + set(CPPDAP_JSON_LIBRARY "nlohmann") + elseif(EXISTS "${CPPDAP_JSON_DIR}/include/rapidjson") + set(CPPDAP_JSON_LIBRARY "rapid") + else() + message(FATAL_ERROR "Could not determine JSON library from ${CPPDAP_JSON_LIBRARY}") + endif() +endif() +string(TOUPPER ${CPPDAP_JSON_LIBRARY} CPPDAP_JSON_LIBRARY_UPPER) + ########################################################### # File lists ########################################################### set(CPPDAP_LIST ${CPPDAP_SRC_DIR}/content_stream.cpp ${CPPDAP_SRC_DIR}/io.cpp - ${CPPDAP_SRC_DIR}/json_serializer.cpp + ${CPPDAP_SRC_DIR}/${CPPDAP_JSON_LIBRARY}_json_serializer.cpp ${CPPDAP_SRC_DIR}/network.cpp + ${CPPDAP_SRC_DIR}/null_json_serializer.cpp ${CPPDAP_SRC_DIR}/protocol_events.cpp ${CPPDAP_SRC_DIR}/protocol_requests.cpp ${CPPDAP_SRC_DIR}/protocol_response.cpp @@ -117,6 +137,11 @@ function(cppdap_set_target_options target) ) endif() + # Add define for JSON library in use + set_target_properties(${target} PROPERTIES + COMPILE_DEFINITIONS "CPPDAP_JSON_${CPPDAP_JSON_LIBRARY_UPPER}=1" + ) + # Treat all warnings as errors if(CPPDAP_WARNINGS_AS_ERRORS) if(MSVC) @@ -151,9 +176,7 @@ endfunction(cppdap_set_target_options) # dap add_library(cppdap STATIC ${CPPDAP_LIST}) -set_target_properties(cppdap PROPERTIES - POSITION_INDEPENDENT_CODE 1 -) +set_target_properties(cppdap PROPERTIES POSITION_INDEPENDENT_CODE 1) target_include_directories(cppdap PRIVATE "${CPPDAP_JSON_DIR}/include/") diff --git a/src/chan.h b/src/chan.h index c4183c2..f2345e9 100644 --- a/src/chan.h +++ b/src/chan.h @@ -87,4 +87,4 @@ void Chan::put(const T& in) { } // namespace dap -#endif // dap_chan_h \ No newline at end of file +#endif // dap_chan_h diff --git a/src/io.cpp b/src/io.cpp index 04db817..3ee972e 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -145,7 +145,7 @@ class File : public dap::ReaderWriter { const bool closable; std::mutex readMutex; std::mutex writeMutex; - std::atomic closed = { false }; + std::atomic closed = {false}; }; class ReaderSpy : public dap::Reader { @@ -254,4 +254,4 @@ bool writef(const std::shared_ptr& w, const char* msg, ...) { return w->write(buf, strlen(buf)); } -} // namespace dap \ No newline at end of file +} // namespace dap diff --git a/src/json_serializer.h b/src/json_serializer.h index 4ae4e11..9bc26d5 100644 --- a/src/json_serializer.h +++ b/src/json_serializer.h @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC +// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,119 +15,28 @@ #ifndef dap_json_serializer_h #define dap_json_serializer_h -#include "dap/protocol.h" -#include "dap/serialization.h" -#include "dap/types.h" - -#include +#if defined(CPPDAP_JSON_NLOHMANN) +#include "nlohmann_json_serializer.h" +#elif defined(CPPDAP_JSON_RAPID) +#include "rapid_json_serializer.h" +#else +#error "Unrecognised cppdap JSON library" +#endif namespace dap { namespace json { -struct Deserializer : public dap::Deserializer { - explicit Deserializer(const std::string&); - ~Deserializer(); - - // dap::Deserializer compliance - bool deserialize(boolean* v) const override; - bool deserialize(integer* v) const override; - bool deserialize(number* v) const override; - bool deserialize(string* v) const override; - bool deserialize(object* v) const override; - bool deserialize(any* v) const override; - size_t count() const override; - bool array(const std::function&) const override; - bool field(const std::string& name, - const std::function&) const override; - - // Unhide base overloads - template - inline bool field(const std::string& name, T* v) { - return dap::Deserializer::field(name, v); - } - - template ::has_custom_serialization>> - inline bool deserialize(T* v) const { - return dap::Deserializer::deserialize(v); - } - - template - inline bool deserialize(dap::array* v) const { - return dap::Deserializer::deserialize(v); - } - - template - inline bool deserialize(dap::optional* v) const { - return dap::Deserializer::deserialize(v); - } - - template - inline bool deserialize(dap::variant* v) const { - return dap::Deserializer::deserialize(v); - } - - template - inline bool field(const std::string& name, T* v) const { - return dap::Deserializer::deserialize(name, v); - } - - private: - Deserializer(const nlohmann::json*); - const nlohmann::json* const json; - const bool ownsJson; -}; - -struct Serializer : public dap::Serializer { - Serializer(); - ~Serializer(); - - std::string dump() const; - - // dap::Serializer compliance - bool serialize(boolean v) override; - bool serialize(integer v) override; - bool serialize(number v) override; - bool serialize(const string& v) override; - bool serialize(const dap::object& v) override; - bool serialize(const any& v) override; - bool array(size_t count, - const std::function&) override; - bool object(const std::function&) override; - void remove() override; - - // Unhide base overloads - template ::has_custom_serialization>> - inline bool serialize(const T& v) { - return dap::Serializer::serialize(v); - } - - template - inline bool serialize(const dap::array& v) { - return dap::Serializer::serialize(v); - } - - template - inline bool serialize(const dap::optional& v) { - return dap::Serializer::serialize(v); - } - - template - inline bool serialize(const dap::variant& v) { - return dap::Serializer::serialize(v); - } - - inline bool serialize(const char* v) { return dap::Serializer::serialize(v); } - - private: - Serializer(nlohmann::json*); - nlohmann::json* const json; - const bool ownsJson; - bool removed = false; -}; +#if defined(CPPDAP_JSON_NLOHMANN) +using Deserializer = NlohmannDeserializer; +using Serializer = NlohmannSerializer; +#elif defined(CPPDAP_JSON_RAPID) +using Deserializer = RapidDeserializer; +using Serializer = RapidSerializer; +#else +#error "Unrecognised cppdap JSON library" +#endif } // namespace json } // namespace dap -#endif // dap_json_serializer_h \ No newline at end of file +#endif // dap_json_serializer_h diff --git a/src/json_serializer.cpp b/src/nlohmann_json_serializer.cpp similarity index 61% rename from src/json_serializer.cpp rename to src/nlohmann_json_serializer.cpp index 9d44dc1..7aa0399 100644 --- a/src/json_serializer.cpp +++ b/src/nlohmann_json_serializer.cpp @@ -12,55 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "json_serializer.h" +#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 -namespace { - -struct NullDeserializer : public dap::Deserializer { - static NullDeserializer instance; - - bool deserialize(dap::boolean*) const override { return false; } - bool deserialize(dap::integer*) const override { return false; } - bool deserialize(dap::number*) const override { return false; } - bool deserialize(dap::string*) const override { return false; } - bool deserialize(dap::object*) const override { return false; } - bool deserialize(dap::any*) const override { return false; } - size_t count() const override { return 0; } - bool array(const std::function&) const override { - return false; - } - bool field(const std::string&, - const std::function&) const override { - return false; - } -}; - -NullDeserializer NullDeserializer::instance; - -} // anonymous namespace - namespace dap { namespace json { -Deserializer::Deserializer(const std::string& str) +NlohmannDeserializer::NlohmannDeserializer(const std::string& str) : json(new nlohmann::json(nlohmann::json::parse(str, nullptr, false))), ownsJson(true) {} -Deserializer::Deserializer(const nlohmann::json* json) +NlohmannDeserializer::NlohmannDeserializer(const nlohmann::json* json) : json(json), ownsJson(false) {} -Deserializer::~Deserializer() { +NlohmannDeserializer::~NlohmannDeserializer() { if (ownsJson) { delete json; } } -bool Deserializer::deserialize(dap::boolean* v) const { +bool NlohmannDeserializer::deserialize(dap::boolean* v) const { if (!json->is_boolean()) { return false; } @@ -68,7 +45,7 @@ bool Deserializer::deserialize(dap::boolean* v) const { return true; } -bool Deserializer::deserialize(dap::integer* v) const { +bool NlohmannDeserializer::deserialize(dap::integer* v) const { if (!json->is_number_integer()) { return false; } @@ -76,7 +53,7 @@ bool Deserializer::deserialize(dap::integer* v) const { return true; } -bool Deserializer::deserialize(dap::number* v) const { +bool NlohmannDeserializer::deserialize(dap::number* v) const { if (!json->is_number()) { return false; } @@ -84,7 +61,7 @@ bool Deserializer::deserialize(dap::number* v) const { return true; } -bool Deserializer::deserialize(dap::string* v) const { +bool NlohmannDeserializer::deserialize(dap::string* v) const { if (!json->is_string()) { return false; } @@ -92,10 +69,10 @@ bool Deserializer::deserialize(dap::string* v) const { return true; } -bool Deserializer::deserialize(dap::object* v) const { +bool NlohmannDeserializer::deserialize(dap::object* v) const { v->reserve(json->size()); for (auto& el : json->items()) { - Deserializer d(&el.value()); + NlohmannDeserializer d(&el.value()); dap::any val; if (!d.deserialize(&val)) { return false; @@ -105,7 +82,7 @@ bool Deserializer::deserialize(dap::object* v) const { return true; } -bool Deserializer::deserialize(dap::any* v) const { +bool NlohmannDeserializer::deserialize(dap::any* v) const { if (json->is_boolean()) { *v = dap::boolean(json->get()); } else if (json->is_number_float()) { @@ -122,17 +99,17 @@ bool Deserializer::deserialize(dap::any* v) const { return true; } -size_t Deserializer::count() const { +size_t NlohmannDeserializer::count() const { return json->size(); } -bool Deserializer::array( +bool NlohmannDeserializer::array( const std::function& cb) const { if (!json->is_array()) { return false; } for (size_t i = 0; i < json->size(); i++) { - Deserializer d(&(*json)[i]); + NlohmannDeserializer d(&(*json)[i]); if (!cb(&d)) { return false; } @@ -140,7 +117,7 @@ bool Deserializer::array( return true; } -bool Deserializer::field( +bool NlohmannDeserializer::field( const std::string& name, const std::function& cb) const { if (!json->is_structured()) { @@ -151,47 +128,49 @@ bool Deserializer::field( return cb(&NullDeserializer::instance); } auto obj = *it; - Deserializer d(&obj); + NlohmannDeserializer d(&obj); return cb(&d); } -Serializer::Serializer() : json(new nlohmann::json()), ownsJson(true) {} +NlohmannSerializer::NlohmannSerializer() + : json(new nlohmann::json()), ownsJson(true) {} -Serializer::Serializer(nlohmann::json* json) : json(json), ownsJson(false) {} +NlohmannSerializer::NlohmannSerializer(nlohmann::json* json) + : json(json), ownsJson(false) {} -Serializer::~Serializer() { +NlohmannSerializer::~NlohmannSerializer() { if (ownsJson) { delete json; } } -std::string Serializer::dump() const { +std::string NlohmannSerializer::dump() const { return json->dump(); } -bool Serializer::serialize(dap::boolean v) { +bool NlohmannSerializer::serialize(dap::boolean v) { *json = (bool)v; return true; } -bool Serializer::serialize(dap::integer v) { +bool NlohmannSerializer::serialize(dap::integer v) { *json = (int)v; return true; } -bool Serializer::serialize(dap::number v) { +bool NlohmannSerializer::serialize(dap::number v) { *json = (double)v; return true; } -bool Serializer::serialize(const dap::string& v) { +bool NlohmannSerializer::serialize(const dap::string& v) { *json = v; return true; } -bool Serializer::serialize(const dap::object& v) { +bool NlohmannSerializer::serialize(const dap::object& v) { for (auto& it : v) { - Serializer s(&(*json)[it.first]); + NlohmannSerializer s(&(*json)[it.first]); if (!s.serialize(it.second)) { return false; } @@ -199,7 +178,7 @@ bool Serializer::serialize(const dap::object& v) { return true; } -bool Serializer::serialize(const dap::any& v) { +bool NlohmannSerializer::serialize(const dap::any& v) { if (v.is()) { *json = (bool)v.get(); } else if (v.is()) { @@ -216,11 +195,12 @@ bool Serializer::serialize(const dap::any& v) { return true; } -bool Serializer::array(size_t count, - const std::function& cb) { +bool NlohmannSerializer::array( + size_t count, + const std::function& cb) { *json = std::vector(); for (size_t i = 0; i < count; i++) { - Serializer s(&(*json)[i]); + NlohmannSerializer s(&(*json)[i]); if (!cb(&s)) { return false; } @@ -228,13 +208,14 @@ bool Serializer::array(size_t count, return true; } -bool Serializer::object(const std::function& cb) { +bool NlohmannSerializer::object( + const std::function& 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 { - Serializer s(&(*json)[name]); + NlohmannSerializer s(&(*json)[name]); auto res = cb(&s); if (s.removed) { json->erase(name); @@ -248,7 +229,7 @@ bool Serializer::object(const std::function& cb) { return cb(&fs); } -void Serializer::remove() { +void NlohmannSerializer::remove() { removed = true; } diff --git a/src/nlohmann_json_serializer.h b/src/nlohmann_json_serializer.h new file mode 100644 index 0000000..f75fe78 --- /dev/null +++ b/src/nlohmann_json_serializer.h @@ -0,0 +1,133 @@ +// 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. + +#ifndef dap_nlohmann_json_serializer_h +#define dap_nlohmann_json_serializer_h + +#include "dap/protocol.h" +#include "dap/serialization.h" +#include "dap/types.h" + +#include + +namespace dap { +namespace json { + +struct NlohmannDeserializer : public dap::Deserializer { + explicit NlohmannDeserializer(const std::string&); + ~NlohmannDeserializer(); + + // dap::Deserializer compliance + bool deserialize(boolean* v) const override; + bool deserialize(integer* v) const override; + bool deserialize(number* v) const override; + bool deserialize(string* v) const override; + bool deserialize(object* v) const override; + bool deserialize(any* v) const override; + size_t count() const override; + bool array(const std::function&) const override; + bool field(const std::string& name, + const std::function&) const override; + + // Unhide base overloads + template + inline bool field(const std::string& name, T* v) { + return dap::Deserializer::field(name, v); + } + + template ::has_custom_serialization>> + inline bool deserialize(T* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool deserialize(dap::array* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool deserialize(dap::optional* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool deserialize(dap::variant* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool field(const std::string& name, T* v) const { + return dap::Deserializer::deserialize(name, v); + } + + private: + NlohmannDeserializer(const nlohmann::json*); + const nlohmann::json* const json; + const bool ownsJson; +}; + +struct NlohmannSerializer : public dap::Serializer { + NlohmannSerializer(); + ~NlohmannSerializer(); + + std::string dump() const; + + // dap::Serializer compliance + bool serialize(boolean v) override; + bool serialize(integer v) override; + bool serialize(number v) override; + bool serialize(const string& v) override; + bool serialize(const dap::object& v) override; + bool serialize(const any& v) override; + bool array(size_t count, + const std::function&) override; + bool object(const std::function&) override; + void remove() override; + + // Unhide base overloads + template ::has_custom_serialization>> + inline bool serialize(const T& v) { + return dap::Serializer::serialize(v); + } + + template + inline bool serialize(const dap::array& v) { + return dap::Serializer::serialize(v); + } + + template + inline bool serialize(const dap::optional& v) { + return dap::Serializer::serialize(v); + } + + template + inline bool serialize(const dap::variant& v) { + return dap::Serializer::serialize(v); + } + + inline bool serialize(const char* v) { return dap::Serializer::serialize(v); } + + private: + NlohmannSerializer(nlohmann::json*); + nlohmann::json* const json; + const bool ownsJson; + bool removed = false; +}; + +} // namespace json +} // namespace dap + +#endif // dap_nlohmann_json_serializer_h \ No newline at end of file diff --git a/src/null_json_serializer.cpp b/src/null_json_serializer.cpp new file mode 100644 index 0000000..5aa5a03 --- /dev/null +++ b/src/null_json_serializer.cpp @@ -0,0 +1,23 @@ +// Copyright 2020 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 "null_json_serializer.h" + +namespace dap { +namespace json { + +NullDeserializer NullDeserializer::instance; + +} // namespace json +} // namespace dap diff --git a/src/null_json_serializer.h b/src/null_json_serializer.h new file mode 100644 index 0000000..c92b99a --- /dev/null +++ b/src/null_json_serializer.h @@ -0,0 +1,47 @@ +// Copyright 2020 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. + +#ifndef dap_null_json_serializer_h +#define dap_null_json_serializer_h + +#include "dap/protocol.h" +#include "dap/serialization.h" +#include "dap/types.h" + +namespace dap { +namespace json { + +struct NullDeserializer : public dap::Deserializer { + static NullDeserializer instance; + + bool deserialize(dap::boolean*) const override { return false; } + bool deserialize(dap::integer*) const override { return false; } + bool deserialize(dap::number*) const override { return false; } + bool deserialize(dap::string*) const override { return false; } + bool deserialize(dap::object*) const override { return false; } + bool deserialize(dap::any*) const override { return false; } + size_t count() const override { return 0; } + bool array(const std::function&) const override { + return false; + } + bool field(const std::string&, + const std::function&) const override { + return false; + } +}; + +} // namespace json +} // namespace dap + +#endif // dap_null_json_serializer_h diff --git a/src/rapid_json_serializer.cpp b/src/rapid_json_serializer.cpp new file mode 100644 index 0000000..35cf7e5 --- /dev/null +++ b/src/rapid_json_serializer.cpp @@ -0,0 +1,259 @@ +// 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 +#include + +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()) { + return false; + } + *v = json()->GetInt(); + return true; +} + +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 val; + RapidDeserializer d(&(el->value)); + if (!d.deserialize(&val)) { + return false; + } + (*v)[el->name.GetString()] = 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 { + return false; + } + return true; +} + +size_t RapidDeserializer::count() const { + return json()->Size(); +} + +bool RapidDeserializer::array( + const std::function& 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& 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 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(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()) { + json()->SetBool((bool)v.get()); + } else if (v.is()) { + json()->SetInt((int)v.get()); + } else if (v.is()) { + json()->SetDouble((double)v.get()); + } else if (v.is()) { + auto s = v.get(); + json()->SetString(s.data(), static_cast(s.length()), allocator); + } else if (v.is()) { + } else { + return false; + } + + return true; +} + +bool RapidSerializer::array(size_t count, + const std::function& 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& 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 diff --git a/src/rapid_json_serializer.h b/src/rapid_json_serializer.h new file mode 100644 index 0000000..6e83384 --- /dev/null +++ b/src/rapid_json_serializer.h @@ -0,0 +1,138 @@ +// 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. + +#ifndef dap_rapid_json_serializer_h +#define dap_rapid_json_serializer_h + +#include "dap/protocol.h" +#include "dap/serialization.h" +#include "dap/types.h" + +#include + +namespace dap { +namespace json { + +struct RapidDeserializer : public dap::Deserializer { + explicit RapidDeserializer(const std::string&); + ~RapidDeserializer(); + + // dap::Deserializer compliance + bool deserialize(boolean* v) const override; + bool deserialize(integer* v) const override; + bool deserialize(number* v) const override; + bool deserialize(string* v) const override; + bool deserialize(object* v) const override; + bool deserialize(any* v) const override; + size_t count() const override; + bool array(const std::function&) const override; + bool field(const std::string& name, + const std::function&) const override; + + // Unhide base overloads + template + inline bool field(const std::string& name, T* v) { + return dap::Deserializer::field(name, v); + } + + template ::has_custom_serialization>> + inline bool deserialize(T* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool deserialize(dap::array* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool deserialize(dap::optional* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool deserialize(dap::variant* v) const { + return dap::Deserializer::deserialize(v); + } + + template + inline bool field(const std::string& name, T* v) const { + return dap::Deserializer::deserialize(name, v); + } + + inline rapidjson::Value* json() const { return (val == nullptr) ? doc : val; } + + private: + RapidDeserializer(rapidjson::Value*); + rapidjson::Document* const doc = nullptr; + rapidjson::Value* const val = nullptr; +}; + +struct RapidSerializer : public dap::Serializer { + RapidSerializer(); + ~RapidSerializer(); + + std::string dump() const; + + // dap::Serializer compliance + bool serialize(boolean v) override; + bool serialize(integer v) override; + bool serialize(number v) override; + bool serialize(const string& v) override; + bool serialize(const dap::object& v) override; + bool serialize(const any& v) override; + bool array(size_t count, + const std::function&) override; + bool object(const std::function&) override; + void remove() override; + + // Unhide base overloads + template ::has_custom_serialization>> + inline bool serialize(const T& v) { + return dap::Serializer::serialize(v); + } + + template + inline bool serialize(const dap::array& v) { + return dap::Serializer::serialize(v); + } + + template + inline bool serialize(const dap::optional& v) { + return dap::Serializer::serialize(v); + } + + template + inline bool serialize(const dap::variant& v) { + return dap::Serializer::serialize(v); + } + + inline bool serialize(const char* v) { return dap::Serializer::serialize(v); } + + inline rapidjson::Value* json() const { return (val == nullptr) ? doc : val; } + + private: + RapidSerializer(rapidjson::Value*, rapidjson::Document::AllocatorType&); + rapidjson::Document* const doc = nullptr; + rapidjson::Value* const val = nullptr; + rapidjson::Document::AllocatorType& allocator; + bool removed = false; +}; + +} // namespace json +} // namespace dap + +#endif // dap_rapid_json_serializer_h diff --git a/src/socket.cpp b/src/socket.cpp index 2e54580..998fed9 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -302,7 +302,7 @@ std::shared_ptr Socket::connect(const char* address, timeval tv; tv.tv_sec = microseconds / 1000000; - tv.tv_usec = microseconds - (tv.tv_sec * 1000000); + tv.tv_usec = microseconds - static_cast(tv.tv_sec * 1000000); res = select(static_cast(socket + 1), nullptr, &fdset, nullptr, &tv); if (res > 0 && !errored(socket) && setBlocking(socket, true)) { out = shared; diff --git a/src/typeof.cpp b/src/typeof.cpp index a5685d3..055421c 100644 --- a/src/typeof.cpp +++ b/src/typeof.cpp @@ -130,7 +130,7 @@ const TypeInfo* TypeOf::type() { } void TypeInfo::deleteOnExit(TypeInfo* ti) { - return TypeInfos::get()->types.emplace_back(std::unique_ptr(ti)); + TypeInfos::get()->types.emplace_back(std::unique_ptr(ti)); } void initialize() {