-
Notifications
You must be signed in to change notification settings - Fork 233
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement tool to convert proto to struct pb
- Loading branch information
1 parent
ae5a951
commit cc8ac5e
Showing
5 changed files
with
613 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <ylt/struct_pb.hpp> | ||
|
||
#define PUBLIC(T) : public iguana::base_impl<T> | ||
|
||
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<Weapon> g, Weapon h, std::vector<Vec3> 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<Weapon> weapons; | ||
Weapon equipped; | ||
std::vector<Vec3> path; | ||
}; | ||
YLT_REFL(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); | ||
|
||
struct Monsters PUBLIC(Monsters) { | ||
Monsters() = default; | ||
Monsters(std::vector<Monster> a) : monsters(std::move(a)) {} | ||
std::vector<Monster> 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<person> a) : person_list(std::move(a)) {} | ||
std::vector<person> 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); | ||
|
||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
#include <google/protobuf/compiler/code_generator.h> | ||
#include <google/protobuf/compiler/plugin.h> | ||
#include <google/protobuf/descriptor.h> | ||
#include <google/protobuf/io/zero_copy_stream.h> | ||
#include <google/protobuf/io/zero_copy_stream_impl.h> | ||
|
||
#include <cinttypes> | ||
#include <fstream> | ||
#include <iostream> | ||
#include <memory> | ||
|
||
#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<const uint8_t*>(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<struct_tokenizer> proto_module_info; | ||
std::vector<struct_enum> 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<std::string> 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; | ||
} |
Oops, something went wrong.