Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coverter: Protobuf -> Domain #670

Open
root-kidik opened this issue Aug 12, 2024 · 0 comments
Open

Coverter: Protobuf -> Domain #670

root-kidik opened this issue Aug 12, 2024 · 0 comments

Comments

@root-kidik
Copy link
Contributor

root-kidik commented Aug 12, 2024

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) };
}            
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant