From b52b0fcc82a247638b6d162daf7f87eab3592882 Mon Sep 17 00:00:00 2001 From: Mutzi Date: Mon, 2 Oct 2023 09:50:27 +0200 Subject: [PATCH] Replaced json in cpp with RapidJson --- src/generators/cpp_s.rs | 31 ++++++++ templates/cpp_server.rs.cpp | 67 +++++++---------- templates/cpp_server.rs.h | 22 ++++-- templates/cpp_server_json.rs.cpp | 121 +++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 45 deletions(-) create mode 100644 templates/cpp_server_json.rs.cpp diff --git a/src/generators/cpp_s.rs b/src/generators/cpp_s.rs index aa0ee3b..51b83f7 100644 --- a/src/generators/cpp_s.rs +++ b/src/generators/cpp_s.rs @@ -45,6 +45,37 @@ pub fn call_args(method: &crate::data::MethodTy) -> String { .join(", ") } +pub fn json_write(ty: &crate::data::FieldTy) -> String { + use crate::data::Types; + match &ty.ty { + Types::String => format!("__w.String({});", ty.name), + Types::Bool => format!("__w.Bool({});", ty.name), + Types::F32 | Types::F64 => format!("__w.Double({});", ty.name), + Types::I8 | Types::I16 | Types::I32 | Types::I64 => format!("__w.Int64({});", ty.name), + Types::U8 | Types::U16 | Types::U32 | Types::U64 => format!("__w.Uint64({});", ty.name), + Types::Named(_) => format!("{} >> __w;", ty.name), + Types::Optional(inner) => { + let inner = crate::data::FieldTy { name: format!("({}.value())", ty.name), ty: (**inner).clone() }; + let inner = json_write(&inner); + format!( +"if ({}.has_value()) {{ + {} + }} else __w.Null();", ty.name, inner) + }, + Types::Array(inner) => { + let inner_var_name = format!("__{}__entry", ty.name); + let inner = crate::data::FieldTy { name: inner_var_name.clone(), ty: (**inner).clone() }; + let inner = json_write(&inner); + format!( +"__w.StartArray(); + for (const auto &{} : {}) {{ + {} + }} + __w.EndArray();", inner_var_name, ty.name, inner) + } + } +} + pub fn gen(file_base_name: &std::path::PathBuf, rpc: &RPC) { let header_name = file_base_name.with_extension("h"); let header_name = header_name.file_name().unwrap().to_str().unwrap(); diff --git a/templates/cpp_server.rs.cpp b/templates/cpp_server.rs.cpp index 3dd2d44..6f57066 100644 --- a/templates/cpp_server.rs.cpp +++ b/templates/cpp_server.rs.cpp @@ -1,44 +1,25 @@ @use crate::data::RPC; @use crate::generators::cpp_s::*; +@use super::cpp_server_json_cpp; @(header_name: &str, rpc: &RPC) #include "@header_name" -using json = nlohmann::json; - -namespace nlohmann @{ - template - struct adl_serializer> @{ - static void to_json(json &j, const std::optional &v) @{ - if (v.has_value()) - j = v.value(); - else - j = nullptr; - @} - - static void from_json(const json &j, std::optional &v) @{ - if (j.is_null()) - v.reset(); - else - v = j.get(); - @} - @}; -@} - -namespace mrpc @{ -@for s in &rpc.structs { -void to_json(nlohmann::json &j, const @s.name &v) @{ -@for f in &s.fields { j["@f.name"] = v.@f.name; -} -@} -void from_json(const nlohmann::json &j, @s.name &v) @{ -@for f in &s.fields { j.at("@f.name").get_to(v.@f.name); -} -@} -} +@:cpp_server_json_cpp(rpc) template -void send_msg(crow::websocket::connection &c, uint64_t id, const T &v) @{ - c.send_text(json@{@{"id", id@},@{"data", v@}@}.dump()); +void send_msg(crow::websocket::connection &c, std::uint64_t id, const T &v) @{ + rapidjson::StringBuffer s; + mrpc::MRPCJWriter writer@{s@}; + writer.StartObject(); + writer.Key("id"); + writer.Uint64(id); + writer.Key("data"); + if constexpr (std::is_same_v) + writer.Null(); + else + v >> writer; + writer.EndObject(); + c.send_text(s.GetString()); @} void mrpc::MRPCStreamImpl::close() noexcept @{ @@ -65,12 +46,18 @@ void mrpc::MRPCServer::install(crow::SimpleApp &app, std::string &&route) @{ catch (const std::exception &_) @{@} @}); @} -void mrpc::MRPCServer::msg_handler(crow::websocket::connection &__c, const std::string &__msg, bool) @{ - json __j = json::parse(__msg); - std::uint64_t __id = __j.at("id"); - std::string __service = __j.at("service"), __method = __j.at("method"); +void mrpc::MRPCServer::msg_handler(crow::websocket::connection &__c, std::string __msg, bool) @{ + rapidjson::Document __j; + __j.ParseInsitu(__msg.data()); + if (__j.HasParseError()) + throw std::exception@{@}; + std::uint64_t __id; std::string __service, __method; + json_get(__j, "id", __id); json_get(__j, "service", __service); json_get(__j, "method", __method); try @{ - json __data = __j.at("data"); + auto __data_member = __j.FindMember("data"); + if (__data_member == __j.MemberEnd() || !__data_member->value.IsObject()) + throw std::exception@{@}; + auto &__data = __data_member->value; @for (si, s) in rpc.services.iter().enumerate() { @if si > 0 {else }if (__service == "@s.name") @{ @for (mi, m) in s.methods.iter().enumerate() { @@ -79,7 +66,7 @@ void mrpc::MRPCServer::msg_handler(crow::websocket::connection &__c, const std:: auto __stream = std::make_shared>(&__c, __id); @{ std::lock_guard guard@{__streams_mutex@}; __streams.emplace(&__c, __stream); @} } -@for (name, ty) in m.args.iter().map(|a| (&a.name, ty_to_str(&a.ty))) { @ty @name = __data.at("@name"); +@for (name, ty) in m.args.iter().map(|a| (&a.name, ty_to_str(&a.ty))) { @ty @name; json_get<@ty>(__data, "@name", @name); } @if m.ret_stream || m.ret.is_none() {@(s.name)_@(m.name)(@call_args(m));} else {send_msg(__c, __id, @(s.name)_@(m.name)(@call_args(m)));} diff --git a/templates/cpp_server.rs.h b/templates/cpp_server.rs.h index fbbad8e..8a43e6c 100644 --- a/templates/cpp_server.rs.h +++ b/templates/cpp_server.rs.h @@ -14,9 +14,13 @@ #include #include #include -#include +#define RAPIDJSON_HAS_STDSTRING 1 +#include +#include +#include namespace mrpc @{ + using MRPCJWriter = rapidjson::Writer; @for e in &rpc.enums { enum struct @e.name : std::uint64_t @{ @e.values.iter().map(|(k,v)| format!("{k} = {v}")).join(",\n ") @@ -24,13 +28,13 @@ enum struct @e.name : std::uint64_t @{ } @for s in &rpc.structs { struct @s.name; -void to_json(nlohmann::json&, const @s.name&); -void from_json(const nlohmann::json&, @s.name&); } @for s in &rpc.structs { struct @s.name @{ @for f in &s.fields { @ty_to_str(&f.ty) @f.name; } + MRPCJWriter& operator >>(MRPCJWriter&) const; + @(s.name)& operator <<(const rapidjson::Value&); @}; } @@ -50,7 +54,15 @@ struct MRPCStream final : MRPCStreamImpl @{ bool send(const T &v) noexcept @{ if (!conn) return false; try @{ - conn->send_text(nlohmann::json@{@{"id", id@},@{"data", v@}@}.dump()); + rapidjson::StringBuffer s; + mrpc::MRPCJWriter writer@{s@}; + writer.StartObject(); + writer.Key("id"); + writer.Uint64(id); + writer.Key("data"); + v >> writer; + writer.EndObject(); + conn->send_text(s.GetString()); @} catch (const std::exception &_) @{ abort(); return false; @@ -64,7 +76,7 @@ struct MRPCServer @{ private: @for s in &rpc.services {@for m in &s.methods { virtual @method_ret(m) @(s.name)_@(m.name)(@method_args(m)) = 0; }} - virtual void msg_handler(crow::websocket::connection&, const std::string&, bool) final; + virtual void msg_handler(crow::websocket::connection&, std::string, bool) final; std::mutex __streams_mutex; std::unordered_multimap> __streams; diff --git a/templates/cpp_server_json.rs.cpp b/templates/cpp_server_json.rs.cpp new file mode 100644 index 0000000..a67f3ec --- /dev/null +++ b/templates/cpp_server_json.rs.cpp @@ -0,0 +1,121 @@ +@use crate::data::RPC; +@use crate::generators::cpp_s::*; + +@(rpc: &RPC) +template +void json_get(const rapidjson::Value &j, const char *key, T &v); +template +void json_get_inner(const rapidjson::Value&, T &v) = delete; + +template<> +inline void json_get_inner(const rapidjson::Value &member, std::string &v) @{ + if (!member.IsString()) + throw std::exception@{@}; + v = member.GetString(); +@} + +@for i in [8, 16, 32] { +template<> +inline void json_get_inner(const rapidjson::Value &member, std::int@(i)_t &v) @{ + if (!member.IsInt()) + throw std::exception@{@}; + v = member.GetInt(); +@} + +template<> +inline void json_get_inner(const rapidjson::Value &member, std::uint@(i)_t& v) @{ + if (!member.IsUint()) + throw std::exception@{@}; + v = member.GetUint(); +@} +} + +template<> +inline void json_get_inner(const rapidjson::Value &member, std::int64_t &v) @{ + if (!member.IsInt64()) + throw std::exception@{@}; + v = member.GetInt64(); +@} + +template<> +inline void json_get_inner(const rapidjson::Value &member, std::uint64_t& v) @{ + if (!member.IsUint64()) + throw std::exception@{@}; + v = member.GetUint64(); +@} + +template<> +inline void json_get_inner(const rapidjson::Value &member, bool &v) @{ + if (!member.IsBool()) + throw std::exception@{@}; + v = member.GetBool(); +@} + +template<> +inline void json_get_inner(const rapidjson::Value &member, double &v) @{ + if (!member.IsDouble()) + throw std::exception@{@}; + v = member.GetDouble(); +@} + +template +inline void json_get_inner(const rapidjson::Value &member, std::optional &v) @{ + if (member.IsNull()) + v = std::nullopt; + else @{ + T t; + json_get_inner(member, t); + v = std::move(t); + @} +@} + +template +inline void json_get_inner(const rapidjson::Value &member, std::vector &v) @{ + if (!member.IsArray()) + throw std::exception@{@}; + for (const auto &j : member.GetArray()) @{ + T t; + json_get_inner(j, t); + v.push_back(std::move(t)); + @} +@} + + +@for s in &rpc.structs { +template<> +inline void json_get_inner(const rapidjson::Value &__j, mrpc::@s.name &v) @{ + using namespace mrpc; +@for f in &s.fields { json_get<@ty_to_str(&f.ty)>(__j, "@f.name", v.@f.name); +}@} +} + +@for e in &rpc.enums { +template<> +inline void json_get_inner(const rapidjson::Value &j, mrpc::@e.name &v) @{ + json_get_inner(j, (std::uint64_t&)v); +@} +mrpc::MRPCJWriter& operator >>(const mrpc::@e.name &v, mrpc::MRPCJWriter &w) @{ + w.Uint64((std::uint64_t)v); + return w; +@} +} + +template +inline void json_get(const rapidjson::Value &j, const char *key, T &v) @{ + auto member = j.FindMember(key); + if (member == j.MemberEnd()) + throw std::exception@{@}; + json_get_inner(member->value, v); +@} + +namespace mrpc @{ +@for s in &rpc.structs { +MRPCJWriter& @(s.name)::operator >>(MRPCJWriter &__w) const @{ + __w.StartObject(); +@for f in &s.fields { __w.Key("@f.name"); + @json_write(&f) +} __w.EndObject(); + return __w; +@} +@(s.name)& @(s.name)::operator <<(const rapidjson::Value &__j) @{ json_get_inner<@(s.name)>(__j, *this); return *this; @} +}