From cc8ac5e33f714a3a31a815e302e1018fa0913a7d Mon Sep 17 00:00:00 2001 From: helintong Date: Mon, 11 Nov 2024 17:06:02 +0800 Subject: [PATCH 1/6] feat: implement tool to convert proto to struct pb --- tool/CMakeLists.txt | 14 +++ tool/README.md | 167 ++++++++++++++++++++++++++++ tool/proto_to_struct.cpp | 119 ++++++++++++++++++++ tool/struct_code_generator.hpp | 197 +++++++++++++++++++++++++++++++++ tool/struct_token.hpp | 116 +++++++++++++++++++ 5 files changed, 613 insertions(+) create mode 100644 tool/CMakeLists.txt create mode 100644 tool/README.md create mode 100644 tool/proto_to_struct.cpp create mode 100644 tool/struct_code_generator.hpp create mode 100644 tool/struct_token.hpp diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt new file mode 100644 index 00000000..f8eec172 --- /dev/null +++ b/tool/CMakeLists.txt @@ -0,0 +1,14 @@ +project(proto_to_struct) + +cmake_minimum_required(VERSION 3.10) + +set(CMAKE_CXX_STANDARD 20) + +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(SOURCE_FILE proto_to_struct.cpp) + +add_executable(proto_to_struct ${SOURCE_FILE}) +target_link_libraries(proto_to_struct protobuf::libprotobuf protobuf::libprotoc pthread) diff --git a/tool/README.md b/tool/README.md new file mode 100644 index 00000000..7a840c9b --- /dev/null +++ b/tool/README.md @@ -0,0 +1,167 @@ +# Instructions for using the .proto file to struc_pack header tool + +## compile + +libprotobuf and libprotoc version is 3.21.0. + +```shell +mkdir build +cd build +cmake .. && make +``` + +## usage + +Usage: + +```shell +protoc --plugin=protoc-gen-example=./proto_to_struct data.proto --example_out=protos +``` + +data.proto is the original file that is intended to be the structure pack file. + +`--example_out=` is followed by the path to the generated file. + +data.proto: + +```proto +syntax = "proto3"; + +package mygame; + +option optimize_for = SPEED; +option cc_enable_arenas = true; + +message Vec3 { + float x = 1; + float y = 2; + float z = 3; +} + +message Weapon { + string name = 1; + int32 damage = 2; +} + +message Monster { + Vec3 pos = 1; + int32 mana = 2; + int32 hp = 3; + string name = 4; + bytes inventory = 5; + enum Color { + Red = 0; + Green = 1; + Blue = 2; + } + Color color = 6; + repeated Weapon weapons = 7; + Weapon equipped = 8; + repeated Vec3 path = 9; +} + +message Monsters { + repeated Monster monsters = 1; +} + +message person { + int32 id = 1; + string name = 2; + int32 age = 3; + double salary = 4; +} + +message persons { + repeated person person_list = 1; +} + +message bench_int32 { + int32 a = 1; + int32 b = 2; + int32 c = 3; + int32 d = 4; +} +``` + +generate struct pack file: + +```cpp +#pragma once +#include + +#define PUBLIC(T) : public iguana::base_impl + +enum class Color { + Red = 0, + Green = 1, + Blue = 2, +}; + +struct Vec3 PUBLIC(Vec3) { + Vec3() = default; + Vec3(float a, float b, float c) : x(a), y(b), z(c) {} + float x; + float y; + float z; +}; +YLT_REFL(Vec3, x, y, z); + +struct Weapon PUBLIC(Weapon) { + Weapon() = default; + Weapon(std::string a, int32 b) : name(std::move(a)), damage(b) {} + std::string name; + int32 damage; +}; +YLT_REFL(Weapon, name, damage); + +struct Monster PUBLIC(Monster) { + Monster() = default; + Monster(Vec3 a, int32 b, int32 c, std::string d, std::string e, enum Color f, std::vector g, Weapon h, std::vector i) : pos(a), mana(b), hp(c), name(std::move(d)), inventory(std::move(e)), weapons(std::move(g)), equipped(h), path(std::move(i)) {} + Vec3 pos; + int32 mana; + int32 hp; + std::string name; + std::string inventory; + enum Color color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); + +struct Monsters PUBLIC(Monsters) { + Monsters() = default; + Monsters(std::vector a) : monsters(std::move(a)) {} + std::vector monsters; +}; +YLT_REFL(Monsters, monsters); + +struct person PUBLIC(person) { + person() = default; + person(int32 a, std::string b, int32 c, double d) : id(a), name(std::move(b)), age(c), salary(d) {} + int32 id; + std::string name; + int32 age; + double salary; +}; +YLT_REFL(person, id, name, age, salary); + +struct persons PUBLIC(persons) { + persons() = default; + persons(std::vector a) : person_list(std::move(a)) {} + std::vector person_list; +}; +YLT_REFL(persons, person_list); + +struct bench_int32 PUBLIC(bench_int32) { + bench_int32() = default; + bench_int32(int32 a, int32 b, int32 c, int32 d) : a(a), b(b), c(c), d(d) {} + int32 a; + int32 b; + int32 c; + int32 d; +}; +YLT_REFL(bench_int32, a, b, c, d); + + +``` \ No newline at end of file diff --git a/tool/proto_to_struct.cpp b/tool/proto_to_struct.cpp new file mode 100644 index 00000000..44eeea4b --- /dev/null +++ b/tool/proto_to_struct.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "struct_code_generator.hpp" +#include "struct_token.hpp" + +bool write_to_output(google::protobuf::io::ZeroCopyOutputStream* output, + const void* data, int size) { + const uint8_t* in = reinterpret_cast(data); + int in_size = size; + + void* out; + int out_size; + + while (true) { + if (!output->Next(&out, &out_size)) { + return false; + } + + if (in_size <= out_size) { + memcpy(out, in, in_size); + output->BackUp(out_size - in_size); + return true; + } + + memcpy(out, in, out_size); + in += out_size; + in_size -= out_size; + } +} + +class struct_code_generator : public google::protobuf::compiler::CodeGenerator { + public: + virtual ~struct_code_generator() {} + + virtual bool Generate(const google::protobuf::FileDescriptor* file, + const std::string& parameter, + google::protobuf::compiler::GeneratorContext* context, + std::string* error) const override { + std::string filename = file->name() + ".h"; + auto output = context->Open(filename); + // Use ZeroCopyOutputStream + google::protobuf::io::ZeroCopyOutputStream* zero_copy_output = output; + + std::vector proto_module_info; + std::vector proto_enum_info; + for (int i = 0; i < file->message_type_count(); ++i) { + // struct name + const google::protobuf::Descriptor* descriptor = file->message_type(i); + + struct_enum enum_token; + enum_token.clear(); + enum_token.get_enum_fields(descriptor); + proto_enum_info.emplace_back(enum_token); + + struct_tokenizer tokenizer; + tokenizer.clear(); + tokenizer.tokenizer(descriptor); + proto_module_info.emplace_back(tokenizer); + } + + std::string struct_header = code_generate_header(); + write_to_output(zero_copy_output, (const void*)struct_header.c_str(), + struct_header.size()); + + // codegen struct enum + for (auto enum_inst : proto_enum_info) { + std::string enum_str = ""; + enum_str = code_generate_enum(enum_inst); + write_to_output(zero_copy_output, (const void*)enum_str.c_str(), + enum_str.size()); + } + + // codegen struct + std::vector struct_module_contents; + + for (auto single_struct : proto_module_info) { + std::string struct_default_str = ""; + std::string struct_constructor_str = ""; + std::string struct_body_str = ""; + std::string struct_macro_str = ""; + + struct_default_str = + code_generate_struct_default(single_struct.get_struct_name()); + struct_constructor_str = code_generate_struct_constructor( + single_struct.get_struct_name(), single_struct.get_tokens()); + struct_body_str = code_generate_body(single_struct.get_tokens()); + struct_macro_str = code_generate_ylt_macro( + single_struct.get_struct_name(), single_struct.get_tokens()); + + write_to_output(zero_copy_output, (const void*)struct_default_str.c_str(), + struct_default_str.size()); + write_to_output(zero_copy_output, + (const void*)struct_constructor_str.c_str(), + struct_constructor_str.size()); + write_to_output(zero_copy_output, (const void*)struct_body_str.c_str(), + struct_body_str.size()); + write_to_output(zero_copy_output, (const void*)struct_macro_str.c_str(), + struct_macro_str.size()); + } + + delete zero_copy_output; + return true; + } +}; + +int main(int argc, char* argv[]) { + google::protobuf::compiler::PluginMain(argc, argv, + new struct_code_generator()); + return 0; +} \ No newline at end of file diff --git a/tool/struct_code_generator.hpp b/tool/struct_code_generator.hpp new file mode 100644 index 00000000..4dfb04ff --- /dev/null +++ b/tool/struct_code_generator.hpp @@ -0,0 +1,197 @@ +#pragma once +#include + +#include "struct_token.hpp" + +char parameter_value[27] = "abcdefghijklmnopqrstuvwxyz"; + +std::string code_generate_header() { + std::string result = + "#pragma once\n#include \n\n#define PUBLIC(T) : " + "public iguana::base_impl\n\n"; + return result; +} + +std::string code_generate_struct_default(const std::string &struct_name) { + std::string result = "struct "; + result.append(struct_name); + result.append(" PUBLIC("); + result.append(struct_name); + result.append(") {\n\t"); + + result.append(struct_name); + result.append("() = default;\n\t"); + + return result; +} + +std::string code_generate_struct_constructor( + const std::string &struct_name, const std::vector lists) { + std::string result = struct_name + "("; + int i = 0; + int list_size = lists.size() - 1; + for (auto it = lists.begin(); it != lists.end(); it++) { + if (it->type == struct_token_type::pod) { + if (it->lable == lable_type::lable_repeated) { + result.append("std::vector<"); + result.append(it->type_name); + result.append("> "); + result += parameter_value[i]; + } + else { + result.append(it->type_name); + result.append(" "); + result += parameter_value[i]; + } + if (i != list_size) + result.append(", "); + i++; + } + else if (it->type == struct_token_type::proto_string) { + if (it->lable == lable_type::lable_repeated) { + result.append("std::vector "); + result += parameter_value[i]; + } + else { + result.append("std::"); + result.append(it->type_name); + result.append(" "); + result += parameter_value[i]; + } + if (i != list_size) + result.append(", "); + i++; + } + else { + if (it->lable == lable_type::lable_repeated) { + result.append("std::vector<"); + result.append(it->type_name); + result.append("> "); + result += parameter_value[i]; + } + else { + result.append(it->type_name); + result.append(" "); + result += parameter_value[i]; + } + if (i != list_size) + result.append(", "); + i++; + } + } + result.append(") : "); + + int j = 0; + for (auto ll : lists) { + if (ll.type == struct_token_type::pod || + ll.type == struct_token_type::message) { + result.append(ll.var_name); + result.append("("); + if (ll.lable == lable_type::lable_repeated) { + result.append("std::move("); + result += parameter_value[j]; + result.append(")"); + if (j != list_size) + result.append("), "); + else + result.append(") {}"); + } + else { + result += parameter_value[j]; + if (j != list_size) + result.append("), "); + else + result.append(") {}"); + } + } + else if (ll.type == struct_token_type::proto_string) { + result.append(ll.var_name); + result.append("("); + result.append("std::move("); + result += parameter_value[j]; + result.append(")"); + if (j != list_size) + result.append("), "); + else + result.append(") {}"); + } + j++; + } + result.append("\n"); + return result; +} + +std::string code_generate_body(const std::vector &lists) { + std::string result; + for (auto ll : lists) { + result.append("\t"); + if (ll.lable == lable_type::lable_repeated) { + if (ll.type == struct_token_type::proto_string) { + result.append("std::vector "); + result.append(ll.var_name); + result.append(";\n"); + } + else { + result.append("std::vector<"); + result.append(ll.type_name); + result.append("> "); + result.append(ll.var_name); + result.append(";\n"); + } + } + else { + if (ll.type == struct_token_type::proto_string) + result.append("std::"); + result.append(ll.type_name); + result.append(" "); + result.append(ll.var_name); + result.append(";\n"); + } + } + result.append("};\n"); + + return result; +} + +std::string code_generate_ylt_macro(const std::string &struct_name, + const std::vector &lists) { + std::string result = "YLT_REFL("; + result.append(struct_name); + result.append(", "); + int i = 0; + int list_size = lists.size() - 1; + for (auto ll : lists) { + if (i != list_size) { + result.append(ll.var_name); + result.append(", "); + } + else { + result.append(ll.var_name); + } + i++; + } + result.append(");\n\n"); + return result; +} + +std::string code_generate_enum(const struct_enum &enum_inst) { + std::string result = "enum class "; + if (enum_inst.enum_name_.empty()) + return ""; + result.append(enum_inst.enum_name_); + result.append(" {\n"); + if (enum_inst.fields_.size() == 0) { + result.append("}\n"); + } + else { + for (auto i : enum_inst.fields_) { + result.append("\t"); + result.append(i.first); + result.append(" = "); + result.append(std::to_string(i.second)); + result.append(",\n"); + } + result.append("};\n\n"); + } + return result; +} \ No newline at end of file diff --git a/tool/struct_token.hpp b/tool/struct_token.hpp new file mode 100644 index 00000000..a9d491a6 --- /dev/null +++ b/tool/struct_token.hpp @@ -0,0 +1,116 @@ +#pragma once +#include + +#include +#include + +enum class struct_token_type { pod, proto_string, message, null_type }; + +enum class lable_type { + lable_optional, + lable_required, + lable_repeated, + lable_null +}; + +struct struct_token { + struct_token() { + this->var_name = ""; + this->type_name = ""; + this->type = struct_token_type::null_type; + this->lable = lable_type::lable_null; + } + + void clear(); + std::string var_name; + std::string type_name; + struct_token_type type; + lable_type lable; +}; + +class struct_tokenizer { + public: + struct_tokenizer() { clear(); } + + void tokenizer(const google::protobuf::Descriptor* descriptor) { + struct_name_ = descriptor->name(); + for (int j = 0; j < descriptor->field_count(); ++j) { + struct_token token = {}; + const google::protobuf::FieldDescriptor* field = descriptor->field(j); + token.var_name = field->name(); + if (field->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE) { + token.type_name = field->message_type()->name(); + token.type = struct_token_type::message; + } + else if (field->type() == + google::protobuf::FieldDescriptor::TYPE_STRING) { + token.type_name = field->type_name(); + token.type = struct_token_type::proto_string; + // std::cout << "string var anme is: " << token.var_name << std::endl; + } + else { + token.type_name = field->type_name(); + if (token.type_name == "bytes") { + token.type = struct_token_type::proto_string; + token.type_name = "string"; + } + else if (token.type_name == "enum") { + const google::protobuf::EnumDescriptor* enum_desc = + field->enum_type(); + token.type_name = "enum " + enum_desc->name(); + } + else { + token.type = struct_token_type::pod; + } + } + + if (field->label() == + google::protobuf::FieldDescriptor::Label::LABEL_REPEATED) + token.lable = lable_type::lable_repeated; + else if (field->label() == + google::protobuf::FieldDescriptor::Label::LABEL_OPTIONAL) + token.lable = lable_type::lable_optional; + else if (field->label() == + google::protobuf::FieldDescriptor::Label::LABEL_REQUIRED) + token.lable = lable_type::lable_required; + + token_lists_.emplace_back(token); + } + } + + void clear() { + token_lists_.clear(); + struct_name_ = ""; + } + + std::vector& get_tokens() { return token_lists_; } + std::string& get_struct_name() { return struct_name_; } + + private: + std::vector token_lists_; + std::string struct_name_; // struct name +}; + +struct struct_enum { + struct_enum() { clear(); } + + void clear() { + this->enum_name_ = ""; + this->fields_.clear(); + } + + void get_enum_fields(const google::protobuf::Descriptor* descriptor) { + for (int e = 0; e < descriptor->enum_type_count(); ++e) { + const google::protobuf::EnumDescriptor* enum_desc = + descriptor->enum_type(e); + enum_name_ = enum_desc->name(); + for (int v = 0; v < enum_desc->value_count(); ++v) { + const google::protobuf::EnumValueDescriptor* value_desc = + enum_desc->value(v); + fields_.push_back({value_desc->name(), value_desc->number()}); + } + } + } + std::string enum_name_; + std::vector> fields_; +}; \ No newline at end of file From 897fe8957073fb221deb2aa5f9de46dcfb89842b Mon Sep 17 00:00:00 2001 From: helintong Date: Thu, 14 Nov 2024 19:05:23 +0800 Subject: [PATCH 2/6] fix: add optional and reflection parameter --- tool/proto_to_struct.cpp | 27 +++++++++++-- tool/struct_code_generator.hpp | 70 +++++++++++++++++++++++++++++----- tool/struct_token.hpp | 13 ++++++- 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/tool/proto_to_struct.cpp b/tool/proto_to_struct.cpp index 44eeea4b..0b96c910 100644 --- a/tool/proto_to_struct.cpp +++ b/tool/proto_to_struct.cpp @@ -46,7 +46,24 @@ class struct_code_generator : public google::protobuf::compiler::CodeGenerator { google::protobuf::compiler::GeneratorContext* context, std::string* error) const override { std::string filename = file->name() + ".h"; + auto output = context->Open(filename); + // std::cout << parameter << std::endl; + bool enable_optional = true; + bool enable_reflection = false; + if (parameter.find("enable_reflection") != std::string::npos) { + enable_reflection = true; + } + else if (parameter.find("disable_reflection") != std::string::npos) { + enable_reflection = false; + } + + if (parameter.find("del_optional") != std::string::npos) { + enable_optional = false; + } + else if (parameter.find("add_optional") != std::string::npos) { + enable_optional = true; + } // Use ZeroCopyOutputStream google::protobuf::io::ZeroCopyOutputStream* zero_copy_output = output; @@ -88,11 +105,13 @@ class struct_code_generator : public google::protobuf::compiler::CodeGenerator { std::string struct_body_str = ""; std::string struct_macro_str = ""; - struct_default_str = - code_generate_struct_default(single_struct.get_struct_name()); + struct_default_str = code_generate_struct_default( + single_struct.get_struct_name(), enable_reflection); struct_constructor_str = code_generate_struct_constructor( - single_struct.get_struct_name(), single_struct.get_tokens()); - struct_body_str = code_generate_body(single_struct.get_tokens()); + single_struct.get_struct_name(), single_struct.get_tokens(), + enable_optional); + struct_body_str = + code_generate_body(single_struct.get_tokens(), enable_optional); struct_macro_str = code_generate_ylt_macro( single_struct.get_struct_name(), single_struct.get_tokens()); diff --git a/tool/struct_code_generator.hpp b/tool/struct_code_generator.hpp index 4dfb04ff..31152397 100644 --- a/tool/struct_code_generator.hpp +++ b/tool/struct_code_generator.hpp @@ -6,18 +6,20 @@ char parameter_value[27] = "abcdefghijklmnopqrstuvwxyz"; std::string code_generate_header() { - std::string result = - "#pragma once\n#include \n\n#define PUBLIC(T) : " - "public iguana::base_impl\n\n"; + std::string result = "#pragma once\n#include \n\n"; return result; } -std::string code_generate_struct_default(const std::string &struct_name) { +std::string code_generate_struct_default(const std::string &struct_name, + bool reflection) { std::string result = "struct "; result.append(struct_name); - result.append(" PUBLIC("); - result.append(struct_name); - result.append(") {\n\t"); + if (reflection) { + result.append(" : public iguana::base_impl<"); + result.append(struct_name); + result.append("> "); + } + result.append("{\n\t"); result.append(struct_name); result.append("() = default;\n\t"); @@ -26,7 +28,8 @@ std::string code_generate_struct_default(const std::string &struct_name) { } std::string code_generate_struct_constructor( - const std::string &struct_name, const std::vector lists) { + const std::string &struct_name, const std::vector lists, + bool add_optiional) { std::string result = struct_name + "("; int i = 0; int list_size = lists.size() - 1; @@ -53,8 +56,15 @@ std::string code_generate_struct_constructor( result += parameter_value[i]; } else { + if (add_optiional) { + result.append("std::optional<"); + } + result.append("std::"); result.append(it->type_name); + if (add_optiional) { + result.append(">"); + } result.append(" "); result += parameter_value[i]; } @@ -62,15 +72,38 @@ std::string code_generate_struct_constructor( result.append(", "); i++; } + else if (it->type == struct_token_type::enum_type) { + // enum no repeated type + result.append(it->type_name); + result.append(" "); + result += parameter_value[i]; + if (i != list_size) + result.append(", "); + i++; + } else { if (it->lable == lable_type::lable_repeated) { result.append("std::vector<"); + + if (add_optiional) { + result.append("std::optional<"); + } + result.append(it->type_name); + if (add_optiional) { + result.append(">"); + } result.append("> "); result += parameter_value[i]; } else { + if (add_optiional) { + result.append("std::optional<"); + } result.append(it->type_name); + if (add_optiional) { + result.append(">"); + } result.append(" "); result += parameter_value[i]; } @@ -84,7 +117,8 @@ std::string code_generate_struct_constructor( int j = 0; for (auto ll : lists) { if (ll.type == struct_token_type::pod || - ll.type == struct_token_type::message) { + ll.type == struct_token_type::message || + ll.type == struct_token_type::enum_type) { result.append(ll.var_name); result.append("("); if (ll.lable == lable_type::lable_repeated) { @@ -121,7 +155,8 @@ std::string code_generate_struct_constructor( return result; } -std::string code_generate_body(const std::vector &lists) { +std::string code_generate_body(const std::vector &lists, + bool add_optional) { std::string result; for (auto ll : lists) { result.append("\t"); @@ -133,16 +168,31 @@ std::string code_generate_body(const std::vector &lists) { } else { result.append("std::vector<"); + if (ll.type == struct_token_type::message && add_optional) { + result.append("std::optional<"); + } result.append(ll.type_name); + if (ll.type == struct_token_type::message && add_optional) { + result.append(">"); + } result.append("> "); result.append(ll.var_name); result.append(";\n"); } } else { + if (ll.type != struct_token_type::pod && + ll.type != struct_token_type::enum_type && add_optional) { + result.append("std::optional<"); + } + if (ll.type == struct_token_type::proto_string) result.append("std::"); result.append(ll.type_name); + if (ll.type != struct_token_type::pod && + ll.type != struct_token_type::enum_type && add_optional) { + result.append(">"); + } result.append(" "); result.append(ll.var_name); result.append(";\n"); diff --git a/tool/struct_token.hpp b/tool/struct_token.hpp index a9d491a6..61bfe4f4 100644 --- a/tool/struct_token.hpp +++ b/tool/struct_token.hpp @@ -4,7 +4,13 @@ #include #include -enum class struct_token_type { pod, proto_string, message, null_type }; +enum class struct_token_type { + pod, + proto_string, + message, + enum_type, + null_type +}; enum class lable_type { lable_optional, @@ -57,10 +63,13 @@ class struct_tokenizer { else if (token.type_name == "enum") { const google::protobuf::EnumDescriptor* enum_desc = field->enum_type(); - token.type_name = "enum " + enum_desc->name(); + token.type_name = enum_desc->name(); + token.type = struct_token_type::enum_type; } else { token.type = struct_token_type::pod; + if (token.type_name.find("int") != std::string::npos) + token.type_name += "_t"; } } From f636c60d0e0b7950ac9e765ae7cdd5ccabf7a40e Mon Sep 17 00:00:00 2001 From: helintong Date: Fri, 15 Nov 2024 14:35:09 +0800 Subject: [PATCH 3/6] fix: refactor parameters 1. del reflection parameter 2. add inherit parameter. 3. only enable_inherit exist generator strurcture function. --- tool/proto_to_struct.cpp | 22 +++++++++++----------- tool/struct_code_generator.hpp | 14 +++++++++----- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/tool/proto_to_struct.cpp b/tool/proto_to_struct.cpp index 0b96c910..8c2baa23 100644 --- a/tool/proto_to_struct.cpp +++ b/tool/proto_to_struct.cpp @@ -50,13 +50,7 @@ class struct_code_generator : public google::protobuf::compiler::CodeGenerator { auto output = context->Open(filename); // std::cout << parameter << std::endl; bool enable_optional = true; - bool enable_reflection = false; - if (parameter.find("enable_reflection") != std::string::npos) { - enable_reflection = true; - } - else if (parameter.find("disable_reflection") != std::string::npos) { - enable_reflection = false; - } + bool enable_inherit = false; if (parameter.find("del_optional") != std::string::npos) { enable_optional = false; @@ -64,6 +58,11 @@ class struct_code_generator : public google::protobuf::compiler::CodeGenerator { else if (parameter.find("add_optional") != std::string::npos) { enable_optional = true; } + + if (parameter.find("enable_inherit") != std::string::npos) { + enable_inherit = true; + } + // Use ZeroCopyOutputStream google::protobuf::io::ZeroCopyOutputStream* zero_copy_output = output; @@ -106,7 +105,7 @@ class struct_code_generator : public google::protobuf::compiler::CodeGenerator { std::string struct_macro_str = ""; struct_default_str = code_generate_struct_default( - single_struct.get_struct_name(), enable_reflection); + single_struct.get_struct_name(), enable_inherit); struct_constructor_str = code_generate_struct_constructor( single_struct.get_struct_name(), single_struct.get_tokens(), enable_optional); @@ -117,9 +116,10 @@ class struct_code_generator : public google::protobuf::compiler::CodeGenerator { write_to_output(zero_copy_output, (const void*)struct_default_str.c_str(), struct_default_str.size()); - write_to_output(zero_copy_output, - (const void*)struct_constructor_str.c_str(), - struct_constructor_str.size()); + if (enable_inherit) + write_to_output(zero_copy_output, + (const void*)struct_constructor_str.c_str(), + struct_constructor_str.size()); write_to_output(zero_copy_output, (const void*)struct_body_str.c_str(), struct_body_str.size()); write_to_output(zero_copy_output, (const void*)struct_macro_str.c_str(), diff --git a/tool/struct_code_generator.hpp b/tool/struct_code_generator.hpp index 31152397..70d44dec 100644 --- a/tool/struct_code_generator.hpp +++ b/tool/struct_code_generator.hpp @@ -11,19 +11,23 @@ std::string code_generate_header() { } std::string code_generate_struct_default(const std::string &struct_name, - bool reflection) { + bool enable_inherit) { std::string result = "struct "; result.append(struct_name); - if (reflection) { + + if (enable_inherit) { result.append(" : public iguana::base_impl<"); result.append(struct_name); result.append("> "); } - result.append("{\n\t"); - result.append(struct_name); - result.append("() = default;\n\t"); + result.append(" {\n"); + if (enable_inherit) { + result.append("\t"); + result.append(struct_name); + result.append("() = default;\n\t"); + } return result; } From 2a2ed338241d48c1f9a8436acbf7ce5da7f06252 Mon Sep 17 00:00:00 2001 From: helintong Date: Mon, 18 Nov 2024 15:08:22 +0800 Subject: [PATCH 4/6] refactor: streamline pb to struct header tool with only two parameters --- tool/README.md | 81 ++++++++++++++++++++++------------------ tool/proto_to_struct.cpp | 9 ++--- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/tool/README.md b/tool/README.md index 7a840c9b..d7341a21 100644 --- a/tool/README.md +++ b/tool/README.md @@ -15,12 +15,12 @@ cmake .. && make Usage: ```shell -protoc --plugin=protoc-gen-example=./proto_to_struct data.proto --example_out=protos +protoc --plugin=protoc-gen-custom=./build/proto_to_struct data.proto --custom_out=:./protos ``` data.proto is the original file that is intended to be the structure pack file. -`--example_out=` is followed by the path to the generated file. +`--custom_out=` is followed by the path to the generated file. data.proto: @@ -89,79 +89,88 @@ generate struct pack file: #pragma once #include -#define PUBLIC(T) : public iguana::base_impl - enum class Color { Red = 0, Green = 1, Blue = 2, }; -struct Vec3 PUBLIC(Vec3) { - Vec3() = default; - Vec3(float a, float b, float c) : x(a), y(b), z(c) {} +struct Vec3 { float x; float y; float z; }; YLT_REFL(Vec3, x, y, z); -struct Weapon PUBLIC(Weapon) { - Weapon() = default; - Weapon(std::string a, int32 b) : name(std::move(a)), damage(b) {} +struct Weapon { std::string name; - int32 damage; + int32_t damage; }; YLT_REFL(Weapon, name, damage); -struct Monster PUBLIC(Monster) { - Monster() = default; - Monster(Vec3 a, int32 b, int32 c, std::string d, std::string e, enum Color f, std::vector g, Weapon h, std::vector i) : pos(a), mana(b), hp(c), name(std::move(d)), inventory(std::move(e)), weapons(std::move(g)), equipped(h), path(std::move(i)) {} +struct Monster { Vec3 pos; - int32 mana; - int32 hp; + int32_t mana; + int32_t hp; std::string name; std::string inventory; - enum Color color; + Color color; std::vector weapons; Weapon equipped; std::vector path; }; YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); -struct Monsters PUBLIC(Monsters) { - Monsters() = default; - Monsters(std::vector a) : monsters(std::move(a)) {} +struct Monsters { std::vector monsters; }; YLT_REFL(Monsters, monsters); -struct person PUBLIC(person) { - person() = default; - person(int32 a, std::string b, int32 c, double d) : id(a), name(std::move(b)), age(c), salary(d) {} - int32 id; +struct person { + int32_t id; std::string name; - int32 age; + int32_t age; double salary; }; YLT_REFL(person, id, name, age, salary); -struct persons PUBLIC(persons) { - persons() = default; - persons(std::vector a) : person_list(std::move(a)) {} +struct persons { std::vector person_list; }; YLT_REFL(persons, person_list); -struct bench_int32 PUBLIC(bench_int32) { - bench_int32() = default; - bench_int32(int32 a, int32 b, int32 c, int32 d) : a(a), b(b), c(c), d(d) {} - int32 a; - int32 b; - int32 c; - int32 d; +struct bench_int32 { + int32_t a; + int32_t b; + int32_t c; + int32_t d; }; YLT_REFL(bench_int32, a, b, c, d); -``` \ No newline at end of file +``` + +There are two parameters: + +## add_optional + +Generate C++ files in optional struct pack format. + +```shell +protoc --plugin=protoc-gen-custom=./build/proto_to_struct data.proto --custom_out=add_optional:./protos +``` + +## enable_inherit + +Generate C++ files in non std::optional format and the file conforms to the `struct pb` standard. + +```shell +protoc --plugin=protoc-gen-custom=./build/proto_to_struct data.proto --custom_out=enable_inherit:./protos + +``` + +## add_optional and enable_inherit + +```shell +protoc --plugin=protoc-gen-custom=./build/proto_to_struct data.proto --custom_out=add_optional+enable_inherit:./protos +``` diff --git a/tool/proto_to_struct.cpp b/tool/proto_to_struct.cpp index 8c2baa23..d4028d2c 100644 --- a/tool/proto_to_struct.cpp +++ b/tool/proto_to_struct.cpp @@ -48,14 +48,11 @@ class struct_code_generator : public google::protobuf::compiler::CodeGenerator { std::string filename = file->name() + ".h"; auto output = context->Open(filename); - // std::cout << parameter << std::endl; - bool enable_optional = true; + + bool enable_optional = false; bool enable_inherit = false; - if (parameter.find("del_optional") != std::string::npos) { - enable_optional = false; - } - else if (parameter.find("add_optional") != std::string::npos) { + if (parameter.find("add_optional") != std::string::npos) { enable_optional = true; } From 5db114d9e2fc7971ea20b245e45d94c79cb5264c Mon Sep 17 00:00:00 2001 From: helintong Date: Mon, 18 Nov 2024 19:31:19 +0800 Subject: [PATCH 5/6] feat: add more example --- tool/README.md | 226 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/tool/README.md b/tool/README.md index d7341a21..405be7ab 100644 --- a/tool/README.md +++ b/tool/README.md @@ -160,17 +160,243 @@ Generate C++ files in optional struct pack format. protoc --plugin=protoc-gen-custom=./build/proto_to_struct data.proto --custom_out=add_optional:./protos ``` +In the generated file, `std::string` will be converted to `std::optional`, and the 'class' type(For example `class Foo`) will be converted to `std::optional`. + +```cpp +#pragma once +#include + +enum class Color { + Red = 0, + Green = 1, + Blue = 2, +}; + +struct Vec3 { + float x; + float y; + float z; +}; +YLT_REFL(Vec3, x, y, z); + +struct Weapon { + std::optional name; + int32_t damage; +}; +YLT_REFL(Weapon, name, damage); + +struct Monster { + std::optional pos; + int32_t mana; + int32_t hp; + std::optional name; + std::optional inventory; + Color color; + std::vector> weapons; + std::optional equipped; + std::vector> path; +}; +YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); + +struct Monsters { + std::vector> monsters; +}; +YLT_REFL(Monsters, monsters); + +struct person { + int32_t id; + std::optional name; + int32_t age; + double salary; +}; +YLT_REFL(person, id, name, age, salary); + +struct persons { + std::vector> person_list; +}; +YLT_REFL(persons, person_list); + +struct bench_int32 { + int32_t a; + int32_t b; + int32_t c; + int32_t d; +}; +YLT_REFL(bench_int32, a, b, c, d); + + +``` + ## enable_inherit Generate C++ files in non std::optional format and the file conforms to the `struct pb` standard. ```shell protoc --plugin=protoc-gen-custom=./build/proto_to_struct data.proto --custom_out=enable_inherit:./protos +``` + +```cpp +#pragma once +#include + +enum class Color { + Red = 0, + Green = 1, + Blue = 2, +}; + +struct Vec3 : public iguana::base_impl { + Vec3() = default; + Vec3(float a, float b, float c) : x(a), y(b), z(c) {} + float x; + float y; + float z; +}; +YLT_REFL(Vec3, x, y, z); + +struct Weapon : public iguana::base_impl { + Weapon() = default; + Weapon(std::string a, int32_t b) : name(std::move(a)), damage(b) {} + std::string name; + int32_t damage; +}; +YLT_REFL(Weapon, name, damage); + +struct Monster : public iguana::base_impl { + Monster() = default; + Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, Color f, std::vector g, Weapon h, std::vector i) : pos(a), mana(b), hp(c), name(std::move(d)), inventory(std::move(e)), color(f), weapons(std::move(g)), equipped(h), path(std::move(i)) {} + Vec3 pos; + int32_t mana; + int32_t hp; + std::string name; + std::string inventory; + Color color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); + +struct Monsters : public iguana::base_impl { + Monsters() = default; + Monsters(std::vector a) : monsters(std::move(a)) {} + std::vector monsters; +}; +YLT_REFL(Monsters, monsters); + +struct person : public iguana::base_impl { + person() = default; + person(int32_t a, std::string b, int32_t c, double d) : id(a), name(std::move(b)), age(c), salary(d) {} + int32_t id; + std::string name; + int32_t age; + double salary; +}; +YLT_REFL(person, id, name, age, salary); + +struct persons : public iguana::base_impl { + persons() = default; + persons(std::vector a) : person_list(std::move(a)) {} + std::vector person_list; +}; +YLT_REFL(persons, person_list); + +struct bench_int32 : public iguana::base_impl { + bench_int32() = default; + bench_int32(int32_t a, int32_t b, int32_t c, int32_t d) : a(a), b(b), c(c), d(d) {} + int32_t a; + int32_t b; + int32_t c; + int32_t d; +}; +YLT_REFL(bench_int32, a, b, c, d); + ``` ## add_optional and enable_inherit +The presence of these two parameters indicates that these two functions take effect on the generated file at the same time. + ```shell protoc --plugin=protoc-gen-custom=./build/proto_to_struct data.proto --custom_out=add_optional+enable_inherit:./protos ``` + +```cpp +#pragma once +#include + +enum class Color { + Red = 0, + Green = 1, + Blue = 2, +}; + +struct Vec3 : public iguana::base_impl { + Vec3() = default; + Vec3(float a, float b, float c) : x(a), y(b), z(c) {} + float x; + float y; + float z; +}; +YLT_REFL(Vec3, x, y, z); + +struct Weapon : public iguana::base_impl { + Weapon() = default; + Weapon(std::optional a, int32_t b) : name(std::move(a)), damage(b) {} + std::optional name; + int32_t damage; +}; +YLT_REFL(Weapon, name, damage); + +struct Monster : public iguana::base_impl { + Monster() = default; + Monster(std::optional a, int32_t b, int32_t c, std::optional d, std::optional e, Color f, std::vector> g, std::optional h, std::vector> i) : pos(a), mana(b), hp(c), name(std::move(d)), inventory(std::move(e)), color(f), weapons(std::move(g)), equipped(h), path(std::move(i)) {} + std::optional pos; + int32_t mana; + int32_t hp; + std::optional name; + std::optional inventory; + Color color; + std::vector> weapons; + std::optional equipped; + std::vector> path; +}; +YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); + +struct Monsters : public iguana::base_impl { + Monsters() = default; + Monsters(std::vector> a) : monsters(std::move(a)) {} + std::vector> monsters; +}; +YLT_REFL(Monsters, monsters); + +struct person : public iguana::base_impl { + person() = default; + person(int32_t a, std::optional b, int32_t c, double d) : id(a), name(std::move(b)), age(c), salary(d) {} + int32_t id; + std::optional name; + int32_t age; + double salary; +}; +YLT_REFL(person, id, name, age, salary); + +struct persons : public iguana::base_impl { + persons() = default; + persons(std::vector> a) : person_list(std::move(a)) {} + std::vector> person_list; +}; +YLT_REFL(persons, person_list); + +struct bench_int32 : public iguana::base_impl { + bench_int32() = default; + bench_int32(int32_t a, int32_t b, int32_t c, int32_t d) : a(a), b(b), c(c), d(d) {} + int32_t a; + int32_t b; + int32_t c; + int32_t d; +}; +YLT_REFL(bench_int32, a, b, c, d); + + +``` \ No newline at end of file From d07ad5a6dbf916ef38179d0e98126036ebf8de17 Mon Sep 17 00:00:00 2001 From: helintong Date: Wed, 20 Nov 2024 19:34:23 +0800 Subject: [PATCH 6/6] fix: std::optinal before vector --- tool/README.md | 30 +++++++++++----------- tool/struct_code_generator.hpp | 47 ++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/tool/README.md b/tool/README.md index 405be7ab..b14f72fe 100644 --- a/tool/README.md +++ b/tool/README.md @@ -115,14 +115,14 @@ struct Monster { std::string name; std::string inventory; Color color; - std::vector weapons; + std::vectorweapons; Weapon equipped; - std::vector path; + std::vectorpath; }; YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); struct Monsters { - std::vector monsters; + std::vectormonsters; }; YLT_REFL(Monsters, monsters); @@ -135,7 +135,7 @@ struct person { YLT_REFL(person, id, name, age, salary); struct persons { - std::vector person_list; + std::vectorperson_list; }; YLT_REFL(persons, person_list); @@ -192,14 +192,14 @@ struct Monster { std::optional name; std::optional inventory; Color color; - std::vector> weapons; + std::optional> weapons; std::optional equipped; - std::vector> path; + std::optional> path; }; YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); struct Monsters { - std::vector> monsters; + std::optional> monsters; }; YLT_REFL(Monsters, monsters); @@ -212,7 +212,7 @@ struct person { YLT_REFL(person, id, name, age, salary); struct persons { - std::vector> person_list; + std::optional> person_list; }; YLT_REFL(persons, person_list); @@ -351,23 +351,23 @@ YLT_REFL(Weapon, name, damage); struct Monster : public iguana::base_impl { Monster() = default; - Monster(std::optional a, int32_t b, int32_t c, std::optional d, std::optional e, Color f, std::vector> g, std::optional h, std::vector> i) : pos(a), mana(b), hp(c), name(std::move(d)), inventory(std::move(e)), color(f), weapons(std::move(g)), equipped(h), path(std::move(i)) {} + Monster(std::optional a, int32_t b, int32_t c, std::optional d, std::optional e, Color f, std::optional> g, std::optional h, std::optional> i) : pos(a), mana(b), hp(c), name(std::move(d)), inventory(std::move(e)), color(f), weapons(std::move(g)), equipped(h), path(std::move(i)) {} std::optional pos; int32_t mana; int32_t hp; std::optional name; std::optional inventory; Color color; - std::vector> weapons; + std::optional> weapons; std::optional equipped; - std::vector> path; + std::optional> path; }; YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); struct Monsters : public iguana::base_impl { Monsters() = default; - Monsters(std::vector> a) : monsters(std::move(a)) {} - std::vector> monsters; + Monsters(std::optional> a) : monsters(std::move(a)) {} + std::optional> monsters; }; YLT_REFL(Monsters, monsters); @@ -383,8 +383,8 @@ YLT_REFL(person, id, name, age, salary); struct persons : public iguana::base_impl { persons() = default; - persons(std::vector> a) : person_list(std::move(a)) {} - std::vector> person_list; + persons(std::optional> a) : person_list(std::move(a)) {} + std::optional> person_list; }; YLT_REFL(persons, person_list); diff --git a/tool/struct_code_generator.hpp b/tool/struct_code_generator.hpp index 70d44dec..7648850b 100644 --- a/tool/struct_code_generator.hpp +++ b/tool/struct_code_generator.hpp @@ -33,7 +33,7 @@ std::string code_generate_struct_default(const std::string &struct_name, std::string code_generate_struct_constructor( const std::string &struct_name, const std::vector lists, - bool add_optiional) { + bool add_optional) { std::string result = struct_name + "("; int i = 0; int list_size = lists.size() - 1; @@ -56,17 +56,23 @@ std::string code_generate_struct_constructor( } else if (it->type == struct_token_type::proto_string) { if (it->lable == lable_type::lable_repeated) { - result.append("std::vector "); + if (add_optional) { + result.append("std::optional<"); + } + result.append("std::vector"); + if (add_optional) { + result.append("> "); + } result += parameter_value[i]; } else { - if (add_optiional) { + if (add_optional) { result.append("std::optional<"); } result.append("std::"); result.append(it->type_name); - if (add_optiional) { + if (add_optional) { result.append(">"); } result.append(" "); @@ -87,25 +93,27 @@ std::string code_generate_struct_constructor( } else { if (it->lable == lable_type::lable_repeated) { - result.append("std::vector<"); - - if (add_optiional) { + if (add_optional) { result.append("std::optional<"); } + result.append("std::vector<"); + result.append(it->type_name); - if (add_optiional) { - result.append(">"); + result.append(">"); + + if (add_optional) { + result.append("> "); } - result.append("> "); + result += parameter_value[i]; } else { - if (add_optiional) { + if (add_optional) { result.append("std::optional<"); } result.append(it->type_name); - if (add_optiional) { + if (add_optional) { result.append(">"); } result.append(" "); @@ -166,20 +174,27 @@ std::string code_generate_body(const std::vector &lists, result.append("\t"); if (ll.lable == lable_type::lable_repeated) { if (ll.type == struct_token_type::proto_string) { - result.append("std::vector "); + if (add_optional) { + result.append("std::optional<"); + } + + result.append("std::vector"); + if (add_optional) { + result.append("> "); + } result.append(ll.var_name); result.append(";\n"); } else { - result.append("std::vector<"); if (ll.type == struct_token_type::message && add_optional) { result.append("std::optional<"); } + result.append("std::vector<"); result.append(ll.type_name); + result.append(">"); if (ll.type == struct_token_type::message && add_optional) { - result.append(">"); + result.append("> "); } - result.append("> "); result.append(ll.var_name); result.append(";\n"); }