Open
Description
Angle.hpp
namespace sf
{
class Angle
{
public:
constexpr Angle() = default;
constexpr Angle(float radians);
[[nodiscard]] constexpr float asDegrees() const;
[[nodiscard]] constexpr float asRadians() const;
[[nodiscard]] constexpr Angle wrapSigned() const;
// And other really usefull methods
private:
float m_radians{};
};
}
Vector2.hpp
namespace sf
{
template <typename T>
class Vector2
{
public:
constexpr Vector2() = default;
constexpr Vector2(T x, T y);
[[nodiscard]] constexpr T dot(Vector2 rhs) const;
[[nodiscard]] constexpr T cross(Vector2 rhs) const;
// And other really usefull methods
private:
T x{};
T y{};
};
using Vector2f = Vector2<float>;
// ...
}
Angle.proto
syntax = "proto3";
package api.sf;
message Angle {
float radians = 1;
}
Vector2f.proto
syntax = "proto3";
package api.sf;
message Vector2f {
float x = 1;
float y = 2;
}
Problem
I really want to use native classes from C++, for this I need to manually transfer each time from classes generated by Protobuf to native ones
Solution
Python plugin
import sys
from google.protobuf.compiler import plugin_pb2 as plugin
from jinja2 import Template
converter_template = Template(
"""
{% for message in proto_file.message_type %}
inline {{cpp_namespace}}::{{message.name}} convert({{api_namespace}}::{{message.name}}&& dto)
{
return { {% for field in message.field %}std::move(*dto.mutable_{{field.name}}()){{ ", " if not loop.last else "" }}{% endfor %} };
}
inline {{api_namespace}}::{{message.name}} convert({{cpp_namespace}}::{{message.name}}&& object)
{
return { {% for field in message.field %}std::move(object.{{field.name}}){{ ", " if not loop.last else "" }}{% endfor %} };
}
{% endfor %}
"""
)
def generate_converter(proto_file, response):
output_code = ""
for proto_file in proto_file:
api_namespace = proto_file.package.replace(".", "::")
cpp_namespace = api_namespace[5:]
output_code += converter_template.render(proto_file=proto_file, api_namespace=api_namespace, cpp_namespace=cpp_namespace)
output_file = response.file.add()
output_file.name = proto_file.name.replace(".proto", ".cpp")
output_file.content = output_code
def main():
data = sys.stdin.buffer.read()
request = plugin.CodeGeneratorRequest.FromString(data)
response = plugin.CodeGeneratorResponse()
generate_converter(request.proto_file, response)
sys.stdout.buffer.write(response.SerializeToString())
if __name__ == "__main__":
main()
Run
protoc --plugin=protoc-gen-custom=/home/rtkid/Documents/pg_grpc_service_template/proto/handlers/plugin.sh --custom_out=. Angle.proto
protoc --plugin=protoc-gen-custom=/home/rtkid/Documents/pg_grpc_service_template/proto/handlers/plugin.sh --custom_out=. Vector2f.proto
Or inside 1 file.
Output
inline sf::Angle convert(api::sf::Angle&& dto)
{
return { std::move(*dto.mutable_radians()) };
}
inline api::sf::Angle convert(sf::Angle&& object)
{
return { std::move(object.radians) };
}
inline sf::Vector2f convert(api::sf::Vector2f&& dto)
{
return { std::move(*dto.mutable_x()), std::move(*dto.mutable_y()) };
}
inline api::sf::Vector2f convert(sf::Vector2f&& object)
{
return { std::move(object.x), std::move(object.y) };
}
Metadata
Assignees
Labels
No labels