QtGrpc: Update code generator to generate gRPC structures

Split the .proto files generator into QtProtobuf and QtGrpc parts.

Pick-to: 6.5
Task-number: QTBUG-105496
Change-Id: Ib43abe4c1fb849ecf68952b82af9d3988e88e02a
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
Tatiana Borisova 2022-11-21 18:31:49 +01:00
parent c287697474
commit 326ebfaadb
69 changed files with 3131 additions and 1082 deletions

View File

@ -15,5 +15,7 @@ find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Co
find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Network)
include("${CMAKE_CURRENT_LIST_DIR}/cmake/QtProtobufBuildInternals.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/src/tools/qtprotobufgen/Qt6ProtobufToolsMacros.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/src/tools/qtgrpcgen/Qt6GrpcToolsMacros.cmake")
qt_build_repo()

View File

@ -5,24 +5,25 @@ project(MyProject)
find_package(Qt6 REQUIRED COMPONENTS Grpc Protobuf)
qt_standard_project_setup()
qt_add_protobuf(MyMessages
FOLDER
qt_add_grpc(MyGrpcClient CLIENT
PROTO_FILES
path/to/service.proto
path/to/message.proto
path/to/other_message.proto
PROTO_INCLUDES
/path/to/proto/include
)
target_link_libraries(MyMessages PRIVATE Qt6::Grpc)
target_link_libraries(MyGrpcClient PRIVATE Qt6::Grpc)
qt_add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE MyMessages)
target_link_libraries(MyApp PRIVATE MyGrpcClient)
\endcode
In the example above we generate a library called \c{MyMessages}
by calling the \l{qt_add_protobuf.html}{qt_add_protobuf()} CMake function.
In the example above we generate a library called \c{MyGrpcClient}
by calling the \l{qt_add_grpc.html}{qt_add_grpc()} CMake function.
Then we are linking generated library with \c{Qt6::Grpc} library.
We then create a target for an executable called \c{MyApp} which we link
to the \c{MyMessages} library.
to the \c{MyGrpcClient} library.

View File

@ -30,7 +30,7 @@ qhp.QtProtobuf.subprojects.classes.sortPages = true
depends += qtdoc qtcore qtcmake
{headerdirs,sourcedirs} += ..
sourcedirs += ../../tools/qtprotobufgen/doc/src
sourcedirs += ../../tools/doc/src
exampledirs += ../../../examples/protobuf

View File

@ -2,5 +2,11 @@
# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_qtprotobufgen)
# Skip building qtprotoccommon when not building tools
if((NOT CMAKE_CROSSCOMPILING OR QT_FORCE_BUILD_TOOLS)
AND TARGET WrapProtobuf::WrapLibProtoc AND TARGET WrapProtobuf::WrapLibProtobuf)
add_subdirectory(qtprotoccommon)
endif()
add_subdirectory(qtprotobufgen)
add_subdirectory(qtgrpcgen)
endif()

View File

@ -0,0 +1,41 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_get_tool_target_name(target_name qtgrpcgen)
qt_internal_add_tool(${target_name}
TARGET_DESCRIPTION "Qt gRPC generator"
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
TOOLS_TARGET Grpc
CORE_LIBRARY None
SOURCES
main.cpp
qgrpcgenerator.cpp qgrpcgenerator.h
grpctemplates.cpp grpctemplates.h
serverdeclarationprinter.cpp serverdeclarationprinter.h
clientdeclarationprinter.cpp clientdeclarationprinter.h
clientdefinitionprinter.cpp clientdefinitionprinter.h
EXTRA_CMAKE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}GrpcToolsMacros.cmake"
EXTRA_CMAKE_INCLUDES
"${QT_CMAKE_EXPORT_NAMESPACE}GrpcToolsMacros.cmake"
LIBRARIES
WrapProtobuf::WrapLibProtoc
QtProtocCommon
)
qt_internal_return_unless_building_tools()
qt_record_extra_package_dependency(${target_name} WrapProtoc "")
if(MSVC)
# Disable C4251:
# `class 'type1' needs to have dll-interface to be used by clients of class 'type2'`
# which can be generated from some of the protobuf headers on msvc.
# This warning is also disabled globally in Qt in QtCore/qcompilerdetection.h
target_compile_options(${target_name}
PRIVATE "/wd4251"
)
target_compile_definitions(${target_name}
PRIVATE "_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING"
)
endif()

View File

@ -0,0 +1,215 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# The function looks for the service definitions inside provided PROTO_FILES and returns list of
# the absolute .proto file paths, protobuf include paths and files that are expected to be generated
# by qtgrpcgen.
# Optional arguments:
# GENERATE_PACKAGE_SUBFOLDERS - generated files will be located in package-base subdirectories.
#
# Multi-value arguments:
# PROTO_FILES - input list of the proto files. May contain either absolute or relative paths.
function(_qt_internal_grpc_preparse_proto_files type
out_proto_files out_proto_includes out_generated_files base_dir)
cmake_parse_arguments(arg "GENERATE_PACKAGE_SUBFOLDERS" "" "PROTO_FILES" ${ARGN})
unset(proto_files)
unset(proto_includes)
unset(output_files)
foreach(f IN LISTS arg_PROTO_FILES)
if(NOT IS_ABSOLUTE "${f}")
set(f "${base_dir}/${f}")
get_filename_component(f "${f}" ABSOLUTE)
endif()
get_filename_component(f "${f}" REALPATH)
list(APPEND proto_files "${f}")
_qt_internal_preparse_proto_file_common(result proto_package "${f}" "service")
if(NOT result)
message(NOTICE "No services found in ${f}. Skipping.")
return()
endif()
get_filename_component(proto_file_base_dir "${f}" DIRECTORY)
list(PREPEND proto_includes "${proto_file_base_dir}")
string(REPLACE "." "/" package_full_path "${proto_package}")
set(folder_path "")
if(arg_GENERATE_PACKAGE_SUBFOLDERS)
set(folder_path "${package_full_path}/")
endif()
get_filename_component(basename "${f}" NAME_WLE)
if(type STREQUAL "SERVER")
list(APPEND output_files
"${folder_path}${basename}_service.grpc.qpb.h")
elseif(type STREQUAL "CLIENT")
list(APPEND output_files
"${folder_path}${basename}_client.grpc.qpb.h"
"${folder_path}${basename}_client.grpc.qpb.cpp")
else()
message(FATAL_ERROR "Unknown gRPC target type: '${type}'.\n"
"Supported types: CLIENT.")
endif()
endforeach()
list(REMOVE_DUPLICATES proto_files)
list(REMOVE_DUPLICATES proto_includes)
list(REMOVE_DUPLICATES output_files)
set(${out_proto_files} "${proto_files}" PARENT_SCOPE)
set(${out_proto_includes} "${proto_includes}" PARENT_SCOPE)
set(${out_generated_files} "${output_files}" PARENT_SCOPE)
endfunction()
# TODO Qt6:
# - Collect PROTO_INCLUDES from the LINK_LIBRARIES property of TARGET
# - Collect proto files from the source files of the ${TARGET}
# This function is currently in Technical Preview
# Its signature and behavior might change.
function(qt6_add_grpc target type)
_qt_internal_get_protoc_common_options(protoc_option_opt protoc_single_opt protoc_multi_opt)
_qt_internal_get_protoc_generate_arguments(protoc_option_arg protoc_single_arg protoc_multi_arg)
set(option_args
${protoc_option_opt}
${protoc_option_arg}
)
set(single_args
${protoc_single_opt}
${protoc_single_arg}
)
set(multi_args
${protoc_multi_opt}
${protoc_multi_arg}
)
cmake_parse_arguments(arg "${option_args}" "${single_args}" "${multi_args}" ${ARGN})
# TODO: Add the gRPC 'SERVER' target type support when implemented.
set(supported_grpc_targets CLIENT)
if(NOT type IN_LIST supported_grpc_targets)
message(FATAL_ERROR "Unknown gRPC target type: '${type}'.\n"
"Supported types: CLIENT.")
endif()
_qt_internal_get_protoc_options(generation_options arg
protoc_option_opt protoc_single_opt protoc_multi_opt)
if(arg_PROTO_FILES_BASE_DIR)
set(base_dir "${arg_PROTO_FILES_BASE_DIR}")
else()
set(base_dir "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
unset(extra_pre_parse_options)
if(arg_GENERATE_PACKAGE_SUBFOLDERS)
list(APPEND extra_pre_parse_options "GENERATE_PACKAGE_SUBFOLDERS")
endif()
_qt_internal_grpc_preparse_proto_files(${type} proto_files proto_includes generated_files
"${base_dir}"
${extra_pre_parse_options}
PROTO_FILES
${arg_PROTO_FILES}
)
if(arg_PROTO_INCLUDES)
list(APPEND proto_includes ${arg_PROTO_INCLUDES})
endif()
set(is_shared FALSE)
set(is_static FALSE)
set(is_executable FALSE)
if(TARGET ${target})
get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "SHARED_LIBRARY")
set(is_shared TRUE)
elseif(target_type STREQUAL "STATIC_LIBRARY")
set(is_static TRUE)
elseif(target_type STREQUAL "EXECUTABLE")
set(is_executable TRUE)
else()
message(FATAL_ERROR "Unsupported target type '${target_type}'.")
endif()
else()
if(BUILD_SHARED_LIBS)
set(target_type "SHARED_LIBRARY")
set(is_shared TRUE)
else()
set(target_type "STATIC_LIBRARY")
set(is_static TRUE)
endif()
_qt_internal_add_library(${target})
if(DEFINED arg_OUTPUT_TARGETS)
list(APPEND ${arg_OUTPUT_TARGETS} "${target}")
endif()
endif()
if(is_static OR is_shared)
# Add EXPORT_MACRO if the target is, or we will create, a shared library
string(TOUPPER "${target}" target_upper)
if (is_shared)
list(APPEND generation_options "EXPORT_MACRO=${target_upper}")
endif()
# Define this so we can conditionally set the export macro
target_compile_definitions(${target}
PRIVATE "QT_BUILD_${target_upper}_LIB")
endif()
set(output_directory "${CMAKE_CURRENT_BINARY_DIR}")
if(DEFINED arg_OUTPUT_DIRECTORY)
set(output_directory "${arg_OUTPUT_DIRECTORY}")
endif()
list(TRANSFORM generated_files PREPEND "${output_directory}/")
_qt_internal_protoc_generate(${target} qtgrpcgen "${output_directory}"
PROTO_FILES ${proto_files}
PROTO_INCLUDES ${proto_includes}
GENERATED_FILES ${generated_files}
)
target_sources(${target} PRIVATE ${generated_files})
# Filter generated headers
set(generated_headers "${generated_files}")
list(FILTER generated_headers INCLUDE REGEX ".+\\.h$")
if(is_static OR is_shared)
set_target_properties(${target}
PROPERTIES
PUBLIC_HEADER "${generated_headers}"
AUTOMOC ON
)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${target}
PRIVATE "/Zc:__cplusplus" "/permissive-" "/bigobj")
endif()
target_link_libraries(${target} PRIVATE
${QT_CMAKE_EXPORT_NAMESPACE}::Grpc
)
if(DEFINED arg_OUTPUT_HEADERS)
set(${arg_OUTPUT_HEADERS} "${generated_headers}" PARENT_SCOPE)
endif()
if(DEFINED arg_OUTPUT_TARGETS)
set(${arg_OUTPUT_TARGETS} "${${arg_OUTPUT_TARGETS}}" PARENT_SCOPE)
endif()
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_add_grpc)
if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_add_grpc(${ARGN})
else()
message(FATAL_ERROR "qt6_add_grpc() is only available in Qt 6. "
"Please check the protobuf documentation for alternatives.")
endif()
endfunction()
endif()

View File

@ -14,10 +14,11 @@
#include <unordered_set>
#include "generatorcommon.h"
#include "templates.h"
#include "utils.h"
#include "commontemplates.h"
#include "grpctemplates.h"
using namespace ::QtProtobuf::generator;
using namespace ::QtGrpc;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::compiler;
@ -33,7 +34,7 @@ ClientDeclarationPrinter::ClientDeclarationPrinter(
const ::google::protobuf::ServiceDescriptor *service,
const std::shared_ptr<::google::protobuf::io::Printer> &printer)
: DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>(
service, printer, common::produceClientTypeMap(service, nullptr))
service, printer, common::produceClientTypeMap(service, nullptr))
{
}
@ -41,18 +42,18 @@ ClientDeclarationPrinter::ClientDeclarationPrinter(
void ClientDeclarationPrinter::printOpenNamespace()
{
m_printer->Print({ { "scope_namespaces", m_typeMap["scope_type"] } },
Templates::NamespaceTemplate());
CommonTemplates::NamespaceTemplate());
}
void ClientDeclarationPrinter::printClientClass()
{
m_printer->Print(m_typeMap, Templates::ChildClassDeclarationTemplate());
m_printer->Print(m_typeMap, GrpcTemplates::ChildClassDeclarationTemplate());
}
void ClientDeclarationPrinter::printConstructor()
{
Indent();
m_printer->Print(m_typeMap, Templates::QObjectConstructorMessageDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::QObjectConstructorMessageDeclarationTemplate());
Outdent();
}
@ -64,15 +65,15 @@ void ClientDeclarationPrinter::printClientMethodsDeclaration()
MethodMap parameters = common::produceMethodMap(method, m_typeMap["classname"]);
if (method->server_streaming()) {
m_printer->Print(parameters, Templates::ClientMethodServerStreamDeclarationTemplate());
m_printer->Print(parameters, Templates::ClientMethodServerStream2DeclarationTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodServerStreamDeclarationTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodServerStream2DeclarationTemplate());
} else {
m_printer->Print(parameters, Templates::ClientMethodDeclarationSyncTemplate());
m_printer->Print(parameters, Templates::ClientMethodDeclarationAsyncTemplate());
m_printer->Print(parameters, Templates::ClientMethodDeclarationAsync2Template());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDeclarationSyncTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDeclarationAsyncTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDeclarationAsync2Template());
if (Options::instance().hasQml()) {
m_printer->Print(parameters, Templates::ClientMethodDeclarationQmlTemplate());
m_printer->Print(parameters, Templates::ClientMethodDeclarationQml2Template());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDeclarationQmlTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDeclarationQml2Template());
}
}
m_printer->Print("\n");
@ -87,7 +88,7 @@ void ClientDeclarationPrinter::printClientMethodsDeclaration()
if (method->server_streaming()) {
if (Options::instance().hasQml()) {
m_printer->Print(parameters,
Templates::ClientMethodServerStreamQmlDeclarationTemplate());
GrpcTemplates::ClientMethodServerStreamQmlDeclarationTemplate());
}
}
}
@ -98,5 +99,5 @@ void ClientDeclarationPrinter::printClientMethodsDeclaration()
void ClientDeclarationPrinter::printCloseNamespace()
{
m_printer->Print({ { "scope_namespaces", m_typeMap["scope_type"] } },
Templates::NamespaceClosingTemplate());
CommonTemplates::NamespaceClosingTemplate());
}

View File

@ -5,19 +5,21 @@
#pragma once
#include "descriptorprinterbase.h"
#include <google/protobuf/io/printer.h>
#include <memory>
namespace google {
namespace protobuf {
namespace google::protobuf {
class ServiceDescriptor;
class Message;
} // namespace protobuf
} // namespace google
}
namespace io {
class Printer;
}
namespace QtProtobuf::generator {
class ClientDeclarationPrinter : public DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>
namespace QtGrpc {
class ClientDeclarationPrinter :
public qtprotoccommon::DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>
{
public:
ClientDeclarationPrinter(const ::google::protobuf::ServiceDescriptor *service,
@ -43,4 +45,4 @@ private:
void printCloseNamespace();
};
} // namespace QtProtobuf::generator
} // namespace QtGrpc

View File

@ -7,10 +7,11 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include "generatorcommon.h"
#include "templates.h"
#include "utils.h"
#include "commontemplates.h"
#include "grpctemplates.h"
using namespace ::QtProtobuf::generator;
using namespace ::QtGrpc;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::compiler;
@ -26,36 +27,43 @@ ClientDefinitionPrinter::ClientDefinitionPrinter(
const google::protobuf::ServiceDescriptor *service,
const std::shared_ptr<::google::protobuf::io::Printer> &printer)
: DescriptorPrinterBase<google::protobuf::ServiceDescriptor>(
service, printer, common::produceClientTypeMap(service, nullptr))
service, printer, common::produceClientTypeMap(service, nullptr))
{
}
void ClientDefinitionPrinter::printOpenNamespace()
{
m_printer->Print({ { "scope_namespaces", m_typeMap["scope_type"] } },
Templates::NamespaceTemplate());
CommonTemplates::NamespaceTemplate());
}
void ClientDefinitionPrinter::printMethods()
{
for (int i = 0; i < m_descriptor->method_count(); i++) {
const MethodDescriptor *method = m_descriptor->method(i);
MethodMap parameters = common::produceMethodMap(method, m_typeMap["classname"]);
if (method->server_streaming()) {
m_printer->Print(parameters, Templates::ClientMethodServerStreamDefinitionTemplate());
m_printer->Print(parameters, Templates::ClientMethodServerStream2DefinitionTemplate());
if (Options::instance().hasQml()) {
m_printer->Print(parameters,
Templates::ClientMethodServerStreamQmlDefinitionTemplate());
}
} else {
m_printer->Print(parameters, Templates::ClientMethodDefinitionSyncTemplate());
m_printer->Print(parameters, Templates::ClientMethodDefinitionAsyncTemplate());
m_printer->Print(parameters, Templates::ClientMethodDefinitionAsync2Template());
if (Options::instance().hasQml()) {
m_printer->Print(parameters, Templates::ClientMethodDefinitionQmlTemplate());
m_printer->Print(parameters, Templates::ClientMethodDefinitionQml2Template());
}
printMethod(method);
}
}
void ClientDefinitionPrinter::printMethod(const MethodDescriptor *method)
{
MethodMap parameters = common::produceMethodMap(method, m_typeMap["classname"]);
if (method->server_streaming()) {
m_printer->Print(parameters,
GrpcTemplates::ClientMethodServerStreamDefinitionTemplate());
m_printer->Print(parameters,
GrpcTemplates::ClientMethodServerStream2DefinitionTemplate());
if (Options::instance().hasQml()) {
m_printer->Print(parameters,
GrpcTemplates::ClientMethodServerStreamQmlDefinitionTemplate());
}
} else {
m_printer->Print(parameters, GrpcTemplates::ClientMethodDefinitionSyncTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDefinitionAsyncTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDefinitionAsync2Template());
if (Options::instance().hasQml()) {
m_printer->Print(parameters, GrpcTemplates::ClientMethodDefinitionQmlTemplate());
m_printer->Print(parameters, GrpcTemplates::ClientMethodDefinitionQml2Template());
}
}
}
@ -65,11 +73,11 @@ void ClientDefinitionPrinter::printConstructor()
m_printer->Print({ { "classname", m_typeMap["classname"] },
{ "parent_class", m_typeMap["parent_class"] },
{ "service_name", m_descriptor->full_name() } },
Templates::ClientConstructorDefinitionTemplate());
GrpcTemplates::ClientConstructorDefinitionTemplate());
}
void ClientDefinitionPrinter::printCloseNamespace()
{
m_printer->Print({ { "scope_namespaces", m_typeMap["scope_type"] } },
Templates::NamespaceClosingTemplate());
CommonTemplates::NamespaceClosingTemplate());
}

View File

@ -6,8 +6,10 @@
#include "descriptorprinterbase.h"
namespace QtProtobuf::generator {
class ClientDefinitionPrinter : public DescriptorPrinterBase<google::protobuf::ServiceDescriptor>
namespace QtGrpc {
class ClientDefinitionPrinter :
public qtprotoccommon::DescriptorPrinterBase<google::protobuf::ServiceDescriptor>
{
public:
ClientDefinitionPrinter(const google::protobuf::ServiceDescriptor *service,
@ -23,6 +25,8 @@ public:
void printConstructor();
void printMethods();
void printCloseNamespace();
private:
void printMethod(const ::google::protobuf::MethodDescriptor *method);
};
} // namespace QtProtobuf::generator
} // namespace QtGrpc

View File

@ -0,0 +1,221 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "grpctemplates.h"
using namespace ::QtGrpc;
const char *GrpcTemplates::ChildClassDeclarationTemplate()
{
return "\nclass $export_macro$ $classname$ : public $parent_class$\n"
"{\n"
" Q_OBJECT\n";
}
const char *GrpcTemplates::ClientMethodDeclarationSyncTemplate()
{
return "QGrpcStatus $method_name$(const $param_type$ &$param_name$, "
"$return_type$ *$return_name$);\n";
}
const char *GrpcTemplates::ClientMethodDeclarationAsyncTemplate()
{
return "std::shared_ptr<QGrpcCallReply> $method_name$(const $param_type$ &$param_name$);\n";
}
const char *GrpcTemplates::ClientMethodDeclarationAsync2Template()
{
return "Q_INVOKABLE void $method_name$(const $param_type$ &$param_name$, const QObject "
"*context, "
"const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback);\n";
}
const char *GrpcTemplates::ClientMethodDeclarationQmlTemplate()
{
return "Q_INVOKABLE void $method_name$($param_type$ *$param_name$, const QJSValue &callback, "
"const QJSValue &errorCallback);\n";
}
const char *GrpcTemplates::ClientMethodDeclarationQml2Template()
{
return "Q_INVOKABLE void $method_name$($param_type$ *$param_name$, $return_type$ "
"*$return_name$, const QJSValue &errorCallback);\n";
}
const char *GrpcTemplates::ServerMethodDeclarationTemplate()
{
return "Q_INVOKABLE virtual $return_type$ $method_name$(const $param_type$ &$param_name$) = "
"0;\n";
}
const char *GrpcTemplates::ClientConstructorDefinitionTemplate()
{
return "\n$classname$::$classname$(QObject *parent) : $parent_class$(\"$service_name$\", "
"parent)\n"
"{\n"
"}\n";
}
const char *GrpcTemplates::ClientMethodDefinitionSyncTemplate()
{
return "\nQGrpcStatus $classname$::$method_name$(const $param_type$ &$param_name$, "
"$return_type$ *$return_name$)\n"
"{\n"
" return call<$param_type$>(\"$method_name$\", $param_name$, $return_name$);\n"
"}\n";
}
const char *GrpcTemplates::ClientMethodDefinitionAsyncTemplate()
{
return "\nstd::shared_ptr<QGrpcCallReply> $classname$::$method_name$(const $param_type$ "
"&$param_name$)\n"
"{\n"
" return call<$param_type$>(\"$method_name$\", $param_name$);\n"
"}\n";
}
const char *GrpcTemplates::ClientMethodDefinitionAsync2Template()
{
return "\nvoid $classname$::$method_name$(const $param_type$ &$param_name$, const QObject "
"*context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback)\n"
"{\n"
" std::shared_ptr<QGrpcCallReply> reply = call<$param_type$>(\"$method_name$\", "
"$param_name$);\n"
" QObject::connect(reply.get(), &QGrpcCallReply::finished, context, [reply, "
"callback]() "
"{\n"
" callback(reply);\n"
" });\n"
"}\n";
}
const char *GrpcTemplates::ClientMethodDefinitionQmlTemplate()
{
return "\nvoid $classname$::$method_name$($param_type$ *$param_name$, const QJSValue "
"&callback, "
"const QJSValue &errorCallback)\n"
"{\n"
" if (!callback.isCallable()) {\n"
" qWarning() << \"Unable to call $classname$::$method_name$, callback is not "
"callable\";\n"
" return;\n"
" }\n\n"
" if (arg == nullptr) {\n"
" qWarning() << \"Invalid argument provided for method "
"$classname$::$method_name$, "
"argument of type '$param_type$ *' expected\";\n"
" return;\n"
" }\n\n"
" QJSEngine *jsEngine = qjsEngine(this);\n"
" if (jsEngine == nullptr) {\n"
" qWarning() << \"Unable to call $classname$::$method_name$, it's only callable "
"from JS engine context\";\n"
" return;\n"
" }\n\n"
" std::shared_ptr<QGrpcCallReply> reply = call<$param_type$>(\"$method_name$\", "
"*$param_name$);\n"
" reply->subscribe(jsEngine, [this, reply, callback, jsEngine]() {\n"
" auto result = new $return_type$(reply->read<$return_type$>());\n"
" qmlEngine(this)->setObjectOwnership(result, QQmlEngine::JavaScriptOwnership);\n"
" QJSValue(callback).call(QJSValueList{jsEngine->toScriptValue(result)});\n"
" }, [errorCallback, jsEngine](const QGrpcStatus &status) {\n"
" QJSValue(errorCallback).call(QJSValueList{jsEngine->toScriptValue(status)});\n"
" });\n"
"}\n";
}
const char *GrpcTemplates::ClientMethodDefinitionQml2Template()
{
return "\nvoid $classname$::$method_name$($param_type$ *$param_name$, $return_type$ "
"*$return_name$, const QJSValue &errorCallback)\n"
"{\n"
" if ($return_name$ == nullptr) {\n"
" qWarning() << \"Invalid argument provided for method "
"$classname$::$method_name$, "
"argument of type '$return_type$ *' expected\";\n"
" return;\n"
" }\n\n"
" QWeakPointer<$return_type$> safeReturn($return_name$);\n\n"
" if ($param_name$ == nullptr) {\n"
" qWarning() << \"Invalid argument provided for method "
"$classname$::$method_name$, "
"argument of type '$param_type$ *' expected\";\n"
" return;\n"
" }\n\n"
" QJSEngine *jsEngine = qjsEngine(this);\n"
" if (jsEngine == nullptr) {\n"
" qWarning() << \"Unable to call $classname$::$method_name$, it's only callable "
"from JS engine context\";\n"
" return;\n"
" }\n\n"
" std::shared_ptr<QGrpcCallReply> reply = call<$param_type$>(\"$method_name$\", "
"*$param_name$);\n"
" reply->subscribe(jsEngine, [this, reply, jsEngine, safeReturn]() {\n"
" if (safeReturn.isNull()) {\n"
" qWarning() << \"Return value is destroyed. Ignore call result\";\n"
" return;\n"
" }\n"
" *safeReturn = $return_type$(reply->read<$return_type$>());\n"
" }, [errorCallback, jsEngine](const QGrpcStatus &status) {\n"
" QJSValue(errorCallback).call(QJSValueList{jsEngine->toScriptValue(status)});\n"
" });\n"
"}\n";
}
const char *GrpcTemplates::ClientMethodServerStreamDeclarationTemplate()
{
return "std::shared_ptr<QGrpcStream> stream$method_name_upper$(const $param_type$ "
"&$param_name$);\n";
}
const char *GrpcTemplates::ClientMethodServerStream2DeclarationTemplate()
{
return "std::shared_ptr<QGrpcStream> stream$method_name_upper$(const $param_type$ "
"&$param_name$, const "
"QWeakPointer<$return_type$> &$return_name$);\n";
}
const char *GrpcTemplates::ClientMethodServerStreamQmlDeclarationTemplate()
{
return "Q_INVOKABLE std::shared_ptr<QGrpcStream> qmlStream$method_name_upper$_p($param_type$ "
"*$param_name$, "
"$return_type$ *$return_name$);\n";
}
const char *GrpcTemplates::ClientMethodServerStreamDefinitionTemplate()
{
return "std::shared_ptr<QGrpcStream> $classname$::stream$method_name_upper$(const $param_type$ "
"&$param_name$)\n"
"{\n"
" return stream<$param_type$>(\"$method_name$\", $param_name$);\n"
"}\n";
}
const char *GrpcTemplates::ClientMethodServerStream2DefinitionTemplate()
{
return "std::shared_ptr<QGrpcStream> $classname$::stream$method_name_upper$(const $param_type$ "
"&$param_name$, const QWeakPointer<$return_type$> &$return_name$)\n"
"{\n"
" return stream<$param_type$>(\"$method_name$\", $param_name$, $return_name$);\n"
"}\n";
}
const char *GrpcTemplates::GrpcClientFileSuffix()
{
return "_client.grpc";
}
const char *GrpcTemplates::GrpcServiceFileSuffix()
{
return "_service.grpc";
}
const char *GrpcTemplates::ClientMethodServerStreamQmlDefinitionTemplate()
{
return "std::shared_ptr<QGrpcStream> $classname$::qmlStream$method_name_upper$_p($param_type$ "
"*$param_name$, "
"$return_type$ *$return_name$)\n"
"{\n"
" return stream<$param_type$>(\"$method_name$\", *$param_name$, "
"QWeakPointer<$return_type$>($return_name$));\n"
"}\n";
}

View File

@ -0,0 +1,45 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef GRPCTEMPLATES_H
#define GRPCTEMPLATES_H
namespace QtGrpc {
class GrpcTemplates
{
public:
// gRPC
static const char *ChildClassDeclarationTemplate();
static const char *GrpcClientFileSuffix();
static const char *GrpcServiceFileSuffix();
static const char *ClientConstructorDefinitionTemplate();
static const char *ClientMethodDeclarationSyncTemplate();
static const char *ClientMethodDeclarationAsyncTemplate();
static const char *ClientMethodDeclarationAsync2Template();
static const char *ClientMethodDeclarationQmlTemplate();
static const char *ClientMethodDeclarationQml2Template();
static const char *ServerMethodDeclarationTemplate();
static const char *ClientMethodDefinitionSyncTemplate();
static const char *ClientMethodDefinitionAsyncTemplate();
static const char *ClientMethodDefinitionAsync2Template();
static const char *ClientMethodDefinitionQmlTemplate();
static const char *ClientMethodDefinitionQml2Template();
static const char *ClientMethodServerStreamDeclarationTemplate();
static const char *ClientMethodServerStream2DeclarationTemplate();
static const char *ClientMethodServerStreamQmlDeclarationTemplate();
static const char *ClientMethodServerStreamDefinitionTemplate();
static const char *ClientMethodServerStream2DefinitionTemplate();
static const char *ClientMethodServerStreamQmlDefinitionTemplate();
};
} // namespace QtGrpc
#endif // GRPCTEMPLATES_H

View File

@ -0,0 +1,21 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <google/protobuf/compiler/plugin.h>
#include "qgrpcgenerator.h"
#include "options.h"
#include "utils.h"
using namespace QtGrpc;
int main(int argc, char *argv[])
{
char *optionsPtr = getenv("QT_GRPC_OPTIONS");
if (optionsPtr != nullptr) {
QT_PROTOBUF_DEBUG("QT_GRPC_OPTIONS: " << optionsPtr);
qtprotoccommon::Options::setFromString(optionsPtr);
}
QGrpcGenerator generator;
return ::google::protobuf::compiler::PluginMain(argc, argv, &generator);
}

View File

@ -0,0 +1,194 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qgrpcgenerator.h"
#include "clientdeclarationprinter.h"
#include "clientdefinitionprinter.h"
#include "serverdeclarationprinter.h"
#include "grpctemplates.h"
#include "utils.h"
#include "options.h"
#include <set>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.h>
using namespace ::QtGrpc;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
using namespace ::google::protobuf::compiler;
QGrpcGenerator::QGrpcGenerator() : GeneratorBase()
{}
QGrpcGenerator::~QGrpcGenerator() = default;
bool QGrpcGenerator::Generate(const FileDescriptor *file,
[[maybe_unused]] const std::string &parameter,
GeneratorContext *generatorContext,
std::string *error) const
{
assert(file != nullptr && generatorContext != nullptr);
if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
*error = "Invalid proto used. qtgrpcgen only supports 'proto3' syntax";
return false;
}
return GenerateServices(file, generatorContext);
}
void QGrpcGenerator::SetInternalIncludes(const FileDescriptor *file,
std::set<std::string>& internalIncludes) const
{
assert(file != nullptr);
for (int i = 0; i < file->service_count(); ++i) {
const ServiceDescriptor *service = file->service(i);
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor *method = service->method(i);
if (method->input_type()->file() != service->file()) {
internalIncludes.insert(
utils::removeFileSuffix(method->input_type()->file()->name())
+ CommonTemplates::ProtoFileSuffix());
}
if (method->output_type()->file() != service->file()) {
internalIncludes.insert(
utils::removeFileSuffix(method->output_type()->file()->name())
+ CommonTemplates::ProtoFileSuffix());
}
}
}
if (file->message_type_count() > 0) {
internalIncludes.insert(generateBaseName(file, utils::extractFileBasename(file->name()))
+ CommonTemplates::ProtoFileSuffix());
}
}
void QGrpcGenerator::RunPrinters(const FileDescriptor *file,
std::shared_ptr<Printer> clientHeaderPrinter,
std::shared_ptr<Printer> clientSourcePrinter,
std::shared_ptr<Printer> serviceHeaderPrinter) const
{
assert(file != nullptr);
for (int i = 0; i < file->service_count(); ++i) {
const ServiceDescriptor *service = file->service(i);
ClientDeclarationPrinter clientDecl(service, clientHeaderPrinter);
clientDecl.run();
ClientDefinitionPrinter clientDef(service, clientSourcePrinter);
clientDef.run();
ServerDeclarationPrinter serverDecl(service, serviceHeaderPrinter);
serverDecl.run();
}
}
bool QGrpcGenerator::GenerateServices(const FileDescriptor *file,
GeneratorContext *generatorContext) const
{
assert(file != nullptr && generatorContext != nullptr);
if (file->service_count() <= 0)
return true;
std::set<std::string> internalIncludes;
const std::string filename = utils::extractFileBasename(file->name());
const std::string basename = generateBaseName(file, filename);
const std::string clientFileName = basename
+ GrpcTemplates::GrpcClientFileSuffix() + CommonTemplates::ProtoFileSuffix();
std::unique_ptr<ZeroCopyOutputStream> clientHeaderStream(
generatorContext->Open(clientFileName + ".h"));
std::unique_ptr<ZeroCopyOutputStream> clientSourceStream(
generatorContext->Open(clientFileName + ".cpp"));
std::unique_ptr<ZeroCopyOutputStream> serviceHeaderStream(
generatorContext->Open(basename
+ GrpcTemplates::GrpcServiceFileSuffix()
+ CommonTemplates::ProtoFileSuffix() + ".h"));
std::shared_ptr<Printer> clientHeaderPrinter(new Printer(clientHeaderStream.get(), '$'));
std::shared_ptr<Printer> clientSourcePrinter(new Printer(clientSourceStream.get(), '$'));
std::shared_ptr<Printer> serviceHeaderPrinter(new Printer(serviceHeaderStream.get(), '$'));
printDisclaimer(clientHeaderPrinter.get());
clientHeaderPrinter->Print({ { "filename", filename + "_client" } },
CommonTemplates::PreambleTemplate());
printDisclaimer(serviceHeaderPrinter.get());
serviceHeaderPrinter->Print({ { "filename", filename + "_service" } },
CommonTemplates::PreambleTemplate());
clientHeaderPrinter->Print(CommonTemplates::DefaultProtobufIncludesTemplate());
if (Options::instance().hasQml())
clientHeaderPrinter->Print(CommonTemplates::QmlProtobufIncludesTemplate());
serviceHeaderPrinter->Print(CommonTemplates::DefaultProtobufIncludesTemplate());
if (Options::instance().hasQml())
serviceHeaderPrinter->Print(CommonTemplates::QmlProtobufIncludesTemplate());
printDisclaimer(clientSourcePrinter.get());
clientSourcePrinter->Print({ { "include", clientFileName } },
CommonTemplates::InternalIncludeTemplate());
SetInternalIncludes(file, internalIncludes);
std::set<std::string> externalIncludes
= {"QAbstractGrpcClient", "QGrpcCallReply", "QGrpcStream"};
for (const auto &include : externalIncludes) {
clientHeaderPrinter->Print({ { "include", include } },
CommonTemplates::ExternalIncludeTemplate());
serviceHeaderPrinter->Print({ { "include", include } },
CommonTemplates::ExternalIncludeTemplate());
}
const std::string serviceIncludes = std::string("QAbstractGrpcService");
serviceHeaderPrinter->Print({ { "include", serviceIncludes } },
CommonTemplates::ExternalIncludeTemplate());
for (const auto &include : internalIncludes) {
clientHeaderPrinter->Print({ { "include", include } },
CommonTemplates::InternalIncludeTemplate());
serviceHeaderPrinter->Print({ { "include", include } },
CommonTemplates::InternalIncludeTemplate());
}
if (Options::instance().hasQml()) {
clientSourcePrinter->Print({ { "include", "QQmlEngine" } },
CommonTemplates::ExternalIncludeTemplate());
clientSourcePrinter->Print({ { "include", "QJSEngine" } },
CommonTemplates::ExternalIncludeTemplate());
clientSourcePrinter->Print({ { "include", "QJSValue" } },
CommonTemplates::ExternalIncludeTemplate());
}
clientHeaderPrinter->PrintRaw("\n");
serviceHeaderPrinter->PrintRaw("\n");
if (!Options::instance().exportMacro().empty()) {
clientHeaderPrinter->Print({ { "export_macro", Options::instance().exportMacro() } },
CommonTemplates::ExportMacroTemplate());
serviceHeaderPrinter->Print({ { "export_macro", Options::instance().exportMacro() } },
CommonTemplates::ExportMacroTemplate());
}
OpenFileNamespaces(file, clientHeaderPrinter.get());
OpenFileNamespaces(file, clientSourcePrinter.get());
OpenFileNamespaces(file, serviceHeaderPrinter.get());
RunPrinters(file, clientHeaderPrinter, clientSourcePrinter, serviceHeaderPrinter);
CloseFileNamespaces(file, clientHeaderPrinter.get());
CloseFileNamespaces(file, clientSourcePrinter.get());
CloseFileNamespaces(file, serviceHeaderPrinter.get());
clientHeaderPrinter->Print({ { "filename", filename + "_client" } },
CommonTemplates::FooterTemplate());
serviceHeaderPrinter->Print({ { "filename", filename + "_service" } },
CommonTemplates::FooterTemplate());
return true;
}

View File

@ -0,0 +1,45 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QGRPCGENERATOR_H
#define QGRPCGENERATOR_H
#include <memory>
#include "generatorbase.h"
namespace google::protobuf {
class FileDescriptor;
class Descriptor;
namespace compiler {
class GeneratorContext;
} // namespace compiler
namespace io {
class Printer;
}
} // namespace google::protobuf
namespace QtGrpc {
class QGrpcGenerator : public qtprotoccommon::GeneratorBase
{
public:
QGrpcGenerator();
~QGrpcGenerator();
bool Generate(const ::google::protobuf::FileDescriptor *file,
const std::string &parameter,
::google::protobuf::compiler::GeneratorContext *generatorContext,
std::string *error) const override;
private:
bool GenerateServices(const ::google::protobuf::FileDescriptor *file,
::google::protobuf::compiler::GeneratorContext *generatorContext) const;
void SetInternalIncludes(const ::google::protobuf::FileDescriptor *file,
std::set<std::string> &internalIncludes) const;
void RunPrinters(const ::google::protobuf::FileDescriptor *file,
std::shared_ptr<::google::protobuf::io::Printer> clientHeaderPrinter,
std::shared_ptr<::google::protobuf::io::Printer> clientSourcePrinter,
std::shared_ptr<::google::protobuf::io::Printer> serviceHeaderPrinter) const;
};
} // namespace QtGrpc
#endif // QGRPCGENERATOR_H

View File

@ -8,8 +8,10 @@
#include <google/protobuf/io/printer.h>
#include "generatorcommon.h"
#include "grpctemplates.h"
using namespace ::QtProtobuf::generator;
using namespace ::QtGrpc;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
/*!
@ -24,19 +26,19 @@ ServerDeclarationPrinter::ServerDeclarationPrinter(
const ::google::protobuf::ServiceDescriptor *service,
const std::shared_ptr<::google::protobuf::io::Printer> &printer)
: DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>(
service, printer, common::produceServiceTypeMap(service, nullptr))
service, printer, common::produceServiceTypeMap(service, nullptr))
{
}
void ServerDeclarationPrinter::printOpenNamespace()
{
m_printer->Print({ { "scope_namespaces", m_typeMap["scope_type"] } },
Templates::NamespaceTemplate());
CommonTemplates::NamespaceTemplate());
}
void ServerDeclarationPrinter::printClassName()
{
m_printer->Print(m_typeMap, Templates::ChildClassDeclarationTemplate());
m_printer->Print(m_typeMap, GrpcTemplates::ChildClassDeclarationTemplate());
}
void ServerDeclarationPrinter::printMethodsDeclaration(const char *methodTemplate,
@ -58,5 +60,5 @@ void ServerDeclarationPrinter::printMethodsDeclaration(const char *methodTemplat
void ServerDeclarationPrinter::printCloseNamespace()
{
m_printer->Print({ { "scope_namespaces", m_typeMap["scope_type"] } },
Templates::NamespaceClosingTemplate());
CommonTemplates::NamespaceClosingTemplate());
}

View File

@ -6,20 +6,21 @@
#define SERVERDECLARATIONPRINTER_H
#include "descriptorprinterbase.h"
#include <google/protobuf/io/printer.h>
#include "grpctemplates.h"
#include <string>
namespace google {
namespace protobuf {
namespace google::protobuf {
class ServiceDescriptor;
class Message;
} // namespace protobuf
} // namespace google
}
namespace io {
class Printer;
}
namespace QtProtobuf {
namespace generator {
namespace QtGrpc {
class ServerDeclarationPrinter : public DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>
class ServerDeclarationPrinter :
public qtprotoccommon::DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>
{
public:
ServerDeclarationPrinter(const google::protobuf::ServiceDescriptor *service,
@ -31,7 +32,7 @@ public:
printOpenNamespace();
printClassName();
printPublicBlock();
printMethodsDeclaration(Templates::ServerMethodDeclarationTemplate());
printMethodsDeclaration(GrpcTemplates::ServerMethodDeclarationTemplate());
encloseClass();
printCloseNamespace();
}
@ -43,7 +44,5 @@ private:
const char *methodAsync2Template = "");
void printCloseNamespace();
};
} // namespace generator
} // namespace QtProtobuf
} // namespace QtGrpc
#endif // SERVERDECLARATIONPRINTER_H

View File

@ -1,10 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# The include is needed by Qt::Protobuf tests that use qt6_add_protobuf call to
# generate the code of protobuf messages for testing.
include("${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}ProtobufToolsMacros.cmake")
qt_get_tool_target_name(target_name qtprotobufgen)
qt_internal_add_tool(${target_name}
TARGET_DESCRIPTION "Qt protobuf generator"
@ -12,22 +8,12 @@ qt_internal_add_tool(${target_name}
TOOLS_TARGET Protobuf
CORE_LIBRARY None
SOURCES
utils.cpp utils.h
descriptorprinterbase.h
main.cpp
generatorcommon.cpp generatorcommon.h
options.cpp options.h
templates.cpp templates.h
generatorbase.cpp generatorbase.h
singlefilegenerator.cpp singlefilegenerator.h
baseprinter.cpp baseprinter.h
qprotobufgenerator.cpp qprotobufgenerator.h
messagedeclarationprinter.cpp messagedeclarationprinter.h
messagedefinitionprinter.cpp messagedefinitionprinter.h
enumdeclarationprinter.cpp enumdeclarationprinter.h
enumdefinitionprinter.cpp enumdefinitionprinter.h
serverdeclarationprinter.cpp serverdeclarationprinter.h
clientdeclarationprinter.cpp clientdeclarationprinter.h
clientdefinitionprinter.cpp clientdefinitionprinter.h
EXTRA_CMAKE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}ProtobufToolsMacros.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/QtProtocCommandWrapper.cmake"
@ -36,6 +22,7 @@ qt_internal_add_tool(${target_name}
LIBRARIES
WrapProtobuf::WrapLibProtobuf
WrapProtobuf::WrapLibProtoc
QtProtocCommon
)
qt_internal_return_unless_building_tools()

View File

@ -3,6 +3,189 @@
set(__qt_protobuf_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "")
# List of the common protoc generator options.
macro(_qt_internal_get_protoc_common_options option_args single_args multi_args)
set(${option_args}
COPY_COMMENTS
GENERATE_PACKAGE_SUBFOLDERS
)
set(${single_args}
EXTRA_NAMESPACE
EXPORT_MACRO
)
set(${multi_args} "")
endmacro()
# List of arguments common for the protoc generating functions.
macro(_qt_internal_get_protoc_generate_arguments option_args single_args multi_args)
set(${option_args} "")
set(${single_args}
OUTPUT_DIRECTORY
PROTO_FILES_BASE_DIR
OUTPUT_HEADERS
OUTPUT_TARGETS
)
set(${multi_args}
PROTO_FILES
PROTO_INCLUDES
)
endmacro()
# The macro collects options in protoc compatible format. Options are written into out_var.
# All input arguments are names of the lists containing the corresponding options.
macro(_qt_internal_get_protoc_options out_var prefix option single multi)
set(${out_var} "")
foreach(opt IN LISTS ${option})
if(${prefix}_${opt})
list(APPEND ${out_var} ${opt})
endif()
endforeach()
foreach(opt IN LISTS ${single} ${multi})
if(${prefix}_${opt})
list(APPEND ${out_var} "${opt}=${${prefix}_${opt}}")
endif()
endforeach()
endmacro()
# The base function that generates rules to call the protoc executable with the custom generator
# plugin.
# Multi-value Arguments:
# PROTO_FILES - list of the .proto file paths. Paths should be absolute for the correct work of
# this function.
# PROTO_INCLUDES - list of the protobuf include paths.
# GENERATED_FILES - list of files that are expected
# to be genreated by the custom generator plugin.
function(_qt_internal_protoc_generate target generator output_directory)
cmake_parse_arguments(arg "" "" "PROTO_FILES;PROTO_INCLUDES;GENERATED_FILES" ${ARGN})
if(NOT arg_PROTO_FILES)
message(FATAL_ERROR "PROTO_FILES list is empty.")
endif()
unset(proto_includes)
if(arg_PROTO_INCLUDES)
set(proto_includes "${arg_PROTO_INCLUDES}")
endif()
if(NOT arg_GENERATED_FILES)
set(generated_files "${arg_GENERATED_FILES}")
message(FATAL_ERROR
"List of generated sources for target '${target}' is empty")
endif()
get_filename_component(output_directory "${output_directory}" REALPATH)
file(MAKE_DIRECTORY ${output_directory})
unset(num_deps)
if(TARGET ${target})
get_target_property(num_deps ${target} _qt_${generator}_deps_num)
endif()
if(NOT num_deps)
set(num_deps 0)
endif()
set(deps_target ${target}_${generator}_deps_${num_deps})
math(EXPR num_deps "${num_deps} + 1")
set(generator_file $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${generator}>)
unset(proto_includes_string)
if(proto_includes)
list(JOIN proto_includes "\\$<SEMICOLON>-I" proto_includes_string)
set(proto_includes_string "-I${proto_includes_string}")
endif()
list(JOIN arg_PROTO_FILES "\\$<SEMICOLON>" proto_files_string)
list(JOIN generation_options "\\\\$<SEMICOLON>" generation_options_string)
string(JOIN "\\$<SEMICOLON>" protoc_arguments
"--plugin=protoc-gen-${generator}=${generator_file}"
"--${generator}_out=${output_directory}"
"--${generator}_opt=${generation_options_string}"
"${proto_files_string}"
"${proto_includes_string}"
)
add_custom_command(OUTPUT ${generated_files}
COMMAND ${CMAKE_COMMAND}
-DPROTOC_EXECUTABLE=$<TARGET_FILE:WrapProtoc::WrapProtoc>
-DPROTOC_ARGS=${protoc_arguments}
-DWORKING_DIRECTORY=${output_directory}
-DGENERATOR_NAME=${generator}
-P
${__qt_protobuf_macros_module_base_dir}/QtProtocCommandWrapper.cmake
WORKING_DIRECTORY ${output_directory}
DEPENDS
${QT_CMAKE_EXPORT_NAMESPACE}::${generator}
${proto_files}
COMMENT "Generating QtProtobuf ${target} sources for ${generator}..."
COMMAND_EXPAND_LISTS
VERBATIM
)
add_custom_target(${deps_target} DEPENDS ${generated_files})
set_property(TARGET ${target} APPEND PROPERTY
AUTOGEN_TARGET_DEPENDS "${deps_target}")
set_property(TARGET ${target} PROPERTY _qt_${generator}_deps_num "${num_deps}")
set_source_files_properties(${generated_files} PROPERTIES
GENERATED TRUE
)
target_include_directories(${target} PUBLIC "$<BUILD_INTERFACE:${output_directory}>")
endfunction()
# The function looks for the enum and message definitions inside provided PROTO_FILES and returns
# list of the absolute .proto file paths, protobuf include paths and files that are expected to be
# generated by qtprotobufgen.
# Optional arguments:
# GENERATE_PACKAGE_SUBFOLDERS - generated files will be located in package-base subdirectories.
#
# Multi-value arguments:
# PROTO_FILES - input list of the proto files. May contain either absolute or relative paths.
function(_qt_internal_protobuf_preparse_proto_files
out_proto_files out_proto_includes out_generated_files base_dir)
cmake_parse_arguments(arg "GENERATE_PACKAGE_SUBFOLDERS" "" "PROTO_FILES" ${ARGN})
unset(proto_files)
unset(proto_includes)
unset(output_files)
foreach(f IN LISTS arg_PROTO_FILES)
if(NOT IS_ABSOLUTE "${f}")
set(f "${base_dir}/${f}")
get_filename_component(f "${f}" ABSOLUTE)
endif()
get_filename_component(f "${f}" REALPATH)
list(APPEND proto_files "${f}")
_qt_internal_preparse_proto_file_common(result proto_package "${f}" "message;enum")
if(NOT result)
message(STATUS "No messages or enums found in ${f}. Skipping.")
return()
endif()
get_filename_component(proto_file_base_dir "${f}" DIRECTORY)
list(PREPEND proto_includes "${proto_file_base_dir}")
string(REPLACE "." "/" package_full_path "${proto_package}")
set(folder_path "")
if(arg_GENERATE_PACKAGE_SUBFOLDERS)
set(folder_path "${package_full_path}/")
endif()
get_filename_component(basename "${f}" NAME_WLE)
list(APPEND output_files
"${folder_path}${basename}.qpb.h"
"${folder_path}${basename}.qpb.cpp"
"${folder_path}${basename}_protobuftyperegistrations.cpp"
)
endforeach()
list(REMOVE_DUPLICATES proto_files)
list(REMOVE_DUPLICATES proto_includes)
list(REMOVE_DUPLICATES output_files)
set(${out_proto_files} "${proto_files}" PARENT_SCOPE)
set(${out_proto_includes} "${proto_includes}" PARENT_SCOPE)
set(${out_generated_files} "${output_files}" PARENT_SCOPE)
endfunction()
# TODO Qt6:
# - Collect PROTO_INCLUDES from the LINK_LIBRARIES property of TARGET
# - Collect proto files from the source files of the ${TARGET}
@ -10,107 +193,98 @@ set(__qt_protobuf_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}" CACHE INTER
# This function is currently in Technical Preview
# Its signature and behavior might change.
function(qt6_add_protobuf target)
set(options COPY_COMMENTS GENERATE_PACKAGE_SUBFOLDERS)
set(oneValueArgs
OUTPUT_DIRECTORY
EXTRA_NAMESPACE
PROTO_FILES_BASE_DIR
OUTPUT_HEADERS
OUTPUT_TARGETS
_qt_internal_get_protoc_common_options(protoc_option_opt protoc_single_opt protoc_multi_opt)
_qt_internal_get_protoc_generate_arguments(protoc_option_arg protoc_single_arg protoc_multi_arg)
set(option_args
${protoc_option_opt}
${protoc_option_arg}
)
set(multiValueArgs PROTO_FILES PROTO_INCLUDES)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
unset(proto_files)
foreach(proto_file IN LISTS arg_PROTO_FILES)
if(NOT IS_ABSOLUTE "${proto_file}")
if(arg_PROTO_FILES_BASE_DIR)
set(proto_file "${arg_PROTO_FILES_BASE_DIR}/${proto_file}")
endif()
get_filename_component(proto_file "${proto_file}" ABSOLUTE)
endif()
get_filename_component(proto_file "${proto_file}" REALPATH)
list(APPEND proto_files "${proto_file}")
endforeach()
list(REMOVE_DUPLICATES proto_files)
set(single_args
${protoc_single_opt}
${protoc_single_arg}
)
if(DEFINED arg_OUTPUT_TARGETS)
set(${arg_OUTPUT_TARGETS} "")
set(multi_args
${protoc_multi_opt}
${protoc_multi_arg}
)
cmake_parse_arguments(arg "${option_args}" "${single_args}" "${multi_args}" ${ARGN})
_qt_internal_get_protoc_options(generation_options arg
protoc_option_opt protoc_single_opt protoc_multi_opt)
if(arg_PROTO_FILES_BASE_DIR)
set(base_dir "${arg_PROTO_FILES_BASE_DIR}")
else()
set(base_dir "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
if(DEFINED arg_OUTPUT_HEADERS)
set(${arg_OUTPUT_HEADERS} "")
endif()
if("${proto_files}" STREQUAL "")
message(FATAL_ERROR "PROTO_FILES list is empty.")
endif()
string(TOUPPER "${target}" target_upper)
set(generation_options "")
set(extra_pre_parse_options "")
if(arg_COPY_COMMENTS)
list(APPEND generation_options "COPY_COMMENTS")
endif()
unset(extra_pre_parse_options)
if(arg_GENERATE_PACKAGE_SUBFOLDERS)
list(APPEND generation_options "GENERATE_PACKAGE_SUBFOLDERS")
list(APPEND extra_pre_parse_options "GENERATE_PACKAGE_SUBFOLDERS")
endif()
if(arg_EXTRA_NAMESPACE)
list(APPEND generation_options "EXTRA_NAMESPACE=${arg_EXTRA_NAMESPACE}")
_qt_internal_protobuf_preparse_proto_files(proto_files proto_includes generated_files
"${base_dir}"
${extra_pre_parse_options}
PROTO_FILES
${arg_PROTO_FILES}
)
if(arg_PROTO_INCLUDES)
list(APPEND proto_includes ${arg_PROTO_INCLUDES})
endif()
set(is_shared FALSE)
set(is_static FALSE)
set(is_executable FALSE)
if(TARGET ${target})
get_target_property(target_type ${target} TYPE)
elseif(BUILD_SHARED_LIBS)
set(target_type "SHARED_LIBRARY")
if(target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY")
set(is_shared TRUE)
elseif(target_type STREQUAL "STATIC_LIBRARY")
set(is_static TRUE)
elseif(target_type STREQUAL "EXECUTABLE")
set(is_executable TRUE)
else()
message(FATAL_ERROR "Unsupported target type '${target_type}'.")
endif()
else()
set(target_type "STATIC_LIBRARY")
endif()
# Add EXPORT_MACRO if the target is, or we will create, a shared library
if (target_type STREQUAL SHARED_LIBRARY)
list(APPEND generation_options "EXPORT_MACRO=${target_upper}")
if(BUILD_SHARED_LIBS)
set(target_type "SHARED_LIBRARY")
set(is_shared TRUE)
else()
set(target_type "STATIC_LIBRARY")
set(is_static TRUE)
endif()
_qt_internal_add_library(${target})
if(DEFINED arg_OUTPUT_TARGETS)
list(APPEND ${arg_OUTPUT_TARGETS} "${target}")
endif()
endif()
set(proto_includes "")
foreach(proto_include IN LISTS arg_PROTO_INCLUDES)
get_filename_component(proto_include "${proto_include}" REALPATH)
list(APPEND proto_includes "${proto_include}")
endforeach()
unset(generated_files)
foreach(proto_file IN LISTS proto_files)
get_filename_component(proto_file_base_dir "${proto_file}" DIRECTORY)
list(PREPEND proto_includes "-I${proto_file_base_dir}")
_qt_internal_preparse_proto_file(preparsed_files "${proto_file}" ${extra_pre_parse_options})
list(APPEND generated_files ${preparsed_files})
endforeach()
if(NOT generated_files)
message(FATAL_ERROR
"Unable to get the list of generated sources for target '${target}'")
if(is_static OR is_shared)
# Add EXPORT_MACRO if the target is, or we will create, a shared library
string(TOUPPER "${target}" target_upper)
if (is_shared)
list(APPEND generation_options "EXPORT_MACRO=${target_upper}")
endif()
# Define this so we can conditionally set the export macro
target_compile_definitions(${target}
PRIVATE "QT_BUILD_${target_upper}_LIB")
endif()
list(REMOVE_DUPLICATES generated_files)
if(NOT DEFINED arg_OUTPUT_DIRECTORY OR "${arg_OUTPUT_DIRECTORY}" STREQUAL "")
set(out_dir ${CMAKE_CURRENT_BINARY_DIR})
else()
set(out_dir ${arg_OUTPUT_DIRECTORY})
set(output_directory "${CMAKE_CURRENT_BINARY_DIR}")
if(DEFINED arg_OUTPUT_DIRECTORY)
set(output_directory "${arg_OUTPUT_DIRECTORY}")
endif()
get_filename_component(out_dir "${out_dir}" REALPATH)
list(TRANSFORM generated_files PREPEND "${output_directory}/")
file(MAKE_DIRECTORY ${out_dir})
list(TRANSFORM generated_files PREPEND "${out_dir}/")
set_source_files_properties(${generated_files} PROPERTIES
GENERATED TRUE
_qt_internal_protoc_generate(${target} qtprotobufgen "${output_directory}"
PROTO_FILES ${proto_files}
PROTO_INCLUDES ${proto_includes}
GENERATED_FILES ${generated_files}
)
# Filter generated headers
@ -128,80 +302,26 @@ function(qt6_add_protobuf target)
endif()
endforeach()
unset(num_deps)
if(TARGET ${target})
get_target_property(num_deps ${target} _qt_protobufgen_deps_num)
target_sources(${target} PRIVATE ${generated_headers} ${generated_sources})
if(is_static OR is_shared)
set_target_properties(${target}
PROPERTIES
PUBLIC_HEADER "${generated_headers}"
AUTOMOC ON
)
endif()
if(NOT num_deps)
set(num_deps 0)
endif()
set(deps_target ${target}_protobufgen_deps_${num_deps})
math(EXPR num_deps "${num_deps} + 1")
set(qtprotobufgen_file $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qtprotobufgen>)
list(REMOVE_DUPLICATES proto_includes)
list(JOIN proto_files "\\$<SEMICOLON>" proto_files_string)
list(JOIN proto_includes "\\$<SEMICOLON>" proto_includes_string)
list(JOIN generation_options "\\\\$<SEMICOLON>" generation_options_string)
string(JOIN "\\$<SEMICOLON>" protoc_arguments
"--plugin=protoc-gen-qtprotobufgen=${qtprotobufgen_file}"
"--qtprotobufgen_out=${out_dir}"
"--qtprotobufgen_opt=${generation_options_string}"
"${proto_files_string}"
"${proto_includes_string}"
)
add_custom_command(OUTPUT ${generated_files}
COMMAND ${CMAKE_COMMAND}
-DPROTOC_EXECUTABLE=$<TARGET_FILE:WrapProtoc::WrapProtoc>
-DPROTOC_ARGS=${protoc_arguments}
-DWORKING_DIRECTORY=${out_dir}
-P
${__qt_protobuf_macros_module_base_dir}/QtProtocCommandWrapper.cmake
WORKING_DIRECTORY ${out_dir}
DEPENDS
${QT_CMAKE_EXPORT_NAMESPACE}::qtprotobufgen
${proto_files}
COMMENT "Generating QtProtobuf ${target} sources..."
COMMAND_EXPAND_LISTS
VERBATIM
)
add_custom_target(${deps_target} DEPENDS ${generated_files})
if(TARGET ${target})
target_sources(${target} PRIVATE ${generated_headers} ${generated_sources})
else()
if(DEFINED arg_OUTPUT_TARGETS)
list(APPEND arg_OUTPUT_TARGETS "${target}")
endif()
_qt_internal_add_library(${target} ${generated_headers} ${generated_sources})
endif()
set_property(TARGET ${target} APPEND PROPERTY
AUTOGEN_TARGET_DEPENDS "${deps_target}")
set_property(TARGET ${target} PROPERTY _qt_protobufgen_deps_num "${num_deps}")
set_target_properties(${target}
PROPERTIES
PUBLIC_HEADER "${generated_headers}"
AUTOMOC ON
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${target}
PRIVATE "/Zc:__cplusplus" "/permissive-" "/bigobj")
endif()
if(NOT target_type STREQUAL "EXECUTABLE")
# Define this so we can conditionally set the export macro
target_compile_definitions(${target}
PRIVATE "QT_BUILD_${target_upper}_LIB")
endif()
target_link_libraries(${target} PRIVATE
${QT_CMAKE_EXPORT_NAMESPACE}::Protobuf
)
if(target_type STREQUAL "STATIC_LIBRARY" OR (WIN32 AND NOT target_type STREQUAL "EXECUTABLE"))
if(is_static OR (WIN32 AND NOT is_executable))
if(TARGET ${target}_protobuf_registration)
target_sources(${target}_protobuf_registration PRIVATE ${generated_typeregistrations})
else()
@ -232,8 +352,6 @@ function(qt6_add_protobuf target)
target_sources(${target} PRIVATE ${generated_typeregistrations})
endif()
target_include_directories(${target} PUBLIC "$<BUILD_INTERFACE:${out_dir}>")
if(DEFINED arg_OUTPUT_HEADERS)
set(${arg_OUTPUT_HEADERS} "${generated_headers}" PARENT_SCOPE)
endif()
@ -254,9 +372,10 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
function(_qt_internal_preparse_proto_file out_generated_files proto_file)
cmake_parse_arguments(arg "GENERATE_PACKAGE_SUBFOLDERS" "" "" ${ARGN})
# The common parsing function looking for the 'lookup_keys' definitions inside the 'proto_file'.
# The function sets the 'out_result' variable to true if one of 'lookup_keys' is found. Also the
# function writes to the 'out_package' variable the package name that the .proto file belongs to.
function(_qt_internal_preparse_proto_file_common out_result out_package proto_file lookup_keys)
if(NOT proto_file OR NOT EXISTS "${proto_file}")
message(FATAL_ERROR "Unable to scan '${proto_file}': file doesn't exist.")
endif()
@ -275,19 +394,14 @@ function(_qt_internal_preparse_proto_file out_generated_files proto_file)
set(unclosed_braces 0)
set(in_message_scope FALSE)
set(found_key FALSE)
list(JOIN lookup_keys "|" lookup_keys_regex)
foreach(item IN LISTS file_content)
if(item MATCHES "^[\t ]*package[\t ]+([a-zA-Z0-9_.-]+)")
set(proto_package "${CMAKE_MATCH_1}")
elseif(item MATCHES "^[\t ]*message${proto_key_common_regex}")
# Skip adding nested messages to the list.
if(unclosed_braces EQUAL 0)
list(APPEND proto_messages "${CMAKE_MATCH_1}")
set(in_message_scope TRUE)
endif()
elseif(item MATCHES "^[\t ]*service${proto_key_common_regex}")
list(APPEND proto_services "${CMAKE_MATCH_1}")
elseif(item MATCHES "^[\t ]*enum${proto_key_common_regex}")
list(APPEND proto_enums "${CMAKE_MATCH_1}")
elseif(item MATCHES "^[\t ]*(${lookup_keys_regex})${proto_key_common_regex}")
set(found_key TRUE)
break()
endif()
if(in_message_scope)
if(item MATCHES "[^/]*\\{")
@ -302,31 +416,6 @@ function(_qt_internal_preparse_proto_file out_generated_files proto_file)
endif()
endforeach()
unset(output_files)
string(REPLACE "." "/" package_full_path "${proto_package}")
get_filename_component(basename "${proto_file}" NAME_WLE)
set(folder_path "")
if(arg_GENERATE_PACKAGE_SUBFOLDERS)
set(folder_path "${package_full_path}/")
endif()
if(proto_messages OR proto_enums)
list(APPEND output_files
"${folder_path}${basename}.qpb.h"
"${folder_path}${basename}.qpb.cpp"
"${folder_path}${basename}_protobuftyperegistrations.cpp"
)
endif()
if(proto_services)
if(QT_FEATURE_native_grpc)
list(APPEND output_files
"${folder_path}${basename}_service.grpc.qpb.h"
)
endif()
list(APPEND output_files
"${folder_path}${basename}_client.grpc.qpb.h"
"${folder_path}${basename}_client.grpc.qpb.cpp"
)
endif()
set(${out_generated_files} "${output_files}" PARENT_SCOPE)
set(${out_package} "${proto_package}" PARENT_SCOPE)
set(${out_result} "${found_key}" PARENT_SCOPE)
endfunction()

View File

@ -2,7 +2,12 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
set(ENV{QT_PROTOBUF_OPTIONS} "${QT_PROTOBUF_OPTIONS}")
if(GENERATOR_NAME EQUAL "qtgrpc")
set(ENV{QT_GRPC_OPTIONS} "${QT_GRPC_OPTIONS}")
elseif(GENERATOR_NAME EQUAL "qtprotobuf")
set(ENV{QT_PROTOBUF_OPTIONS} "${QT_PROTOBUF_OPTIONS}")
endif()
execute_process(COMMAND
${PROTOC_EXECUTABLE}

View File

@ -3,9 +3,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "enumdeclarationprinter.h"
#include "utils.h"
#include "generatorcommon.h"
using namespace ::QtProtobuf::generator;
using namespace ::QtProtobuf;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
@ -21,14 +23,14 @@ EnumDeclarationPrinter::~EnumDeclarationPrinter() = default;
void EnumDeclarationPrinter::startEnum()
{
printEnumClass();
m_printer->Print(m_typeMap, Templates::EnumRegistrationDeclaration());
m_printer->Print(m_typeMap, CommonTemplates::EnumRegistrationDeclaration());
}
void EnumDeclarationPrinter::printEnum()
{
auto typeMap = common::produceEnumTypeMap(m_descriptor, nullptr);
m_printer->Print(typeMap, Templates::EnumDefinitionTemplate());
m_printer->Print(typeMap, CommonTemplates::EnumDefinitionTemplate());
Indent();
int numValues = m_descriptor->value_count();
@ -36,15 +38,15 @@ void EnumDeclarationPrinter::printEnum()
const EnumValueDescriptor *valueDescr = m_descriptor->value(j);
m_printer->Print({ { "enumvalue", utils::capitalizeAsciiName(valueDescr->name()) },
{ "value", std::to_string(valueDescr->number()) } },
Templates::EnumFieldTemplate());
CommonTemplates::EnumFieldTemplate());
}
Outdent();
m_printer->Print(Templates::SemicolonBlockEnclosureTemplate());
m_printer->Print(typeMap, Templates::QEnumNSTemplate());
m_printer->Print(typeMap, Templates::UsingRepeatedEnumTemplate());
m_printer->Print(CommonTemplates::SemicolonBlockEnclosureTemplate());
m_printer->Print(typeMap, CommonTemplates::QEnumNSTemplate());
m_printer->Print(typeMap, CommonTemplates::UsingRepeatedEnumTemplate());
}
void EnumDeclarationPrinter::printEnumClass()
{
m_printer->Print(m_typeMap, Templates::EnumDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::EnumDeclarationTemplate());
}

View File

@ -7,8 +7,9 @@
#include "descriptorprinterbase.h"
namespace QtProtobuf::generator {
class EnumDeclarationPrinter final : public DescriptorPrinterBase<google::protobuf::EnumDescriptor>
namespace QtProtobuf {
class EnumDeclarationPrinter final
: public qtprotoccommon::DescriptorPrinterBase<google::protobuf::EnumDescriptor>
{
public:
explicit EnumDeclarationPrinter(
@ -30,6 +31,6 @@ private:
void printEnumClass();
};
} // namespace QtProtobuf::generator
} // namespace QtProtobuf
#endif // ENUMDECLARATIONPRINTER_H

View File

@ -6,7 +6,8 @@
#include "options.h"
using namespace ::QtProtobuf::generator;
using namespace ::QtProtobuf;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
@ -21,14 +22,14 @@ EnumDefinitionPrinter::~EnumDefinitionPrinter() = default;
void EnumDefinitionPrinter::printRegisterBody()
{
m_printer->Print(m_typeMap, Templates::RegistrarEnumTemplate());
m_printer->Print(m_typeMap, Templates::MetaTypeRegistrationGlobalEnumDefinition());
m_printer->Print(m_typeMap, CommonTemplates::RegistrarEnumTemplate());
m_printer->Print(m_typeMap, CommonTemplates::MetaTypeRegistrationGlobalEnumDefinition());
Indent();
if (Options::instance().hasQml())
m_printer->Print(m_typeMap, Templates::QmlRegisterTypeEnumTemplate());
m_printer->Print(m_typeMap, CommonTemplates::QmlRegisterTypeEnumTemplate());
m_printer->Print(m_typeMap, Templates::MetaTypeRegistrationGlobalEnumTemplate());
m_printer->Print(m_typeMap, Templates::RegisterEnumSerializersTemplate());
m_printer->Print(m_typeMap, CommonTemplates::MetaTypeRegistrationGlobalEnumTemplate());
m_printer->Print(m_typeMap, CommonTemplates::RegisterEnumSerializersTemplate());
Outdent();
m_printer->Print(Templates::SimpleBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SimpleBlockEnclosureTemplate());
}

View File

@ -7,9 +7,9 @@
#include "descriptorprinterbase.h"
namespace QtProtobuf::generator {
class EnumDefinitionPrinter final : public DescriptorPrinterBase<google::protobuf::EnumDescriptor>
namespace QtProtobuf {
class EnumDefinitionPrinter final
: public qtprotoccommon::DescriptorPrinterBase<google::protobuf::EnumDescriptor>
{
public:
explicit EnumDefinitionPrinter(const google::protobuf::EnumDescriptor *descriptor,
@ -21,6 +21,6 @@ public:
void printRegisterBody();
};
} // namespace QtProtobuf::generator
} // namespace QtProtobuf
#endif // ENUMDEFINITIONPRINTER_H

View File

@ -1,51 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "generatorbase.h"
#include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include "utils.h"
#include "templates.h"
#include "options.h"
#include "generatorcommon.h"
#include <string>
#include <vector>
#include <cassert>
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
using namespace ::google::protobuf::compiler;
using namespace ::QtProtobuf::generator;
bool GeneratorBase::GenerateAll(const std::vector<const FileDescriptor *> &files,
const std::string &parameter, GeneratorContext *generatorContext,
std::string *error) const
{
Options::setFromString(parameter);
return CodeGenerator::GenerateAll(files, parameter, generatorContext, error);
}
std::string GeneratorBase::generateBaseName(const FileDescriptor *file, const std::string &name)
{
std::string outFileBasename;
if (Options::instance().isFolder()) {
outFileBasename = file->package();
outFileBasename = utils::replace(outFileBasename, ".", "/");
outFileBasename += '/';
}
outFileBasename += name;
return outFileBasename;
}
void GeneratorBase::printDisclaimer(Printer *printer)
{
printer->Print(Templates::DisclaimerTemplate());
}

View File

@ -4,18 +4,18 @@
#include <google/protobuf/compiler/plugin.h>
#include "singlefilegenerator.h"
#include "qprotobufgenerator.h"
#include "options.h"
#include "utils.h"
using namespace ::QtProtobuf::generator;
using namespace ::QtProtobuf;
int main(int argc, char *argv[])
{
char *optionsPtr = getenv("QT_PROTOBUF_OPTIONS");
if (optionsPtr != nullptr) {
QT_PROTOBUF_DEBUG("QT_PROTOBUF_OPTIONS: " << optionsPtr);
Options::setFromString(optionsPtr);
qtprotoccommon::Options::setFromString(optionsPtr);
}
SingleFileGenerator generator;
QProtobufGenerator generator;
return ::google::protobuf::compiler::PluginMain(argc, argv, &generator);
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2020 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
@ -12,14 +12,16 @@
#include <cassert>
using namespace ::QtProtobuf::generator;
using namespace ::QtProtobuf;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
using namespace ::google::protobuf::compiler;
MessageDeclarationPrinter::MessageDeclarationPrinter(const Descriptor *message,
std::shared_ptr<Printer> printer)
: DescriptorPrinterBase<Descriptor>(message, std::move(printer),
: DescriptorPrinterBase<Descriptor>(message,
std::move(printer),
common::produceMessageTypeMap(message, nullptr))
{
}
@ -30,16 +32,16 @@ void MessageDeclarationPrinter::printClassForwardDeclarationPrivate()
{
if (common::hasNestedMessages(m_descriptor)) {
auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
m_printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceTemplate());
common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer);
nesterPrinter.printClassForwardDeclarationPrivate();
});
m_printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceClosingTemplate());
}
m_printer->Print(m_typeMap, Templates::ClassMessageForwardDeclarationTemplate());
m_printer->Print(m_typeMap, Templates::UsingMessageTemplate());
m_printer->Print(m_typeMap, CommonTemplates::ClassMessageForwardDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::UsingMessageTemplate());
}
void MessageDeclarationPrinter::printClassForwardDeclaration()
@ -56,12 +58,12 @@ void MessageDeclarationPrinter::printClassDeclarationPrivate()
{
if (common::hasNestedMessages(m_descriptor)) {
auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
m_printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceTemplate());
common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer);
nesterPrinter.printClassDeclarationPrivate();
});
m_printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceClosingTemplate());
}
printComments(m_descriptor);
printClassDeclarationBegin();
@ -72,30 +74,30 @@ void MessageDeclarationPrinter::printClassDeclarationPrivate()
void MessageDeclarationPrinter::printCopyFunctionality()
{
assert(m_descriptor != nullptr);
m_printer->Print(m_typeMap, Templates::CopyConstructorDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::CopyConstructorDeclarationTemplate());
m_printer->Print(m_typeMap, Templates::AssignmentOperatorDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::AssignmentOperatorDeclarationTemplate());
}
void MessageDeclarationPrinter::printMoveSemantic()
{
assert(m_descriptor != nullptr);
m_printer->Print(m_typeMap, Templates::MoveConstructorDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::MoveConstructorDeclarationTemplate());
m_printer->Print(m_typeMap, Templates::MoveAssignmentOperatorDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::MoveAssignmentOperatorDeclarationTemplate());
}
void MessageDeclarationPrinter::printComparisonOperators()
{
assert(m_descriptor != nullptr);
m_printer->Print(m_typeMap, Templates::EqualOperatorDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::EqualOperatorDeclarationTemplate());
m_printer->Print(m_typeMap, Templates::NotEqualOperatorDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::NotEqualOperatorDeclarationTemplate());
}
void MessageDeclarationPrinter::printConstructors()
{
m_printer->Print(m_typeMap, Templates::ConstructorMessageDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::ConstructorMessageDeclarationTemplate());
if (m_descriptor->full_name() == "google.protobuf.Timestamp") {
m_printer->Print("Timestamp(const QDateTime &datetime);\n"
@ -112,8 +114,8 @@ void MessageDeclarationPrinter::printMaps()
if (field->is_map()) {
const Descriptor *type = field->message_type();
const char *mapTemplate = type->field(1)->type() == FieldDescriptor::TYPE_MESSAGE
? Templates::UsingMapMessageTemplate()
: Templates::UsingMapTemplate();
? CommonTemplates::UsingMapMessageTemplate()
: CommonTemplates::UsingMapTemplate();
m_printer->Print(common::producePropertyMap(field, m_descriptor), mapTemplate);
}
}
@ -125,22 +127,22 @@ void MessageDeclarationPrinter::printNested()
Indent();
common::iterateNestedMessages(m_descriptor, [&](const Descriptor *nestedMessage) {
m_printer->Print(common::produceMessageTypeMap(nestedMessage, m_descriptor),
Templates::UsingNestedMessageTemplate());
CommonTemplates::UsingNestedMessageTemplate());
});
Outdent();
}
void MessageDeclarationPrinter::printClassDeclarationBegin()
{
m_printer->Print(m_typeMap, Templates::ClassMessageBeginDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::ClassMessageBeginDeclarationTemplate());
}
void MessageDeclarationPrinter::printMetaTypesDeclaration()
{
m_printer->Print(m_typeMap, Templates::DeclareMetaTypeTemplate());
m_printer->Print(m_typeMap, CommonTemplates::DeclareMetaTypeTemplate());
if (Options::instance().hasQml()) {
m_printer->Print(m_typeMap, Templates::DeclareMetaTypeQmlListTemplate());
m_printer->Print(m_typeMap, CommonTemplates::DeclareMetaTypeQmlListTemplate());
}
common::iterateNestedMessages(m_descriptor, [&](const Descriptor *nestedMessage) {
@ -158,18 +160,18 @@ void MessageDeclarationPrinter::printProperties()
const int numFields = m_descriptor->field_count();
for (int i = 0; i < numFields; ++i) {
const FieldDescriptor *field = m_descriptor->field(i);
const char *propertyTemplate = Templates::PropertyTemplate();
const char *propertyTemplate = CommonTemplates::PropertyTemplate();
if (common::isPureMessage(field)) {
propertyTemplate = Templates::PropertyMessageTemplate();
propertyTemplate = CommonTemplates::PropertyMessageTemplate();
} else if (common::hasQmlAlias(field)) {
propertyTemplate = Templates::PropertyNonScriptableTemplate();
propertyTemplate = CommonTemplates::PropertyNonScriptableTemplate();
} else if (field->is_repeated() && !field->is_map()) {
// Non-message list properties don't require an extra QQmlListProperty to access
// their data, so the property name should not contain the 'Data' suffix
if (field->type() == FieldDescriptor::TYPE_MESSAGE)
propertyTemplate = Templates::PropertyRepeatedMessageTemplate();
propertyTemplate = CommonTemplates::PropertyRepeatedMessageTemplate();
else
propertyTemplate = Templates::PropertyRepeatedTemplate();
propertyTemplate = CommonTemplates::PropertyRepeatedTemplate();
}
m_printer->Print(common::producePropertyMap(field, m_descriptor), propertyTemplate);
}
@ -180,10 +182,10 @@ void MessageDeclarationPrinter::printProperties()
if (field->type() == FieldDescriptor::TYPE_MESSAGE && field->is_repeated()
&& !field->is_map() && Options::instance().hasQml()) {
m_printer->Print(common::producePropertyMap(field, m_descriptor),
Templates::PropertyQmlListTemplate());
CommonTemplates::PropertyQmlListTemplate());
} else if (common::hasQmlAlias(field)) {
m_printer->Print(common::producePropertyMap(field, m_descriptor),
Templates::PropertyNonScriptableAliasTemplate());
CommonTemplates::PropertyNonScriptableAliasTemplate());
}
}
@ -197,16 +199,17 @@ void MessageDeclarationPrinter::printGetters()
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
printComments(field);
m_printer->Print("\n");
if (common::isPureMessage(field))
m_printer->Print(propertyMap, Templates::GetterMessageDeclarationTemplate());
else
m_printer->Print(propertyMap, Templates::GetterTemplate());
m_printer->Print(propertyMap,
common::isPureMessage(field) ?
CommonTemplates::GetterMessageDeclarationTemplate() :
CommonTemplates::GetterTemplate());
if (field->is_repeated()) {
m_printer->Print(propertyMap, Templates::GetterComplexTemplate());
m_printer->Print(propertyMap, CommonTemplates::GetterComplexTemplate());
if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map()
&& Options::instance().hasQml()) {
m_printer->Print(propertyMap, Templates::GetterQmlListDeclarationTemplate());
m_printer->Print(propertyMap,
CommonTemplates::GetterQmlListDeclarationTemplate());
}
}
});
@ -220,19 +223,21 @@ void MessageDeclarationPrinter::printSetters()
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
if (!field->is_map() && !field->is_repeated() && !common::isQtType(field))
if (!field->is_map() && !field->is_repeated() && !common::isQtType(field)) {
m_printer->Print(propertyMap,
Templates::SetterMessageDeclarationTemplate());
else
CommonTemplates::SetterMessageDeclarationTemplate());
} else {
m_printer->Print(propertyMap,
Templates::SetterComplexDeclarationTemplate());
CommonTemplates::SetterComplexDeclarationTemplate());
}
break;
case FieldDescriptor::FieldDescriptor::TYPE_STRING:
case FieldDescriptor::FieldDescriptor::TYPE_BYTES:
m_printer->Print(propertyMap, Templates::SetterComplexDeclarationTemplate());
m_printer->Print(propertyMap,
CommonTemplates::SetterComplexDeclarationTemplate());
break;
default:
m_printer->Print(propertyMap, Templates::SetterTemplate());
m_printer->Print(propertyMap, CommonTemplates::SetterTemplate());
break;
}
});
@ -244,9 +249,10 @@ void MessageDeclarationPrinter::printPrivateGetters()
Indent();
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field))
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap,
Templates::PrivateGetterMessageDeclarationTemplate());
CommonTemplates::PrivateGetterMessageDeclarationTemplate());
}
});
Outdent();
}
@ -256,9 +262,10 @@ void MessageDeclarationPrinter::printPrivateSetters()
Indent();
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field))
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap,
Templates::PrivateSetterMessageDeclarationTemplate());
CommonTemplates::PrivateSetterMessageDeclarationTemplate());
}
});
Outdent();
}
@ -269,8 +276,8 @@ void MessageDeclarationPrinter::printPrivateMethods()
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::hasQmlAlias(field)) {
m_printer->Print(propertyMap, Templates::GetterNonScriptableTemplate());
m_printer->Print(propertyMap, Templates::SetterNonScriptableTemplate());
m_printer->Print(propertyMap, CommonTemplates::GetterNonScriptableTemplate());
m_printer->Print(propertyMap, CommonTemplates::SetterNonScriptableTemplate());
}
});
Outdent();
@ -289,24 +296,24 @@ void MessageDeclarationPrinter::printQEnums()
for (int i = 0; i < m_descriptor->enum_type_count(); ++i) {
const auto *enumDescr = m_descriptor->enum_type(i);
auto typeMap = common::produceEnumTypeMap(enumDescr, m_descriptor);
m_printer->Print(typeMap, Templates::EnumDefinitionTemplate());
m_printer->Print(typeMap, CommonTemplates::EnumDefinitionTemplate());
Indent();
for (int j = 0; j < enumDescr->value_count(); ++j) {
const auto *valueDescr = enumDescr->value(j);
m_printer->Print({ { "enumvalue", utils::capitalizeAsciiName(valueDescr->name()) },
{ "value", std::to_string(valueDescr->number()) } },
Templates::EnumFieldTemplate());
CommonTemplates::EnumFieldTemplate());
}
Outdent();
m_printer->Print(Templates::SemicolonBlockEnclosureTemplate());
m_printer->Print(typeMap, Templates::QEnumTemplate());
m_printer->Print(CommonTemplates::SemicolonBlockEnclosureTemplate());
m_printer->Print(typeMap, CommonTemplates::QEnumTemplate());
}
for (int i = 0; i < m_descriptor->enum_type_count(); ++i) {
const auto *enumDescr = m_descriptor->enum_type(i);
auto typeMap = common::produceEnumTypeMap(enumDescr, m_descriptor);
m_printer->Print(typeMap, Templates::UsingRepeatedEnumTemplate());
m_printer->Print(typeMap, CommonTemplates::UsingRepeatedEnumTemplate());
}
Outdent();
}
@ -334,7 +341,7 @@ void MessageDeclarationPrinter::printClassBody()
printSetters();
Indent();
m_printer->Print(m_typeMap, Templates::MetaTypeRegistrationDeclaration());
m_printer->Print(m_typeMap, CommonTemplates::MetaTypeRegistrationDeclaration());
Outdent();
printPrivateBlock();
@ -351,11 +358,11 @@ void MessageDeclarationPrinter::printClassMembers()
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap, Templates::MemberMessageTemplate());
m_printer->Print(propertyMap, CommonTemplates::MemberMessageTemplate());
} else if (field->is_repeated() && !field->is_map()) {
m_printer->Print(propertyMap, Templates::MemberRepeatedTemplate());
m_printer->Print(propertyMap, CommonTemplates::MemberRepeatedTemplate());
} else {
m_printer->Print(propertyMap, Templates::MemberTemplate());
m_printer->Print(propertyMap, CommonTemplates::MemberTemplate());
}
});
Outdent();
@ -363,22 +370,24 @@ void MessageDeclarationPrinter::printClassMembers()
void MessageDeclarationPrinter::printDestructor()
{
m_printer->Print(m_typeMap, Templates::DestructorMessageDeclarationTemplate());
m_printer->Print(m_typeMap, CommonTemplates::DestructorMessageDeclarationTemplate());
}
void MessageDeclarationPrinter::printFieldEnum()
{
if (m_descriptor->field_count() > 0) {
Indent();
m_printer->Print(Templates::FieldEnumTemplate());
m_printer->Print(CommonTemplates::FieldEnumTemplate());
Indent();
common::iterateMessageFields(m_descriptor,
[&](const FieldDescriptor *, const PropertyMap &propertyMap) {
m_printer->Print(propertyMap, Templates::FieldNumberTemplate());
m_printer->Print(propertyMap,
CommonTemplates::FieldNumberTemplate());
});
Outdent();
m_printer->Print(Templates::SemicolonBlockEnclosureTemplate());
m_printer->Print({ { "type", Templates::QtProtobufFieldEnum() } }, Templates::QEnumTemplate());
m_printer->Print(CommonTemplates::SemicolonBlockEnclosureTemplate());
m_printer->Print({ { "type", CommonTemplates::QtProtobufFieldEnum() } },
CommonTemplates::QEnumTemplate());
Outdent();
m_printer->Print("\n");
}

View File

@ -7,9 +7,10 @@
#include "descriptorprinterbase.h"
namespace QtProtobuf::generator {
namespace QtProtobuf {
class MessageDeclarationPrinter final : public DescriptorPrinterBase<google::protobuf::Descriptor>
class MessageDeclarationPrinter final
: public qtprotoccommon::DescriptorPrinterBase<google::protobuf::Descriptor>
{
public:
explicit MessageDeclarationPrinter(const ::google::protobuf::Descriptor *message,
@ -45,6 +46,7 @@ private:
void printClassDeclarationPrivate();
void printClassForwardDeclarationPrivate();
};
} // namespace QtProtobuf::generator
} // namespace QtProtobuf
#endif // MESSAGEDECLARATIONPRINTER_H

View File

@ -1,17 +1,19 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "messagedefinitionprinter.h"
#include "generatorcommon.h"
#include "options.h"
#include "templates.h"
#include <google/protobuf/descriptor.h>
#include "utils.h"
#include "options.h"
#include "commontemplates.h"
#include "generatorcommon.h"
#include <cassert>
using namespace ::QtProtobuf::generator;
using namespace ::QtProtobuf;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
@ -22,10 +24,10 @@ using namespace ::google::protobuf::io;
\brief Generates gRPC message class definition.
*/
MessageDefinitionPrinter::MessageDefinitionPrinter(const Descriptor *message,
std::shared_ptr<Printer> printer)
: DescriptorPrinterBase<Descriptor>(message, std::move(printer),
: DescriptorPrinterBase<Descriptor>(message,
std::move(printer),
common::produceMessageTypeMap(message, nullptr))
{
}
@ -35,13 +37,13 @@ MessageDefinitionPrinter::~MessageDefinitionPrinter() = default;
void MessageDefinitionPrinter::printClassDefinitionPrivate()
{
if (common::hasNestedMessages(m_descriptor)) {
auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
m_printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
auto scopeNamespaces = qtprotoccommon::common::getNestedScopeNamespace(m_typeMap["classname"]);
m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceTemplate());
common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
MessageDefinitionPrinter nestedPrinter(nestedMessage, m_printer);
nestedPrinter.printClassDefinitionPrivate();
});
m_printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceClosingTemplate());
}
printDestructor();
@ -63,11 +65,11 @@ void MessageDefinitionPrinter::printRegisterBody()
{
std::vector<std::string> registredMetaTypes;
m_printer->Print(m_typeMap, Templates::MetaTypeRegistrationMessageDefinition());
m_printer->Print(m_typeMap, CommonTemplates::MetaTypeRegistrationMessageDefinition());
Indent();
if (Options::instance().hasQml()) {
m_printer->Print(m_typeMap, Templates::MetaTypeRegistrationQmlListTemplate());
m_printer->Print(m_typeMap, Templates::QmlRegisterTypeTemplate());
m_printer->Print(m_typeMap, CommonTemplates::MetaTypeRegistrationQmlListTemplate());
m_printer->Print(m_typeMap, CommonTemplates::QmlRegisterTypeTemplate());
}
common::iterateMessageFields(
@ -83,14 +85,15 @@ void MessageDefinitionPrinter::printRegisterBody()
if (field->type() == FieldDescriptor::TYPE_ENUM
&& common::isLocalEnum(field->enum_type(), m_descriptor)) {
m_printer->Print(propertyMap,
Templates::MetaTypeRegistrationLocalEnumTemplate());
CommonTemplates::MetaTypeRegistrationLocalEnumTemplate());
} else if (field->is_map()) {
m_printer->Print(propertyMap, Templates::MetaTypeRegistrationMapTemplate());
m_printer->Print(propertyMap,
CommonTemplates::MetaTypeRegistrationMapTemplate());
}
});
Outdent();
m_printer->Print(Templates::SimpleBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SimpleBlockEnclosureTemplate());
}
void MessageDefinitionPrinter::printFieldsOrdering()
@ -113,35 +116,35 @@ void MessageDefinitionPrinter::printFieldsOrdering()
std::to_string(fieldCount * (uint_dataOffset++) + NullTerminator) },
{ "property_index_offset",
std::to_string(fieldCount * (uint_dataOffset++) + NullTerminator) },
{ "field_flags_offset", std::to_string(fieldCount * (uint_dataOffset++) + NullTerminator) },
{ "field_flags_offset", std::to_string(fieldCount * (uint_dataOffset++) + NullTerminator)},
{ "uint_size", std::to_string(fieldCount * MetaFieldsCount + FakeJsonNameOffset) },
{ "char_size", std::to_string(char_dataSizeTotal) },
{ "message_full_name_size", std::to_string(metadataCharSize) },
};
assert(uint_dataOffset == MetaFieldsCount);
m_printer->Print(dataVariables, Templates::PropertyOrderingDataOpeningTemplate());
m_printer->Print(dataVariables, CommonTemplates::PropertyOrderingDataOpeningTemplate());
Indent();
// uint_data
m_printer->Print("// uint_data\n{\n");
Indent();
m_printer->Print("// JSON name offsets:\n");
printUintData(Templates::JsonNameOffsetsUintDataTemplate());
printUintData(CommonTemplates::JsonNameOffsetsUintDataTemplate());
// Include an extra offset which points to the end-of-string, so we can efficiently get the
// length of all the strings by subtracting adjacent offsets:
m_printer->Print({ { "json_name_offset", std::to_string(char_dataSizeTotal - NullTerminator) },
{ "json_name", "end-of-string-marker" } },
Templates::JsonNameOffsetsUintDataTemplate());
CommonTemplates::JsonNameOffsetsUintDataTemplate());
m_printer->Print("// Field numbers:\n");
printUintData(Templates::FieldNumbersUintDataTemplate());
printUintData(CommonTemplates::FieldNumbersUintDataTemplate());
m_printer->Print("// Property indices:\n");
printUintData(Templates::QtPropertyIndicesUintDataTemplate());
printUintData(CommonTemplates::QtPropertyIndicesUintDataTemplate());
m_printer->Print("// Field flags:\n");
printUintData(Templates::FieldFlagsUintDataTemplate());
printUintData(CommonTemplates::FieldFlagsUintDataTemplate());
Outdent();
m_printer->Print("},\n");
@ -150,9 +153,9 @@ void MessageDefinitionPrinter::printFieldsOrdering()
printCharData();
Outdent();
m_printer->Print(m_typeMap, Templates::PropertyOrderingDataClosingTemplate());
m_printer->Print(m_typeMap, CommonTemplates::PropertyOrderingDataClosingTemplate());
m_printer->Print(m_typeMap, Templates::PropertyOrderingDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::PropertyOrderingDefinitionTemplate());
}
void MessageDefinitionPrinter::printUintData(const char *templateString)
@ -214,9 +217,9 @@ size_t MessageDefinitionPrinter::charDataSize() const
void MessageDefinitionPrinter::printConstructors()
{
m_printer->Print(m_typeMap, Templates::ConstructorMessageDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::ConstructorMessageDefinitionTemplate());
printInitializationList();
m_printer->Print(Templates::EmptyBracesTemplate());
m_printer->Print(CommonTemplates::EmptyBracesTemplate());
if (m_descriptor->full_name() == "google.protobuf.Timestamp") {
m_printer->Print(
@ -270,11 +273,11 @@ void MessageDefinitionPrinter::printInitializationList()
if (common::isPureMessage(field)) {
m_printer->Print(",\n");
m_printer->Print(propertyMap, Templates::InitializerMemberMessageTemplate());
m_printer->Print(propertyMap, CommonTemplates::InitializerMemberMessageTemplate());
} else {
if (!propertyMap["initializer"].empty()) {
m_printer->Print(",\n");
m_printer->Print(propertyMap, Templates::InitializerMemberTemplate());
m_printer->Print(propertyMap, CommonTemplates::InitializerMemberTemplate());
}
}
}
@ -284,169 +287,173 @@ void MessageDefinitionPrinter::printInitializationList()
void MessageDefinitionPrinter::printCopyFunctionality()
{
assert(m_descriptor != nullptr);
m_printer->Print(m_typeMap, Templates::CopyConstructorDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::CopyConstructorDefinitionTemplate());
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(",\n");
m_printer->Print(propertyMap, Templates::InitializerMemberMessageTemplate());
}
});
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(",\n");
m_printer->Print(propertyMap,
CommonTemplates::InitializerMemberMessageTemplate());
}
});
m_printer->Print("\n{\n");
Indent();
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap, Templates::CopyMemberMessageTemplate());
} else {
m_printer->Print(propertyMap, Templates::CopyMemberTemplate());
}
});
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
m_printer->Print(propertyMap,
common::isPureMessage(field) ?
CommonTemplates::CopyMemberMessageTemplate() :
CommonTemplates::CopyMemberTemplate());
});
Outdent();
m_printer->Print(Templates::SimpleBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SimpleBlockEnclosureTemplate());
m_printer->Print(m_typeMap, Templates::AssignmentOperatorDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::AssignmentOperatorDefinitionTemplate());
Indent();
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap, Templates::AssignMemberMessageTemplate());
} else {
m_printer->Print(propertyMap, Templates::CopyMemberTemplate());
}
});
m_printer->Print(Templates::AssignmentOperatorReturnTemplate());
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
m_printer->Print(propertyMap,
common::isPureMessage(field) ?
CommonTemplates::AssignMemberMessageTemplate() :
CommonTemplates::CopyMemberTemplate());
});
m_printer->Print(CommonTemplates::AssignmentOperatorReturnTemplate());
Outdent();
m_printer->Print(Templates::SimpleBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SimpleBlockEnclosureTemplate());
}
void MessageDefinitionPrinter::printMoveSemantic()
{
assert(m_descriptor != nullptr);
m_printer->Print(m_typeMap, Templates::MoveConstructorDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::MoveConstructorDefinitionTemplate());
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(",\n");
m_printer->Print(propertyMap, Templates::InitializerMemberMessageTemplate());
}
});
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(",\n");
m_printer->Print(propertyMap,
CommonTemplates::InitializerMemberMessageTemplate());
}
});
m_printer->Print("\n{\n");
Indent();
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (field->type() == FieldDescriptor::TYPE_MESSAGE
|| field->type() == FieldDescriptor::TYPE_STRING
|| field->type() == FieldDescriptor::TYPE_BYTES || field->is_repeated()) {
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap, Templates::MoveMemberMessageTemplate());
} else {
m_printer->Print(propertyMap,
Templates::MoveConstructorMemberComplexTemplate());
}
} else {
if (field->type() != FieldDescriptor::TYPE_ENUM) {
m_printer->Print(propertyMap, Templates::MoveMemberTemplate());
} else {
m_printer->Print(propertyMap, Templates::MoveMemberEnumTemplate());
}
}
});
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (field->type() == FieldDescriptor::TYPE_MESSAGE
|| field->type() == FieldDescriptor::TYPE_STRING
|| field->type() == FieldDescriptor::TYPE_BYTES || field->is_repeated()) {
m_printer->Print(propertyMap,
common::isPureMessage(field) ?
CommonTemplates::MoveMemberMessageTemplate() :
CommonTemplates::MoveConstructorMemberComplexTemplate());
} else {
m_printer->Print(propertyMap,
(field->type() != FieldDescriptor::TYPE_ENUM) ?
CommonTemplates::MoveMemberTemplate() :
CommonTemplates::MoveMemberEnumTemplate());
}
});
Outdent();
m_printer->Print(Templates::SimpleBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SimpleBlockEnclosureTemplate());
m_printer->Print(m_typeMap, Templates::MoveAssignmentOperatorDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::MoveAssignmentOperatorDefinitionTemplate());
Indent();
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (field->type() == FieldDescriptor::TYPE_MESSAGE
|| field->type() == FieldDescriptor::TYPE_STRING
|| field->type() == FieldDescriptor::TYPE_BYTES || field->is_repeated()) {
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap, Templates::MoveAssignMemberMessageTemplate());
} else {
m_printer->Print(propertyMap, Templates::MoveAssignMemberComplexTemplate());
}
} else {
if (field->type() != FieldDescriptor::TYPE_ENUM) {
m_printer->Print(propertyMap, Templates::MoveMemberTemplate());
} else {
m_printer->Print(propertyMap, Templates::MoveMemberEnumTemplate());
}
}
});
m_printer->Print(Templates::AssignmentOperatorReturnTemplate());
m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
if (field->type() == FieldDescriptor::TYPE_MESSAGE
|| field->type() == FieldDescriptor::TYPE_STRING
|| field->type() == FieldDescriptor::TYPE_BYTES || field->is_repeated()) {
m_printer->Print(propertyMap,
common::isPureMessage(field) ?
CommonTemplates::MoveAssignMemberMessageTemplate() :
CommonTemplates::MoveAssignMemberComplexTemplate());
} else {
m_printer->Print(propertyMap,
(field->type() != FieldDescriptor::TYPE_ENUM) ?
CommonTemplates::MoveMemberTemplate() :
CommonTemplates::MoveMemberEnumTemplate());
}
});
m_printer->Print(CommonTemplates::AssignmentOperatorReturnTemplate());
Outdent();
m_printer->Print(Templates::SimpleBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SimpleBlockEnclosureTemplate());
}
void MessageDefinitionPrinter::printComparisonOperators()
{
assert(m_descriptor != nullptr);
m_printer->Print(m_typeMap, Templates::EqualOperatorDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::EqualOperatorDefinitionTemplate());
Indent();
Indent();
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
m_printer->Print("\n&& ");
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap, Templates::EqualOperatorMemberMessageTemplate());
} else if (field->type() == FieldDescriptor::TYPE_MESSAGE && field->is_repeated()) {
m_printer->Print(propertyMap, Templates::EqualOperatorMemberRepeatedTemplate());
} else {
m_printer->Print(propertyMap, Templates::EqualOperatorMemberTemplate());
}
});
m_descriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
m_printer->Print("\n&& ");
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap,
CommonTemplates::EqualOperatorMemberMessageTemplate());
} else if (field->type() == FieldDescriptor::TYPE_MESSAGE
&& field->is_repeated()) {
m_printer->Print(propertyMap,
CommonTemplates::EqualOperatorMemberRepeatedTemplate());
} else {
m_printer->Print(propertyMap,
CommonTemplates::EqualOperatorMemberTemplate());
}
});
Outdent();
Outdent();
m_printer->Print(";\n");
m_printer->Print(Templates::SimpleBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SimpleBlockEnclosureTemplate());
m_printer->Print(m_typeMap, Templates::NotEqualOperatorDefinitionTemplate());
m_printer->Print(m_typeMap, CommonTemplates::NotEqualOperatorDefinitionTemplate());
}
void MessageDefinitionPrinter::printGetters()
{
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap,
Templates::PrivateGetterMessageDefinitionTemplate());
m_printer->Print(propertyMap, Templates::GetterMessageDefinitionTemplate());
}
if (field->is_repeated()) {
if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map()
&& !common::isQtType(field) && Options::instance().hasQml()) {
m_printer->Print(propertyMap, Templates::GetterQmlListDefinitionTemplate());
}
}
});
m_descriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
if (common::isPureMessage(field)) {
m_printer->Print(propertyMap,
CommonTemplates::PrivateGetterMessageDefinitionTemplate());
m_printer->Print(propertyMap,
CommonTemplates::GetterMessageDefinitionTemplate());
}
if (field->is_repeated()) {
if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map()
&& !common::isQtType(field) && Options::instance().hasQml()) {
m_printer->Print(propertyMap,
CommonTemplates::GetterQmlListDefinitionTemplate());
}
}
});
common::iterateMessageFields(
m_descriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
if (!field->is_map() && !field->is_repeated() && !common::isQtType(field)) {
m_printer->Print(propertyMap,
Templates::PrivateSetterMessageDefinitionTemplate());
m_printer->Print(propertyMap, Templates::SetterMessageDefinitionTemplate());
} else {
m_printer->Print(propertyMap, Templates::SetterComplexDefinitionTemplate());
}
break;
case FieldDescriptor::FieldDescriptor::TYPE_STRING:
case FieldDescriptor::FieldDescriptor::TYPE_BYTES:
m_printer->Print(propertyMap, Templates::SetterComplexDefinitionTemplate());
break;
default:
break;
}
});
m_descriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
if (!field->is_map() && !field->is_repeated() && !common::isQtType(field)) {
m_printer->Print(propertyMap,
CommonTemplates::PrivateSetterMessageDefinitionTemplate());
m_printer->Print(propertyMap,
CommonTemplates::SetterMessageDefinitionTemplate());
} else {
m_printer->Print(propertyMap,
CommonTemplates::SetterComplexDefinitionTemplate());
}
break;
case FieldDescriptor::FieldDescriptor::TYPE_STRING:
case FieldDescriptor::FieldDescriptor::TYPE_BYTES:
m_printer->Print(propertyMap,
CommonTemplates::SetterComplexDefinitionTemplate());
break;
default:
break;
}
});
}
void MessageDefinitionPrinter::printDestructor()
@ -458,15 +465,14 @@ void MessageDefinitionPrinter::printClassRegistration(Printer *printer)
{
if (common::hasNestedMessages(m_descriptor)) {
auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
printer->Print(scopeNamespaces, Templates::NamespaceTemplate());
common::iterateNestedMessages(m_descriptor,
[this, &printer](const Descriptor *nestedMessage) {
MessageDefinitionPrinter nestedPrinter(nestedMessage,
m_printer);
nestedPrinter.printClassRegistration(printer);
});
printer->Print(scopeNamespaces, Templates::NamespaceClosingTemplate());
printer->Print(scopeNamespaces, CommonTemplates::NamespaceTemplate());
common::iterateNestedMessages(
m_descriptor, [this, &printer](const Descriptor *nestedMessage) {
MessageDefinitionPrinter nestedPrinter(nestedMessage, m_printer);
nestedPrinter.printClassRegistration(printer);
});
printer->Print(scopeNamespaces, CommonTemplates::NamespaceClosingTemplate());
}
printer->Print(m_typeMap, Templates::RegistrarTemplate());
printer->Print(m_typeMap, CommonTemplates::RegistrarTemplate());
}

View File

@ -7,11 +7,10 @@
#include "descriptorprinterbase.h"
#include <stddef.h>
namespace QtProtobuf {
namespace QtProtobuf::generator {
class MessageDefinitionPrinter final : public DescriptorPrinterBase<google::protobuf::Descriptor>
class MessageDefinitionPrinter final
: public qtprotoccommon::DescriptorPrinterBase<google::protobuf::Descriptor>
{
public:
explicit MessageDefinitionPrinter(const google::protobuf::Descriptor *message,
@ -40,5 +39,5 @@ private:
void printClassDefinitionPrivate();
};
} // namespace QtProtobuf::generator
} // namespace QtProtobuf
#endif // MESSAGEDEFINITIONPRINTER_H

View File

@ -0,0 +1,219 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qprotobufgenerator.h"
#include "enumdeclarationprinter.h"
#include "enumdefinitionprinter.h"
#include "messagedeclarationprinter.h"
#include "messagedefinitionprinter.h"
#include "commontemplates.h"
#include "utils.h"
#include "options.h"
#include <cassert>
#include <array>
#include <numeric>
#include <set>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.h>
using namespace ::QtProtobuf;
using namespace ::qtprotoccommon;
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
using namespace ::google::protobuf::compiler;
QProtobufGenerator::QProtobufGenerator() : GeneratorBase()
{}
QProtobufGenerator::~QProtobufGenerator() = default;
bool QProtobufGenerator::Generate(const FileDescriptor *file,
[[maybe_unused]] const std::string &parameter,
GeneratorContext *generatorContext,
std::string *error) const
{
assert(file != nullptr && generatorContext != nullptr);
if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
*error = "Invalid proto used. qtprotobufgen only supports 'proto3' syntax";
return false;
}
return GenerateMessages(file, generatorContext);
}
void QProtobufGenerator::GenerateSources(const FileDescriptor *file,
GeneratorContext *generatorContext) const
{
assert(file != nullptr && generatorContext != nullptr);
std::string filename = utils::extractFileBasename(file->name());
std::string basename = generateBaseName(file, filename);
std::unique_ptr<io::ZeroCopyOutputStream> sourceStream(
generatorContext->Open(basename + CommonTemplates::ProtoFileSuffix() + ".cpp"));
std::unique_ptr<io::ZeroCopyOutputStream> registrationStream(
generatorContext->Open(basename + "_protobuftyperegistrations.cpp"));
std::shared_ptr<Printer> sourcePrinter(new Printer(sourceStream.get(), '$'));
std::shared_ptr<Printer> registrationPrinter(new Printer(registrationStream.get(), '$'));
printDisclaimer(sourcePrinter.get());
sourcePrinter->Print({{"include", basename + CommonTemplates::ProtoFileSuffix()}},
CommonTemplates::InternalIncludeTemplate());
std::array<std::string, 2> registrationPrinterExternalIncludes {"QProtobufSerializer",
"array"};
for (const auto &include : registrationPrinterExternalIncludes) {
registrationPrinter->Print({{"include", include}},
CommonTemplates::ExternalIncludeTemplate());
}
registrationPrinter->Print({{"include", basename + CommonTemplates::ProtoFileSuffix()}},
CommonTemplates::InternalIncludeTemplate());
sourcePrinter->Print({{"include", "QProtobufSerializer"}},
CommonTemplates::ExternalIncludeTemplate());
if (Options::instance().hasQml()) {
sourcePrinter->Print({{"include", "QQmlEngine"}},
CommonTemplates::ExternalIncludeTemplate());
}
OpenFileNamespaces(file, sourcePrinter.get());
OpenFileNamespaces(file, registrationPrinter.get());
for (int i = 0; i < file->enum_type_count(); ++i) {
EnumDefinitionPrinter enumSourceDef(file->enum_type(i), sourcePrinter);
enumSourceDef.run();
}
common::iterateMessages(
file,
[&sourcePrinter, &registrationPrinter](const Descriptor *message) {
MessageDefinitionPrinter messageDef(message, sourcePrinter);
messageDef.printClassDefinition();
messageDef.printClassRegistration(registrationPrinter.get());
});
CloseFileNamespaces(file, registrationPrinter.get());
CloseFileNamespaces(file, sourcePrinter.get());
// Include the moc file:
sourcePrinter->Print({{"source_file", filename + CommonTemplates::ProtoFileSuffix()}},
"#include \"moc_$source_file$.cpp\"\n");
}
void QProtobufGenerator::GenerateHeader(const FileDescriptor *file,
GeneratorContext *generatorContext) const
{
assert(file != nullptr && generatorContext != nullptr);
std::string filename = utils::extractFileBasename(file->name());
std::string basename = generateBaseName(file, filename);
std::set<std::string> internalIncludes;
std::set<std::string> externalIncludes;
std::unique_ptr<io::ZeroCopyOutputStream> headerStream(
generatorContext->Open(basename
+ CommonTemplates::ProtoFileSuffix() + ".h"));
std::shared_ptr<Printer> headerPrinter(new Printer(headerStream.get(), '$'));
printDisclaimer(headerPrinter.get());
headerPrinter->Print({{"filename", filename}}, CommonTemplates::PreambleTemplate());
headerPrinter->Print(CommonTemplates::DefaultProtobufIncludesTemplate());
if (Options::instance().hasQml()) {
headerPrinter->Print(CommonTemplates::QmlProtobufIncludesTemplate());
}
externalIncludes.insert("QByteArray");
externalIncludes.insert("QString");
bool hasQtTypes = false;
common::iterateMessages(file, [&externalIncludes, &hasQtTypes](const Descriptor *message) {
for (int i = 0; i < message->field_count(); ++i) {
const auto *field = message->field(i);
if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map()
&& !field->is_repeated() && common::isQtType(field)) {
externalIncludes.insert(field->message_type()->name());
hasQtTypes = true;
}
}
if (message->full_name() == "google.protobuf.Timestamp") {
externalIncludes.insert("QDateTime");
}
});
if (hasQtTypes) {
externalIncludes.insert("QtProtobufQtTypes");
}
for (int i = 0; i < file->dependency_count(); ++i) {
if (file->dependency(i)->name() == "QtProtobuf/QtCore.proto"
|| file->dependency(i)->name() == "QtProtobuf/QtGui.proto") {
continue;
}
internalIncludes.insert(utils::removeFileSuffix(file->dependency(i)->name())
+ CommonTemplates::ProtoFileSuffix());
}
for (const auto &include : externalIncludes) {
headerPrinter->Print({{"include", include}}, CommonTemplates::ExternalIncludeTemplate());
}
for (const auto &include : internalIncludes) {
headerPrinter->Print({{"include", include}}, CommonTemplates::InternalIncludeTemplate());
}
headerPrinter->PrintRaw("\n");
if (!Options::instance().exportMacro().empty()) {
headerPrinter->Print({ { "export_macro", Options::instance().exportMacro() } },
CommonTemplates::ExportMacroTemplate());
}
OpenFileNamespaces(file, headerPrinter.get());
for (int i = 0; i < file->enum_type_count(); ++i) {
EnumDeclarationPrinter enumDecl(file->enum_type(i), headerPrinter);
enumDecl.run();
}
common::iterateMessages(file, [&headerPrinter](const Descriptor *message) {
MessageDeclarationPrinter messageDecl(message, headerPrinter);
messageDecl.printClassForwardDeclaration();
});
common::iterateMessages(
file,
[&headerPrinter](const Descriptor *message) {
MessageDeclarationPrinter messageDecl(message, headerPrinter);
messageDecl.printClassDeclaration();
});
CloseFileNamespaces(file, headerPrinter.get());
common::iterateMessages(file, [&headerPrinter](const Descriptor *message) {
MessageDeclarationPrinter messageDef(message, headerPrinter);
messageDef.printMetaTypesDeclaration();
});
headerPrinter->Print({{"filename", filename}}, CommonTemplates::FooterTemplate());
}
bool QProtobufGenerator::GenerateMessages(const FileDescriptor *file,
GeneratorContext *generatorContext) const
{
assert(file != nullptr && generatorContext != nullptr);
if (file->message_type_count() <= 0 && file->enum_type_count() <= 0) {
return false;
}
GenerateHeader(file, generatorContext);
GenerateSources(file, generatorContext);
return true;
}

View File

@ -0,0 +1,38 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QPROTOBUFGENERATOR_H
#define QPROTOBUFGENERATOR_H
#include "generatorbase.h"
namespace google::protobuf {
class FileDescriptor;
class Descriptor;
namespace compiler {
class GeneratorContext;
} // namespace compiler
} // namespace google::protobuf
namespace QtProtobuf {
class QProtobufGenerator : public qtprotoccommon::GeneratorBase
{
public:
QProtobufGenerator();
~QProtobufGenerator();
bool Generate(const ::google::protobuf::FileDescriptor *file,
const std::string &parameter,
::google::protobuf::compiler::GeneratorContext *generatorContext,
std::string *error) const override;
private:
bool GenerateMessages(const ::google::protobuf::FileDescriptor *file,
::google::protobuf::compiler::GeneratorContext *generatorContext) const;
void GenerateHeader(const ::google::protobuf::FileDescriptor *file,
::google::protobuf::compiler::GeneratorContext *generatorContext) const;
void GenerateSources(const ::google::protobuf::FileDescriptor *file,
::google::protobuf::compiler::GeneratorContext *generatorContext) const;
};
} // namespace QtProtobuf
#endif // QPROTOBUFGENERATOR_H

View File

@ -1,40 +0,0 @@
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef SINGLEFILEGENERATOR_H
#define SINGLEFILEGENERATOR_H
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <string>
#include <memory>
#include <functional>
#include "generatorbase.h"
namespace google::protobuf {
class FileDescriptor;
class Descriptor;
namespace compiler {
class GeneratorContext;
} // namespace compiler
} // namespace google::protobuf
namespace QtProtobuf::generator {
class SingleFileGenerator : public GeneratorBase
{
public:
SingleFileGenerator();
~SingleFileGenerator();
bool Generate(const ::google::protobuf::FileDescriptor *file,
const std::string &parameter,
::google::protobuf::compiler::GeneratorContext *generatorContext,
std::string *error) const override;
private:
bool GenerateMessages(const ::google::protobuf::FileDescriptor *file,
::google::protobuf::compiler::GeneratorContext *generatorContext) const;
bool GenerateServices(const ::google::protobuf::FileDescriptor *file,
::google::protobuf::compiler::GeneratorContext *generatorContext) const;
};
} // namespace QtProtobuf
#endif // SINGLEFILEGENERATOR_H

View File

@ -0,0 +1,22 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_add_library(QtProtocCommon STATIC
baseprinter.cpp baseprinter.h
descriptorprinterbase.h
generatorbase.cpp generatorbase.h
generatorcommon.cpp generatorcommon.h
options.cpp options.h
commontemplates.cpp commontemplates.h
utils.cpp utils.h
)
target_link_libraries(QtProtocCommon
PUBLIC
WrapProtobuf::WrapLibProtobuf
WrapProtobuf::WrapLibProtoc
)
target_include_directories(QtProtocCommon PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)

View File

@ -2,16 +2,15 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "baseprinter.h"
#include "templates.h"
#include "generatorcommon.h"
#include <google/protobuf/descriptor.h>
#include "utils.h"
#include "commontemplates.h"
#include <google/protobuf/io/printer.h>
#include <string.h>
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
using namespace ::QtProtobuf::generator;
using namespace ::qtprotoccommon;
BasePrinter::BasePrinter(std::shared_ptr<Printer> printer) : m_printer(std::move(printer)) { }
@ -19,12 +18,12 @@ BasePrinter::~BasePrinter() = default;
void BasePrinter::printPublicBlock()
{
m_printer->Print(Templates::PublicBlockTemplate());
m_printer->Print(CommonTemplates::PublicBlockTemplate());
}
void BasePrinter::printPrivateBlock()
{
m_printer->Print(Templates::PrivateBlockTemplate());
m_printer->Print(CommonTemplates::PrivateBlockTemplate());
}
void BasePrinter::printCommentsImpl(std::string comments)
@ -55,3 +54,16 @@ void BasePrinter::printCommentsImpl(std::string comments)
m_printer->Print(" */");
}
}
void BasePrinter::Indent()
{
// The protoc printer prints 2 spaces, so we call it twice
m_printer->Indent();
m_printer->Indent();
}
void BasePrinter::Outdent()
{
m_printer->Outdent();
m_printer->Outdent();
}

View File

@ -1,19 +1,20 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef BASEPRINTER_H
#define BASEPRINTER_H
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.h>
#include <memory>
#include "utils.h"
#include "options.h"
#include "generatorcommon.h"
namespace QtProtobuf::generator {
namespace google::protobuf::io {
class Printer;
} // google::protobuf::io
namespace qtprotoccommon {
using PropertyMap = std::map<std::string, std::string>;
@ -39,19 +40,8 @@ public:
descriptor->GetSourceLocation(&loc);
printCommentsImpl(loc.leading_comments);
}
void Indent()
{
// The protoc printer prints 2 spaces, so we call it twice
m_printer->Indent();
m_printer->Indent();
}
void Outdent()
{
m_printer->Outdent();
m_printer->Outdent();
}
void Indent();
void Outdent();
private:
void printCommentsImpl(std::string comments);
@ -62,5 +52,5 @@ protected:
std::shared_ptr<::google::protobuf::io::Printer> m_printer;
};
} // namespace QtProtobuf::generator
} // namespace qtprotoccommon
#endif // BASEPRINTER_H

View File

@ -2,10 +2,9 @@
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "templates.h"
#include <unordered_map>
#include "commontemplates.h"
// Templates navigation map:
// CommonTemplates navigation map:
// All template functions are named as following(with some exceptions):
// <CommonTemplateType>[TemplateSubject][Declaration|Definition]Template
//
@ -27,20 +26,20 @@
// Map and Repeated can be combined with one of Complex, Message or Enum keywords, that indicates
// the specialization of the template.
using namespace ::QtProtobuf::generator;
using namespace ::qtprotoccommon;
const char *Templates::ProtoSuffix()
const char *CommonTemplates::ProtoSuffix()
{
return "_proto";
}
const std::vector<std::string> &Templates::ListOfQmlExceptions()
const std::vector<std::string> &CommonTemplates::ListOfQmlExceptions()
{
static std::vector<std::string> vec{ { "id", "property", "import" } };
return vec;
}
const char *Templates::DefaultProtobufIncludesTemplate()
const char *CommonTemplates::DefaultProtobufIncludesTemplate()
{
return "#include <QtCore/QMetaType>\n"
"#include <QtCore/QList>\n"
@ -52,107 +51,107 @@ const char *Templates::DefaultProtobufIncludesTemplate()
"\n";
}
const char *Templates::QmlProtobufIncludesTemplate()
const char *CommonTemplates::QmlProtobufIncludesTemplate()
{
return "#include <QtQml/QQmlListProperty>\n"
"#include <QtProtobufQuick/qtprotobufqmllistpropertyconstructor.h>\n\n";
}
const char *Templates::DisclaimerTemplate()
const char *CommonTemplates::DisclaimerTemplate()
{
return "/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */\n\n";
}
const char *Templates::PreambleTemplate()
const char *CommonTemplates::PreambleTemplate()
{
return "#ifndef Q_PROTOBUF_$filename$_H\n"
"#define Q_PROTOBUF_$filename$_H\n\n"
"#include <QtProtobuf/QProtobufMessage>\n";
}
const char *Templates::FooterTemplate()
const char *CommonTemplates::FooterTemplate()
{
return "#endif // Q_PROTOBUF_$filename$_H\n";
}
const char *Templates::InternalIncludeTemplate()
const char *CommonTemplates::InternalIncludeTemplate()
{
return "#include \"$include$.h\"\n";
}
const char *Templates::ExternalIncludeTemplate()
const char *CommonTemplates::ExternalIncludeTemplate()
{
return "#include <$include$>\n";
}
const char *Templates::GlobalEnumIncludeTemplate()
const char *CommonTemplates::GlobalEnumIncludeTemplate()
{
return "#include <globalenums.h>\n";
}
const char *Templates::EnumRegistrationDeclaration()
const char *CommonTemplates::EnumRegistrationDeclaration()
{
return "$export_macro$ void registerTypes();\n";
}
const char *Templates::MetaTypeRegistrationDeclaration()
const char *CommonTemplates::MetaTypeRegistrationDeclaration()
{
return "static void registerTypes();\n";
}
const char *Templates::MetaTypeRegistrationMessageDefinition()
const char *CommonTemplates::MetaTypeRegistrationMessageDefinition()
{
return "void $type$::registerTypes()\n{\n"
" qRegisterMetaType<$type$>();\n"
" qRegisterMetaType<$list_type$>();\n";
}
const char *Templates::MetaTypeRegistrationGlobalEnumDefinition()
const char *CommonTemplates::MetaTypeRegistrationGlobalEnumDefinition()
{
return "void $enum_gadget$::registerTypes()\n{\n";
}
const char *Templates::MetaTypeRegistrationGlobalEnumTemplate()
const char *CommonTemplates::MetaTypeRegistrationGlobalEnumTemplate()
{
return "qRegisterMetaType<$type$>();\n"
"qRegisterMetaType<$full_type$>();\n";
}
const char *Templates::UsingMessageTemplate()
const char *CommonTemplates::UsingMessageTemplate()
{
return "using $classname$Repeated = QList<std::shared_ptr<$classname$>>;\n";
}
const char *Templates::UsingMapTemplate()
const char *CommonTemplates::UsingMapTemplate()
{
return "using $type$ = QHash<$key_type$, $value_type$>;\n";
}
const char *Templates::UsingMapMessageTemplate()
const char *CommonTemplates::UsingMapMessageTemplate()
{
return "using $type$ = QHash<$key_type$, std::shared_ptr<$value_type$>>;\n";
}
const char *Templates::UsingNestedMessageTemplate()
const char *CommonTemplates::UsingNestedMessageTemplate()
{
return "using $type$ = $scope_namespaces$::$type$;\n"
"using $list_type$ = $scope_namespaces$::$list_type$;\n";
}
const char *Templates::UsingRepeatedEnumTemplate()
const char *CommonTemplates::UsingRepeatedEnumTemplate()
{
return "using $list_type$ = QList<$type$>;\n";
}
const char *Templates::NamespaceTemplate()
const char *CommonTemplates::NamespaceTemplate()
{
return "namespace $scope_namespaces$ {\n";
}
const char *Templates::NamespaceClosingTemplate()
const char *CommonTemplates::NamespaceClosingTemplate()
{
return "} // namespace $scope_namespaces$\n";
}
const char *Templates::EnumDeclarationTemplate()
const char *CommonTemplates::EnumDeclarationTemplate()
{
return "\nnamespace $classname$ {\n"
"Q_NAMESPACE_EXPORT($export_macro$)\n";
}
const char *Templates::ClassMessageForwardDeclarationTemplate()
const char *CommonTemplates::ClassMessageForwardDeclarationTemplate()
{
return "class $classname$;\n";
}
const char *Templates::ClassMessageBeginDeclarationTemplate()
const char *CommonTemplates::ClassMessageBeginDeclarationTemplate()
{
return "\nclass $export_macro$ $classname$ : public QProtobufMessage\n"
"{\n"
@ -161,286 +160,286 @@ const char *Templates::ClassMessageBeginDeclarationTemplate()
" Q_DECLARE_PROTOBUF_SERIALIZERS($classname$)\n";
}
const char *Templates::PropertyTemplate()
const char *CommonTemplates::PropertyTemplate()
{
return "Q_PROPERTY($property_type$ $property_name$ READ $property_name$ WRITE "
"set$property_name_cap$ SCRIPTABLE $scriptable$)\n";
}
const char *Templates::PropertyRepeatedTemplate()
const char *CommonTemplates::PropertyRepeatedTemplate()
{
return "Q_PROPERTY($property_list_type$ $property_name$ READ $property_name$ WRITE "
"set$property_name_cap$ SCRIPTABLE $scriptable$)\n";
}
const char *Templates::PropertyRepeatedMessageTemplate()
const char *CommonTemplates::PropertyRepeatedMessageTemplate()
{
return "Q_PROPERTY($property_list_type$ $property_name$Data READ $property_name$ WRITE "
"set$property_name_cap$ SCRIPTABLE $scriptable$)\n";
}
const char *Templates::PropertyNonScriptableTemplate()
const char *CommonTemplates::PropertyNonScriptableTemplate()
{
return "Q_PROPERTY($property_type$ $property_name$_p READ $property_name$ WRITE "
"set$property_name_cap$ SCRIPTABLE false)\n";
}
const char *Templates::PropertyNonScriptableAliasTemplate()
const char *CommonTemplates::PropertyNonScriptableAliasTemplate()
{
return "Q_PROPERTY($qml_alias_type$ $property_name$ READ $property_name$_p WRITE "
"set$property_name_cap$_p SCRIPTABLE true)\n";
}
const char *Templates::PropertyMessageTemplate()
const char *CommonTemplates::PropertyMessageTemplate()
{
return "Q_PROPERTY($property_type$ *$property_name$ READ $property_name$_p WRITE "
"set$property_name_cap$_p)\n";
}
const char *Templates::PropertyQmlListTemplate()
const char *CommonTemplates::PropertyQmlListTemplate()
{
return "Q_PROPERTY(QQmlListProperty<$property_type$> $property_name$ READ $property_name$_l)\n";
}
const char *Templates::ConstructorMessageDeclarationTemplate()
const char *CommonTemplates::ConstructorMessageDeclarationTemplate()
{
return "$classname$();\n";
}
const char *Templates::DestructorMessageDeclarationTemplate()
const char *CommonTemplates::DestructorMessageDeclarationTemplate()
{
return "~$classname$() override;\n";
}
const char *Templates::MemberTemplate()
const char *CommonTemplates::MemberTemplate()
{
return "$scope_type$ m_$property_name$;\n";
}
const char *Templates::MemberRepeatedTemplate()
const char *CommonTemplates::MemberRepeatedTemplate()
{
return "$scope_list_type$ m_$property_name$;\n";
}
const char *Templates::MemberMessageTemplate()
const char *CommonTemplates::MemberMessageTemplate()
{
return "QtProtobufPrivate::QProtobufLazyMessagePointer<$scope_type$> m_$property_name$;\n";
}
const char *Templates::PublicBlockTemplate()
const char *CommonTemplates::PublicBlockTemplate()
{
return "\npublic:\n";
}
const char *Templates::PrivateBlockTemplate()
const char *CommonTemplates::PrivateBlockTemplate()
{
return "\nprivate:\n";
}
const char *Templates::EnumDefinitionTemplate()
const char *CommonTemplates::EnumDefinitionTemplate()
{
return "enum $type$ {\n";
}
const char *Templates::EnumFieldTemplate()
const char *CommonTemplates::EnumFieldTemplate()
{
return "$enumvalue$ = $value$,\n";
}
const char *Templates::ConstructorMessageDefinitionTemplate()
const char *CommonTemplates::ConstructorMessageDefinitionTemplate()
{
return "$type$::$type$() : QProtobufMessage(&$type$::staticMetaObject)";
}
const char *Templates::EmptyConstructorTemplate()
const char *CommonTemplates::EmptyConstructorTemplate()
{
return "$classname$() {}\n";
}
const char *Templates::QObjectConstructorMessageDeclarationTemplate()
const char *CommonTemplates::QObjectConstructorMessageDeclarationTemplate()
{
return "explicit $classname$(QObject *parent = nullptr);\n";
}
const char *Templates::CopyConstructorDeclarationTemplate()
const char *CommonTemplates::CopyConstructorDeclarationTemplate()
{
return "$classname$(const $classname$ &other);\n";
}
const char *Templates::MoveConstructorDeclarationTemplate()
const char *CommonTemplates::MoveConstructorDeclarationTemplate()
{
return "$classname$($classname$ &&other) noexcept;\n";
}
const char *Templates::CopyConstructorDefinitionTemplate()
const char *CommonTemplates::CopyConstructorDefinitionTemplate()
{
return "$classname$::$classname$(const $classname$ &other) : "
"QProtobufMessage(other)";
}
const char *Templates::MoveConstructorDefinitionTemplate()
const char *CommonTemplates::MoveConstructorDefinitionTemplate()
{
return "$classname$::$classname$($classname$ &&other) noexcept : "
"QProtobufMessage(std::move(other))";
}
const char *Templates::DeletedCopyConstructorTemplate()
const char *CommonTemplates::DeletedCopyConstructorTemplate()
{
return "$classname$(const $classname$ &) = delete;\n";
}
const char *Templates::DeletedMoveConstructorTemplate()
const char *CommonTemplates::DeletedMoveConstructorTemplate()
{
return "$classname$($classname$ &&) = delete;\n";
}
const char *Templates::CopyMemberTemplate()
const char *CommonTemplates::CopyMemberTemplate()
{
return "set$property_name_cap$(other.m_$property_name$);\n";
}
const char *Templates::CopyMemberMessageTemplate()
const char *CommonTemplates::CopyMemberMessageTemplate()
{
return "if (m_$property_name$ != other.m_$property_name$) {\n"
" *m_$property_name$ = *other.m_$property_name$;\n"
"}\n";
}
const char *Templates::AssignMemberMessageTemplate()
const char *CommonTemplates::AssignMemberMessageTemplate()
{
return "if (m_$property_name$ != other.m_$property_name$)\n"
" *m_$property_name$ = *other.m_$property_name$;\n";
}
const char *Templates::MoveMemberMessageTemplate()
const char *CommonTemplates::MoveMemberMessageTemplate()
{
return "if (m_$property_name$ != other.m_$property_name$) {\n"
" *m_$property_name$ = std::move(*other.m_$property_name$);\n"
"}\n";
}
const char *Templates::MoveAssignMemberMessageTemplate()
const char *CommonTemplates::MoveAssignMemberMessageTemplate()
{
return "if (m_$property_name$ != other.m_$property_name$)\n"
" *m_$property_name$ = std::move(*other.m_$property_name$);\n";
}
const char *Templates::MoveAssignMemberComplexTemplate()
const char *CommonTemplates::MoveAssignMemberComplexTemplate()
{
return "if (m_$property_name$ != other.m_$property_name$)\n"
" m_$property_name$ = std::move(other.m_$property_name$);\n";
}
const char *Templates::MoveConstructorMemberComplexTemplate()
const char *CommonTemplates::MoveConstructorMemberComplexTemplate()
{
return "m_$property_name$ = std::move(other.m_$property_name$);\n";
}
const char *Templates::MoveMemberTemplate()
const char *CommonTemplates::MoveMemberTemplate()
{
return "set$property_name_cap$(std::exchange(other.m_$property_name$, 0));\n";
}
const char *Templates::MoveMemberEnumTemplate()
const char *CommonTemplates::MoveMemberEnumTemplate()
{
return "m_$property_name$ = other.m_$property_name$;\n";
}
const char *Templates::AssignmentOperatorDeclarationTemplate()
const char *CommonTemplates::AssignmentOperatorDeclarationTemplate()
{
return "$classname$ &operator =(const $classname$ &other);\n";
}
const char *Templates::AssignmentOperatorDefinitionTemplate()
const char *CommonTemplates::AssignmentOperatorDefinitionTemplate()
{
return "$classname$ &$classname$::operator =(const $classname$ &other)\n"
"{\n"
" QProtobufMessage::operator=(other);\n";
}
const char *Templates::AssignmentOperatorReturnTemplate()
const char *CommonTemplates::AssignmentOperatorReturnTemplate()
{
return "return *this;\n";
}
const char *Templates::MoveAssignmentOperatorDeclarationTemplate()
const char *CommonTemplates::MoveAssignmentOperatorDeclarationTemplate()
{
return "$classname$ &operator =($classname$ &&other) noexcept;\n";
}
const char *Templates::MoveAssignmentOperatorDefinitionTemplate()
const char *CommonTemplates::MoveAssignmentOperatorDefinitionTemplate()
{
return "$classname$ &$classname$::operator =($classname$ &&other) noexcept\n"
"{\n"
" QProtobufMessage::operator=(std::move(other));\n";
}
const char *Templates::EqualOperatorDeclarationTemplate()
const char *CommonTemplates::EqualOperatorDeclarationTemplate()
{
return "bool operator ==(const $classname$ &other) const;\n";
}
const char *Templates::EqualOperatorDefinitionTemplate()
const char *CommonTemplates::EqualOperatorDefinitionTemplate()
{
return "bool $classname$::operator ==(const $classname$ &other) const\n{\n"
" return QProtobufMessage::isEqual(*this, other)";
}
const char *Templates::EqualOperatorMemberTemplate()
const char *CommonTemplates::EqualOperatorMemberTemplate()
{
return "m_$property_name$ == other.m_$property_name$";
}
const char *Templates::EqualOperatorMemberMessageTemplate()
const char *CommonTemplates::EqualOperatorMemberMessageTemplate()
{
return "(m_$property_name$ == other.m_$property_name$\n"
" || *m_$property_name$ == *other.m_$property_name$)\n";
}
const char *Templates::EqualOperatorMemberRepeatedTemplate()
const char *CommonTemplates::EqualOperatorMemberRepeatedTemplate()
{
return "QtProtobuf::repeatedValueCompare(m_$property_name$, other.m_$property_name$)";
}
const char *Templates::NotEqualOperatorDeclarationTemplate()
const char *CommonTemplates::NotEqualOperatorDeclarationTemplate()
{
return "bool operator !=(const $classname$ &other) const;\n";
}
const char *Templates::NotEqualOperatorDefinitionTemplate()
const char *CommonTemplates::NotEqualOperatorDefinitionTemplate()
{
return "bool $classname$::operator !=(const $classname$ &other) const\n{\n"
" return !this->operator ==(other);\n"
"}\n\n";
}
const char *Templates::PrivateGetterMessageDeclarationTemplate()
const char *CommonTemplates::PrivateGetterMessageDeclarationTemplate()
{
return "$getter_type$ *$property_name$_p() const;\n";
}
const char *Templates::PrivateGetterMessageDefinitionTemplate()
const char *CommonTemplates::PrivateGetterMessageDefinitionTemplate()
{
return "$getter_type$ *$classname$::$property_name$_p() const\n{\n"
" return m_$property_name$.get();\n"
"}\n\n";
}
const char *Templates::GetterMessageDeclarationTemplate()
const char *CommonTemplates::GetterMessageDeclarationTemplate()
{
return "$getter_type$ &$property_name$() const;\n";
}
const char *Templates::GetterMessageDefinitionTemplate()
const char *CommonTemplates::GetterMessageDefinitionTemplate()
{
return "$getter_type$ &$classname$::$property_name$() const\n{\n"
" return *m_$property_name$;\n"
"}\n\n";
}
const char *Templates::GetterTemplate()
const char *CommonTemplates::GetterTemplate()
{
return "$getter_type$ $property_name$() const {\n"
" return m_$property_name$;\n"
"}\n\n";
}
const char *Templates::GetterNonScriptableTemplate()
const char *CommonTemplates::GetterNonScriptableTemplate()
{
return "$qml_alias_type$ $property_name$_p() const {\n"
" return m_$property_name$;\n"
"}\n\n";
}
const char *Templates::GetterComplexTemplate()
const char *CommonTemplates::GetterComplexTemplate()
{
return "$getter_type$ &$property_name$() {\n"
" return m_$property_name$;\n"
"}\n\n";
}
const char *Templates::GetterQmlListDeclarationTemplate()
const char *CommonTemplates::GetterQmlListDeclarationTemplate()
{
return "QQmlListProperty<$scope_type$> $property_name$_l();\n";
}
const char *Templates::GetterQmlListDefinitionTemplate()
const char *CommonTemplates::GetterQmlListDefinitionTemplate()
{
return "QQmlListProperty<$full_type$> $classname$::$property_name$_l()\n{\n"
" return qProtobufConstructQmlListProperty<$scope_type$>(this, &m_$property_name$);\n"
"}\n\n";
}
const char *Templates::PrivateSetterMessageDeclarationTemplate()
const char *CommonTemplates::PrivateSetterMessageDeclarationTemplate()
{
return "void set$property_name_cap$_p($setter_type$ *$property_name$);\n";
}
const char *Templates::PrivateSetterMessageDefinitionTemplate()
const char *CommonTemplates::PrivateSetterMessageDefinitionTemplate()
{
return "void $classname$::set$property_name_cap$_p($setter_type$ *$property_name$)\n{\n"
" if (m_$property_name$.get() != $property_name$)\n"
@ -448,11 +447,11 @@ const char *Templates::PrivateSetterMessageDefinitionTemplate()
"}\n\n";
}
const char *Templates::SetterMessageDeclarationTemplate()
const char *CommonTemplates::SetterMessageDeclarationTemplate()
{
return "void set$property_name_cap$(const $setter_type$ &$property_name$);\n";
}
const char *Templates::SetterMessageDefinitionTemplate()
const char *CommonTemplates::SetterMessageDefinitionTemplate()
{
return "void $classname$::set$property_name_cap$(const $setter_type$ &$property_name$)\n{\n"
" if (*m_$property_name$ != $property_name$)\n"
@ -460,11 +459,11 @@ const char *Templates::SetterMessageDefinitionTemplate()
"}\n\n";
}
const char *Templates::SetterComplexDeclarationTemplate()
const char *CommonTemplates::SetterComplexDeclarationTemplate()
{
return "void set$property_name_cap$(const $setter_type$ &$property_name$);\n";
}
const char *Templates::SetterComplexDefinitionTemplate()
const char *CommonTemplates::SetterComplexDefinitionTemplate()
{
return "void $classname$::set$property_name_cap$(const $setter_type$ &$property_name$)\n{\n"
" if (m_$property_name$ != $property_name$)\n"
@ -472,14 +471,14 @@ const char *Templates::SetterComplexDefinitionTemplate()
"}\n\n";
}
const char *Templates::SetterTemplate()
const char *CommonTemplates::SetterTemplate()
{
return "void set$property_name_cap$(const $setter_type$ &$property_name$) {\n"
" if (m_$property_name$ != $property_name$)\n"
" m_$property_name$ = $property_name$;\n"
"}\n\n";
}
const char *Templates::SetterNonScriptableTemplate()
const char *CommonTemplates::SetterNonScriptableTemplate()
{
return "void set$property_name_cap$_p(const $qml_alias_type$ &$property_name$) {\n"
" if (m_$property_name$ != $property_name$)\n"
@ -487,46 +486,46 @@ const char *Templates::SetterNonScriptableTemplate()
"}\n\n";
}
const char *Templates::SignalsBlockTemplate()
const char *CommonTemplates::SignalsBlockTemplate()
{
return "\nQ_SIGNALS:\n";
}
const char *Templates::SignalTemplate()
const char *CommonTemplates::SignalTemplate()
{
return "void $property_name$Changed();\n";
}
const char *Templates::MetaDataUintDataEntryTemplate()
const char *CommonTemplates::MetaDataUintDataEntryTemplate()
{
return "const std::array<uint, $size$> qt_protobuf_$classname$_uint_data =";
}
const char *Templates::MetaDataCharDataEntryTemplate()
const char *CommonTemplates::MetaDataCharDataEntryTemplate()
{
return "const char qt_protobuf_$classname$_char_data[$size$] =";
}
const char *Templates::JsonNameOffsetsUintDataTemplate()
const char *CommonTemplates::JsonNameOffsetsUintDataTemplate()
{
return "$json_name_offset$, /* = $json_name$ */\n";
}
const char *Templates::FieldNumbersUintDataTemplate()
const char *CommonTemplates::FieldNumbersUintDataTemplate()
{
return "$field_number$, /* = $json_name$ */\n";
}
const char *Templates::QtPropertyIndicesUintDataTemplate()
const char *CommonTemplates::QtPropertyIndicesUintDataTemplate()
{
return "$property_index$, /* = $json_name$ */\n";
}
const char *Templates::FieldFlagsUintDataTemplate()
const char *CommonTemplates::FieldFlagsUintDataTemplate()
{
return "$field_flags$, /* = $json_name$ */\n";
}
const char *Templates::PropertyOrderingDataOpeningTemplate()
const char *CommonTemplates::PropertyOrderingDataOpeningTemplate()
{
return "static constexpr struct {\n"
" QtProtobufPrivate::QProtobufPropertyOrdering::Data data;\n"
@ -544,101 +543,101 @@ const char *Templates::PropertyOrderingDataOpeningTemplate()
" },\n";
}
const char *Templates::PropertyOrderingDataClosingTemplate()
const char *CommonTemplates::PropertyOrderingDataClosingTemplate()
{
return "};\n\n";
}
const char *Templates::PropertyOrderingDefinitionTemplate()
const char *CommonTemplates::PropertyOrderingDefinitionTemplate()
{
return "const QtProtobufPrivate::QProtobufPropertyOrdering $type$::propertyOrdering = {\n"
" &qt_protobuf_$classname$_metadata.data\n"
"};\n\n";
}
const char *Templates::SimpleBlockEnclosureTemplate()
const char *CommonTemplates::SimpleBlockEnclosureTemplate()
{
return "}\n";
}
const char *Templates::SemicolonBlockEnclosureTemplate()
const char *CommonTemplates::SemicolonBlockEnclosureTemplate()
{
return "};\n";
}
const char *Templates::InitializerMemberTemplate()
const char *CommonTemplates::InitializerMemberTemplate()
{
return "m_$property_name$($initializer$)";
}
const char *Templates::InitializerMemberMessageTemplate()
const char *CommonTemplates::InitializerMemberMessageTemplate()
{
return "m_$property_name$(nullptr)";
}
const char *Templates::EmptyBracesTemplate()
const char *CommonTemplates::EmptyBracesTemplate()
{
return "\n{\n}\n";
}
const char *Templates::DeclareMetaTypeTemplate()
const char *CommonTemplates::DeclareMetaTypeTemplate()
{
return "Q_DECLARE_METATYPE($full_type$)\n";
}
const char *Templates::DeclareMetaTypeQmlListTemplate()
const char *CommonTemplates::DeclareMetaTypeQmlListTemplate()
{
return "Q_DECLARE_METATYPE(QQmlListProperty<$full_type$>)\n";
}
const char *Templates::MetaTypeRegistrationLocalEnumTemplate()
const char *CommonTemplates::MetaTypeRegistrationLocalEnumTemplate()
{
return "qRegisterProtobufEnumType<$scope_type$>();\n"
"qRegisterMetaType<$scope_type$>();\n"
"qRegisterMetaType<$scope_type$>();\n"
"qRegisterMetaType<$scope_list_type$>();\n";
}
const char *Templates::MetaTypeRegistrationMapTemplate()
const char *CommonTemplates::MetaTypeRegistrationMapTemplate()
{
return "qRegisterMetaType<$scope_type$>();\n"
"qRegisterProtobufMapType<$key_type$, $value_type$>();\n";
}
const char *Templates::MetaTypeRegistrationQmlListTemplate()
const char *CommonTemplates::MetaTypeRegistrationQmlListTemplate()
{
return "qRegisterMetaType<QQmlListProperty<$full_type$>>();\n";
}
const char *Templates::QEnumTemplate()
const char *CommonTemplates::QEnumTemplate()
{
return "Q_ENUM($type$)\n";
}
const char *Templates::QEnumNSTemplate()
const char *CommonTemplates::QEnumNSTemplate()
{
return "Q_ENUM_NS($type$)\n";
}
const char *Templates::RegisterEnumSerializersTemplate()
const char *CommonTemplates::RegisterEnumSerializersTemplate()
{
return "qRegisterProtobufEnumType<$full_type$>();\n";
}
const char *Templates::RegistrarTemplate()
const char *CommonTemplates::RegistrarTemplate()
{
return "static QtProtobuf::ProtoTypeRegistrar "
"ProtoTypeRegistrar$classname$(qRegisterProtobufType<$classname$>);\n";
}
const char *Templates::RegistrarEnumTemplate()
const char *CommonTemplates::RegistrarEnumTemplate()
{
return "static QtProtobuf::ProtoTypeRegistrar "
"ProtoTypeRegistrar$enum_gadget$($enum_gadget$::registerTypes);\n";
}
const char *Templates::QmlRegisterTypeTemplate()
const char *CommonTemplates::QmlRegisterTypeTemplate()
{
return "qmlRegisterType<$scope_type$>(\"$qml_package$\", 1, 0, \"$type$\");\n";
}
const char *Templates::QmlRegisterTypeEnumTemplate()
const char *CommonTemplates::QmlRegisterTypeEnumTemplate()
{
return "qmlRegisterUncreatableType<$enum_gadget$>(\"$qml_package$\", 1, 0, \"$type$\", "
"QStringLiteral(\"$full_type$ Could not be created from qml context\"));\n";
}
const char *Templates::RepeatedSuffix()
const char *CommonTemplates::RepeatedSuffix()
{
return "Repeated";
}
@ -647,7 +646,7 @@ const char *Templates::RepeatedSuffix()
// See https://doc.qt.io/qt-6/qtqml-typesystem-valuetypes.html for types that are supported by the
// QML JS engine.
const std::unordered_map<::google::protobuf::FieldDescriptor::Type, std::string>
&Templates::TypeReflection()
&CommonTemplates::TypeReflection()
{
static std::unordered_map<::google::protobuf::FieldDescriptor::Type, std::string> map{
{ ::google::protobuf::FieldDescriptor::TYPE_DOUBLE, "double" },
@ -669,49 +668,39 @@ const std::unordered_map<::google::protobuf::FieldDescriptor::Type, std::string>
return map;
}
const char *Templates::ProtoFileSuffix()
const char *CommonTemplates::ProtoFileSuffix()
{
return ".qpb";
}
const char *Templates::GrpcClientFileSuffix()
{
return "_client.grpc";
}
const char *Templates::GrpcServiceFileSuffix()
{
return "_service.grpc";
}
const char *Templates::EnumClassSuffix()
const char *CommonTemplates::EnumClassSuffix()
{
return "Gadget";
}
const char *Templates::QtProtobufNamespace()
const char *CommonTemplates::QtProtobufNamespace()
{
return "QtProtobuf";
}
const char *Templates::QtProtobufNestedNamespace()
const char *CommonTemplates::QtProtobufNestedNamespace()
{
return "_QtProtobufNested";
}
const char *Templates::QtProtobufFieldEnum()
const char *CommonTemplates::QtProtobufFieldEnum()
{
return "QtProtobufFieldEnum";
}
const char *Templates::FieldEnumTemplate()
const char *CommonTemplates::FieldEnumTemplate()
{
return "enum QtProtobufFieldEnum {\n";
}
const char *Templates::FieldNumberTemplate()
const char *CommonTemplates::FieldNumberTemplate()
{
return "$property_name_cap$ProtoFieldNumber = $number$,\n";
}
const char *Templates::ExportMacroTemplate()
const char *CommonTemplates::ExportMacroTemplate()
{
return "#if defined(QT_SHARED) || !defined(QT_STATIC)\n"
"# if defined(QT_BUILD_$export_macro$_LIB)\n"
@ -724,208 +713,3 @@ const char *Templates::ExportMacroTemplate()
"#endif\n";
}
const char *Templates::ChildClassDeclarationTemplate()
{
return "\nclass $export_macro$ $classname$ : public $parent_class$\n"
"{\n"
" Q_OBJECT\n";
}
const char *Templates::ClientMethodDeclarationSyncTemplate()
{
return "QGrpcStatus $method_name$(const $param_type$ &$param_name$, "
"$return_type$ *$return_name$);\n";
}
const char *Templates::ClientMethodDeclarationAsyncTemplate()
{
return "std::shared_ptr<QGrpcCallReply> $method_name$(const $param_type$ &$param_name$);\n";
}
const char *Templates::ClientMethodDeclarationAsync2Template()
{
return "Q_INVOKABLE void $method_name$(const $param_type$ &$param_name$, const QObject "
"*context, "
"const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback);\n";
}
const char *Templates::ClientMethodDeclarationQmlTemplate()
{
return "Q_INVOKABLE void $method_name$($param_type$ *$param_name$, const QJSValue &callback, "
"const QJSValue &errorCallback);\n";
}
const char *Templates::ClientMethodDeclarationQml2Template()
{
return "Q_INVOKABLE void $method_name$($param_type$ *$param_name$, $return_type$ "
"*$return_name$, const QJSValue &errorCallback);\n";
}
const char *Templates::ServerMethodDeclarationTemplate()
{
return "Q_INVOKABLE virtual $return_type$ $method_name$(const $param_type$ &$param_name$) = "
"0;\n";
}
const char *Templates::ClientConstructorDefinitionTemplate()
{
return "\n$classname$::$classname$(QObject *parent) : $parent_class$(\"$service_name$\", "
"parent)\n"
"{\n"
"}\n";
}
const char *Templates::ClientMethodDefinitionSyncTemplate()
{
return "\nQGrpcStatus $classname$::$method_name$(const $param_type$ &$param_name$, "
"$return_type$ *$return_name$)\n"
"{\n"
" return call<$param_type$>(\"$method_name$\", $param_name$, $return_name$);\n"
"}\n";
}
const char *Templates::ClientMethodDefinitionAsyncTemplate()
{
return "\nstd::shared_ptr<QGrpcCallReply> $classname$::$method_name$(const $param_type$ "
"&$param_name$)\n"
"{\n"
" return call<$param_type$>(\"$method_name$\", $param_name$);\n"
"}\n";
}
const char *Templates::ClientMethodDefinitionAsync2Template()
{
return "\nvoid $classname$::$method_name$(const $param_type$ &$param_name$, const QObject "
"*context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback)\n"
"{\n"
" std::shared_ptr<QGrpcCallReply> reply = call<$param_type$>(\"$method_name$\", "
"$param_name$);\n"
" QObject::connect(reply.get(), &QGrpcCallReply::finished, context, [reply, "
"callback]() "
"{\n"
" callback(reply);\n"
" });\n"
"}\n";
}
const char *Templates::ClientMethodDefinitionQmlTemplate()
{
return "\nvoid $classname$::$method_name$($param_type$ *$param_name$, const QJSValue "
"&callback, "
"const QJSValue &errorCallback)\n"
"{\n"
" if (!callback.isCallable()) {\n"
" qWarning() << \"Unable to call $classname$::$method_name$, callback is not "
"callable\";\n"
" return;\n"
" }\n\n"
" if (arg == nullptr) {\n"
" qWarning() << \"Invalid argument provided for method "
"$classname$::$method_name$, "
"argument of type '$param_type$ *' expected\";\n"
" return;\n"
" }\n\n"
" QJSEngine *jsEngine = qjsEngine(this);\n"
" if (jsEngine == nullptr) {\n"
" qWarning() << \"Unable to call $classname$::$method_name$, it's only callable "
"from JS engine context\";\n"
" return;\n"
" }\n\n"
" std::shared_ptr<QGrpcCallReply> reply = call<$param_type$>(\"$method_name$\", "
"*$param_name$);\n"
" reply->subscribe(jsEngine, [this, reply, callback, jsEngine]() {\n"
" auto result = new $return_type$(reply->read<$return_type$>());\n"
" qmlEngine(this)->setObjectOwnership(result, QQmlEngine::JavaScriptOwnership);\n"
" QJSValue(callback).call(QJSValueList{jsEngine->toScriptValue(result)});\n"
" }, [errorCallback, jsEngine](const QGrpcStatus &status) {\n"
" QJSValue(errorCallback).call(QJSValueList{jsEngine->toScriptValue(status)});\n"
" });\n"
"}\n";
}
const char *Templates::ClientMethodDefinitionQml2Template()
{
return "\nvoid $classname$::$method_name$($param_type$ *$param_name$, $return_type$ "
"*$return_name$, const QJSValue &errorCallback)\n"
"{\n"
" if ($return_name$ == nullptr) {\n"
" qWarning() << \"Invalid argument provided for method "
"$classname$::$method_name$, "
"argument of type '$return_type$ *' expected\";\n"
" return;\n"
" }\n\n"
" QWeakPointer<$return_type$> safeReturn($return_name$);\n\n"
" if ($param_name$ == nullptr) {\n"
" qWarning() << \"Invalid argument provided for method "
"$classname$::$method_name$, "
"argument of type '$param_type$ *' expected\";\n"
" return;\n"
" }\n\n"
" QJSEngine *jsEngine = qjsEngine(this);\n"
" if (jsEngine == nullptr) {\n"
" qWarning() << \"Unable to call $classname$::$method_name$, it's only callable "
"from JS engine context\";\n"
" return;\n"
" }\n\n"
" std::shared_ptr<QGrpcCallReply> reply = call<$param_type$>(\"$method_name$\", "
"*$param_name$);\n"
" reply->subscribe(jsEngine, [this, reply, jsEngine, safeReturn]() {\n"
" if (safeReturn.isNull()) {\n"
" qWarning() << \"Return value is destroyed. Ignore call result\";\n"
" return;\n"
" }\n"
" *safeReturn = $return_type$(reply->read<$return_type$>());\n"
" }, [errorCallback, jsEngine](const QGrpcStatus &status) {\n"
" QJSValue(errorCallback).call(QJSValueList{jsEngine->toScriptValue(status)});\n"
" });\n"
"}\n";
}
const char *Templates::ClientMethodServerStreamDeclarationTemplate()
{
return "std::shared_ptr<QGrpcStream> stream$method_name_upper$(const $param_type$ "
"&$param_name$);\n";
}
const char *Templates::ClientMethodServerStream2DeclarationTemplate()
{
return "std::shared_ptr<QGrpcStream> stream$method_name_upper$(const $param_type$ "
"&$param_name$, const "
"QWeakPointer<$return_type$> &$return_name$);\n";
}
const char *Templates::ClientMethodServerStreamQmlDeclarationTemplate()
{
return "Q_INVOKABLE std::shared_ptr<QGrpcStream> qmlStream$method_name_upper$_p($param_type$ "
"*$param_name$, "
"$return_type$ *$return_name$);\n";
}
const char *Templates::ClientMethodServerStreamDefinitionTemplate()
{
return "std::shared_ptr<QGrpcStream> $classname$::stream$method_name_upper$(const $param_type$ "
"&$param_name$)\n"
"{\n"
" return stream<$param_type$>(\"$method_name$\", $param_name$);\n"
"}\n";
}
const char *Templates::ClientMethodServerStream2DefinitionTemplate()
{
return "std::shared_ptr<QGrpcStream> $classname$::stream$method_name_upper$(const $param_type$ "
"&$param_name$, const QWeakPointer<$return_type$> &$return_name$)\n"
"{\n"
" return stream<$param_type$>(\"$method_name$\", $param_name$, $return_name$);\n"
"}\n";
}
const char *Templates::ClientMethodServerStreamQmlDefinitionTemplate()
{
return "std::shared_ptr<QGrpcStream> $classname$::qmlStream$method_name_upper$_p($param_type$ "
"*$param_name$, "
"$return_type$ *$return_name$)\n"
"{\n"
" return stream<$param_type$>(\"$method_name$\", *$param_name$, "
"QWeakPointer<$return_type$>($return_name$));\n"
"}\n";
}

View File

@ -2,16 +2,16 @@
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTPROTOBUFGEN_TEMPLATES_H
#define QTPROTOBUFGEN_TEMPLATES_H
#ifndef QTPROTOCCOMMON_TEMPLATES_H
#define QTPROTOCCOMMON_TEMPLATES_H
#include <unordered_map>
#include <string>
#include <google/protobuf/descriptor.h>
namespace QtProtobuf::generator {
namespace qtprotoccommon {
class Templates
class CommonTemplates
{
public:
static const std::vector<std::string> &ListOfQmlExceptions();
@ -150,38 +150,8 @@ public:
static const char *QtProtobufFieldEnum();
static const char *ExportMacroTemplate();
// gRPC
static const char *ChildClassDeclarationTemplate();
static const char *GrpcClientFileSuffix();
static const char *GrpcServiceFileSuffix();
static const char *ClientConstructorDefinitionTemplate();
static const char *QObjectConstructorMessageDeclarationTemplate();
static const char *ClientMethodDeclarationSyncTemplate();
static const char *ClientMethodDeclarationAsyncTemplate();
static const char *ClientMethodDeclarationAsync2Template();
static const char *ClientMethodDeclarationQmlTemplate();
static const char *ClientMethodDeclarationQml2Template();
static const char *ServerMethodDeclarationTemplate();
static const char *ClientMethodDefinitionSyncTemplate();
static const char *ClientMethodDefinitionAsyncTemplate();
static const char *ClientMethodDefinitionAsync2Template();
static const char *ClientMethodDefinitionQmlTemplate();
static const char *ClientMethodDefinitionQml2Template();
static const char *ClientMethodServerStreamDeclarationTemplate();
static const char *ClientMethodServerStream2DeclarationTemplate();
static const char *ClientMethodServerStreamQmlDeclarationTemplate();
static const char *ClientMethodServerStreamDefinitionTemplate();
static const char *ClientMethodServerStream2DefinitionTemplate();
static const char *ClientMethodServerStreamQmlDefinitionTemplate();
};
} // namespace QtProtobuf::generator
#endif // QTPROTOBUFGEN_TEMPLATES_H
} // namespace qtprotoccommon
#endif // QTPROTOCCOMMON_TEMPLATES_H

View File

@ -7,11 +7,10 @@
#include "baseprinter.h"
#include "templates.h"
#include "options.h"
#include "commontemplates.h"
#include "generatorcommon.h"
namespace QtProtobuf::generator {
namespace qtprotoccommon {
template<typename T>
class DescriptorPrinterBase : public BasePrinter
@ -27,7 +26,7 @@ public:
void encloseClass()
{
m_printer->Print(Templates::SemicolonBlockEnclosureTemplate());
m_printer->Print(CommonTemplates::SemicolonBlockEnclosureTemplate());
m_printer->Print("\n");
}
@ -35,6 +34,6 @@ protected:
const T *m_descriptor;
TypeMap m_typeMap;
};
} // namespace QtProtobuf::generator
} // namespace qtprotoccommon
#endif // DESCRIPTORPRINTERBASE_H

View File

@ -0,0 +1,85 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "generatorbase.h"
#include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include "utils.h"
#include "commontemplates.h"
#include "generatorcommon.h"
#include "options.h"
#include <cassert>
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
using namespace ::google::protobuf::compiler;
using namespace ::qtprotoccommon;
bool GeneratorBase::GenerateAll(const std::vector<const FileDescriptor *> &files,
const std::string &parameter, GeneratorContext *generatorContext,
std::string *error) const
{
Options::setFromString(parameter);
return CodeGenerator::GenerateAll(files, parameter, generatorContext, error);
}
std::string GeneratorBase::generateBaseName(const FileDescriptor *file, const std::string &name)
{
std::string outFileBasename;
if (Options::instance().isFolder()) {
outFileBasename = file->package();
outFileBasename = utils::replace(outFileBasename, ".", "/");
outFileBasename += '/';
}
outFileBasename += name;
return outFileBasename;
}
void GeneratorBase::printDisclaimer(Printer *printer)
{
printer->Print(CommonTemplates::DisclaimerTemplate());
}
void GeneratorBase::OpenFileNamespaces(
const FileDescriptor *file,
google::protobuf::io::Printer *printer) const
{
assert(printer != nullptr);
const bool hasQtNamespace = (Options::instance().extraNamespace() == "QT_NAMESPACE");
const std::string scopeNamespaces = file->message_type_count() > 0
? common::getFullNamespace(file->message_type(0), "::")
: common::getFullNamespace(file->enum_type(0), "::");
printer->Print("\n");
if (hasQtNamespace)
printer->PrintRaw("QT_BEGIN_NAMESPACE\n");
if (!scopeNamespaces.empty()) {
printer->Print({ { "scope_namespaces", scopeNamespaces } },
CommonTemplates::NamespaceTemplate());
}
}
void GeneratorBase::CloseFileNamespaces(
const ::google::protobuf::FileDescriptor *file,
google::protobuf::io::Printer *printer) const
{
assert(printer != nullptr);
const bool hasQtNamespace = (Options::instance().extraNamespace() == "QT_NAMESPACE");
const std::string scopeNamespaces = file->message_type_count() > 0
? common::getFullNamespace(file->message_type(0), "::")
: common::getFullNamespace(file->enum_type(0), "::");
if (!scopeNamespaces.empty()) {
printer->Print({ { "scope_namespaces", scopeNamespaces } },
CommonTemplates::NamespaceClosingTemplate());
}
if (hasQtNamespace)
printer->PrintRaw("QT_END_NAMESPACE\n");
printer->Print("\n");
}

View File

@ -6,11 +6,9 @@
#define GENERATORBASE_H
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <string>
#include <memory>
#include <functional>
#include <google/protobuf/descriptor.h>
namespace google::protobuf {
class FileDescriptor;
@ -18,9 +16,12 @@ class Descriptor;
namespace compiler {
class GeneratorContext;
} // namespace compiler
namespace io {
class Printer;
} // namespace io
} // namespace google::protobuf
namespace QtProtobuf::generator {
namespace qtprotoccommon {
class GeneratorBase : public ::google::protobuf::compiler::CodeGenerator
{
GeneratorBase(const GeneratorBase &) = delete;
@ -37,11 +38,15 @@ public:
bool HasGenerateAll() const override { return true; }
static void printDisclaimer(::google::protobuf::io::Printer *printer);
void OpenFileNamespaces(const ::google::protobuf::FileDescriptor *file,
google::protobuf::io::Printer *printer) const;
void CloseFileNamespaces(const ::google::protobuf::FileDescriptor *file,
google::protobuf::io::Printer *printer) const;
protected:
static std::string generateBaseName(const ::google::protobuf::FileDescriptor *file,
const std::string &name);
};
} // namespace QtProtobuf::generator
} // namespace qtprotoccommon
#endif // GENERATORBASE_H

View File

@ -5,13 +5,14 @@
#include "generatorcommon.h"
#include "options.h"
#include "utils.h"
#include "commontemplates.h"
#include <cassert>
#include <algorithm>
using namespace ::google::protobuf;
using namespace ::google::protobuf::io;
using namespace ::QtProtobuf::generator;
using namespace ::qtprotoccommon;
/*
Constructs a C++ namespace from the full protobuf descriptor name. E.g. for
@ -41,7 +42,7 @@ std::string common::getFullNamespace(std::string_view fullDescriptorName,
*/
std::string common::getNestedNamespace(const Descriptor *type, std::string_view separator)
{
static const std::string nestedSuffix = Templates::QtProtobufNestedNamespace();
static const std::string nestedSuffix = CommonTemplates::QtProtobufNestedNamespace();
const std::size_t packageSize =
type->file()->package().size() > 0 ? type->file()->package().size() + 1 : 0;
@ -89,7 +90,7 @@ std::string common::getScopeNamespace(std::string_view original, std::string_vie
std::map<std::string, std::string> common::getNestedScopeNamespace(const std::string &className)
{
return { { "scope_namespaces", className + Templates::QtProtobufNestedNamespace() } };
return { { "scope_namespaces", className + CommonTemplates::QtProtobufNestedNamespace() } };
}
TypeMap common::produceQtTypeMap(const Descriptor *type, const Descriptor *scope)
@ -102,7 +103,7 @@ TypeMap common::produceQtTypeMap(const Descriptor *type, const Descriptor *scope
std::string fullName = name;
std::string scopeName = name;
std::string listName = std::string("QList<") + Templates::RepeatedSuffix() + ">";
std::string listName = std::string("QList<") + CommonTemplates::RepeatedSuffix() + ">";
std::string fullListName = listName;
std::string scopeListName = listName;
@ -133,7 +134,7 @@ TypeMap common::produceMessageTypeMap(const Descriptor *type, const Descriptor *
std::string fullName = namespaces.empty() ? name : (namespaces + "::" + name);
std::string scopeName = scopeNamespaces.empty() ? name : (scopeNamespaces + "::" + name);
std::string listName = name + Templates::RepeatedSuffix();
std::string listName = name + CommonTemplates::RepeatedSuffix();
std::string fullListName = namespaces.empty() ? listName : (namespaces + "::" + listName);
std::string scopeListName =
scopeNamespaces.empty() ? listName : (scopeNamespaces + "::" + listName);
@ -172,7 +173,7 @@ TypeMap common::produceEnumTypeMap(const EnumDescriptor *type, const Descriptor
// Not used:
std::string enumGadget = scope != nullptr ? utils::capitalizeAsciiName(scope->name()) : "";
if (visibility == GLOBAL_ENUM) {
enumGadget = name + Templates::EnumClassSuffix();
enumGadget = name + CommonTemplates::EnumClassSuffix();
namespaces += "::";
namespaces += enumGadget; // Global enums are stored in helper Gadget
}
@ -182,7 +183,7 @@ TypeMap common::produceEnumTypeMap(const EnumDescriptor *type, const Descriptor
std::string fullName = namespaces.empty() ? name : (namespaces + "::" + name);
std::string scopeName = scopeNamespaces.empty() ? name : (scopeNamespaces + "::" + name);
std::string listName = name + Templates::RepeatedSuffix();
std::string listName = name + CommonTemplates::RepeatedSuffix();
std::string fullListName = namespaces.empty() ? listName : (namespaces + "::" + listName);
std::string scopeListName =
scopeNamespaces.empty() ? listName : (scopeNamespaces + "::" + listName);
@ -218,14 +219,14 @@ TypeMap common::produceSimpleTypeMap(FieldDescriptor::Type type)
if (type != FieldDescriptor::TYPE_STRING && type != FieldDescriptor::TYPE_BYTES
&& type != FieldDescriptor::TYPE_BOOL && type != FieldDescriptor::TYPE_FLOAT
&& type != FieldDescriptor::TYPE_DOUBLE) {
namespaces = Templates::QtProtobufNamespace();
namespaces = CommonTemplates::QtProtobufNamespace();
}
std::string name;
std::string qmlPackage = Templates::QtProtobufNamespace();
std::string qmlPackage = CommonTemplates::QtProtobufNamespace();
auto it = Templates::TypeReflection().find(type);
if (it != std::end(Templates::TypeReflection()))
auto it = CommonTemplates::TypeReflection().find(type);
if (it != std::end(CommonTemplates::TypeReflection()))
name = it->second;
else
assert(name.empty());
@ -235,7 +236,7 @@ TypeMap common::produceSimpleTypeMap(FieldDescriptor::Type type)
using namespace std::string_literals;
std::string fullListName = listName;
if (type != FieldDescriptor::TYPE_STRING && type != FieldDescriptor::TYPE_BYTES)
fullListName = Templates::QtProtobufNamespace() + "::"s + listName;
fullListName = CommonTemplates::QtProtobufNamespace() + "::"s + listName;
std::string scopeListName = fullListName;
std::string qmlAliasType;
@ -406,10 +407,10 @@ PropertyMap common::producePropertyMap(const FieldDescriptor *field, const Descr
std::string common::qualifiedName(const std::string &name)
{
std::string fieldName(name);
const std::vector<std::string> &searchExceptions = Templates::ListOfQmlExceptions();
const std::vector<std::string> &searchExceptions = CommonTemplates::ListOfQmlExceptions();
if (utils::contains(searchExceptions, fieldName))
return fieldName.append(Templates::ProtoSuffix());
return fieldName.append(CommonTemplates::ProtoSuffix());
return fieldName;
}

View File

@ -6,19 +6,15 @@
#define GENERATORCOMMON_H
#include <google/protobuf/io/printer.h>
#include <vector>
#include <map>
#include <string>
#include <string_view>
#include <functional>
#include "utils.h"
#include "templates.h"
#include "options.h"
#include <google/protobuf/descriptor.h>
namespace QtProtobuf::generator {
namespace qtprotoccommon {
using TypeMap = std::map<std::string, std::string>;
using PropertyMap = std::map<std::string, std::string>;
@ -89,6 +85,6 @@ struct common {
static std::string collectFieldFlags(const google::protobuf::FieldDescriptor *field);
};
} // namespace QtProtobuf::generator
} // namespace qtprotoccommon
#endif // GENERATORCOMMON_H

View File

@ -6,7 +6,7 @@
#include "utils.h"
using namespace ::QtProtobuf::generator;
using namespace ::qtprotoccommon;
static const char QmlPluginOption[] = "QML";
static const char CommentsGenerationOption[] = "COPY_COMMENTS";

View File

@ -7,7 +7,7 @@
#include <string>
namespace QtProtobuf::generator {
namespace qtprotoccommon {
/*!
\ingroup generator

View File

@ -5,8 +5,6 @@
#include "utils.h"
#include <sstream>
#include <algorithm>
#include <string>
#include <string_view>
#include <ctype.h>
@ -16,7 +14,7 @@ namespace {
const std::string_view asciiSpacing = " \t\n\r\f\v";
}
namespace QtProtobuf::generator::utils {
namespace qtprotoccommon::utils {
bool isAsciiAlpha(char c)
{
@ -177,4 +175,4 @@ size_t count(std::string_view s, char c)
{
return std::count(s.begin(), s.end(), c);
}
} // namespace QtProtobuf::generator::utils
} // namespace qtprotoccommon::utils

View File

@ -7,8 +7,6 @@
#include <string>
#include <vector>
#include <unordered_map>
#include <list>
#include <algorithm>
#ifdef QT_PROTOBUF_DEBUG_GENERATOR
@ -22,7 +20,7 @@ namespace google::protobuf {
class FileDescriptor;
}
namespace QtProtobuf::generator {
namespace qtprotoccommon {
namespace utils {
std::vector<std::string> split(std::string_view s, std::string_view c, bool keepEmpty = false);
std::string replace(std::string_view where, std::string_view from, std::string_view to);
@ -68,6 +66,5 @@ std::string join(const T &container, std::string_view separator, std::string_vie
size_t count(std::string_view s, char c);
} // namespace utils
} // namespace QtProtobuf::generator
} // namespace qtprotoccommon
#endif // QTPROTOBUFGEN_UTILS_H

View File

@ -4,6 +4,7 @@
add_subdirectory(protobuf)
if(QT_FEATURE_qtprotobufgen AND NOT CMAKE_CROSSCOMPILING)
add_subdirectory(protobufgen)
add_subdirectory(grpcgen)
endif()
if(QT_FEATURE_grpc)

View File

@ -11,10 +11,14 @@ qt6_add_protobuf(tst_grpc_client_qtgrpc_gen
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
)
target_link_libraries(tst_grpc_client_qtgrpc_gen PRIVATE Qt::Grpc)
qt6_add_grpc(tst_grpc_client_qtgrpc_gen CLIENT
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
)
qt_autogen_tools_initial_setup(tst_grpc_client_qtgrpc_gen)
qt_internal_add_test(tst_grpc_client
SOURCES
tst_grpc_client.cpp
@ -24,7 +28,6 @@ qt_internal_add_test(tst_grpc_client
Qt::Test
Qt::Core
Qt::Grpc
WrapgRPC::WrapLibgRPC
tst_grpc_client_qtgrpc_gen
)

View File

@ -2,12 +2,18 @@
# SPDX-License-Identifier: BSD-3-Clause
qt6_add_protobuf(tst_grpc_server_qtgrpc_gen
OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
)
qt6_add_grpc(tst_grpc_server_qtgrpc_gen CLIENT
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
)
target_link_libraries(tst_grpc_server_qtgrpc_gen PRIVATE Qt::Grpc)
qt_autogen_tools_initial_setup(tst_grpc_server_qtgrpc_gen)

View File

@ -6,12 +6,17 @@ if(NOT TARGET securetestserver)
endif()
qt6_add_protobuf(tst_grpc_ssl_client_qtgrpc_gen
OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
)
qt6_add_grpc(tst_grpc_ssl_client_qtgrpc_gen CLIENT
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
)
target_link_libraries(tst_grpc_ssl_client_qtgrpc_gen PRIVATE Qt::Grpc)
qt_autogen_tools_initial_setup(tst_grpc_ssl_client_qtgrpc_gen)
@ -25,7 +30,6 @@ qt_internal_add_test(tst_grpc_ssl_client
Qt::Core
Qt::Grpc
Qt::Network
WrapgRPC::WrapLibgRPC
tst_grpc_ssl_client_qtgrpc_gen
)

View File

@ -2,13 +2,17 @@
# SPDX-License-Identifier: BSD-3-Clause
qt6_add_protobuf(tst_grpc_unattached_channel_qtgrpc_gen
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
)
qt6_add_grpc(tst_grpc_unattached_channel_qtgrpc_gen CLIENT
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated"
PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../shared/proto/testservice.proto
)
target_link_libraries(tst_grpc_unattached_channel_qtgrpc_gen PRIVATE Qt::Grpc)
qt_autogen_tools_initial_setup(tst_grpc_unattached_channel_qtgrpc_gen)
qt_internal_add_test(tst_grpc_unattached_channel

View File

@ -0,0 +1,17 @@
# Blacklist for testing on ARM macos due to QTBUG-109130
[initTestCase]
macos arm ci
[cmakeGeneratedFile_data]
macos arm ci
[cmakeGeneratedFile]
macos arm ci
[cmdLineGeneratedFile_data]
macos arm ci
[cmdLineGeneratedFile]
macos arm ci
[cmdLineGeneratedNoOptions_data]
macos arm ci
[cmdLineGeneratedNoOptions]
macos arm ci
[cleanupTestCase]
macos arm ci

View File

@ -0,0 +1,30 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_test(tst_qtgrpcgen
SOURCES
tst_qtgrpcgen.cpp
LIBRARIES
Qt::Test
Qt::Protobuf
Qt::Grpc
DEFINES
PROTOC_EXECUTABLE="$<TARGET_FILE:WrapProtoc::WrapProtoc>"
)
qt_add_protobuf(tst_qtgrpcgen
OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated/folder"
GENERATE_PACKAGE_SUBFOLDERS
PROTO_FILES
../shared/data/proto/testservice.proto
)
qt_add_grpc(tst_qtgrpcgen CLIENT
PROTO_FILES
../shared/data/proto/testservice.proto
GENERATE_PACKAGE_SUBFOLDERS
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_grpc_generated/folder"
)
qt_autogen_tools_initial_setup(tst_qtgrpcgen)

View File

@ -0,0 +1,255 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#include "qtgrpc/tests/testservice.qpb.h"
#include <QProtobufSerializer>
namespace qtgrpc::tests {
SimpleStringMessage::~SimpleStringMessage() = default;
static constexpr struct {
QtProtobufPrivate::QProtobufPropertyOrdering::Data data;
const std::array<uint, 5> qt_protobuf_SimpleStringMessage_uint_data;
const char qt_protobuf_SimpleStringMessage_char_data[50];
} qt_protobuf_SimpleStringMessage_metadata {
// data
{
0, /* = version */
1, /* = num fields */
2, /* = field number offset */
3, /* = property index offset */
4, /* = field flags offset */
32, /* = message full name length */
},
// uint_data
{
// JSON name offsets:
33, /* = testFieldString */
49, /* = end-of-string-marker */
// Field numbers:
6, /* = testFieldString */
// Property indices:
0, /* = testFieldString */
// Field flags:
QtProtobufPrivate::NoFlags, /* = testFieldString */
},
// char_data
/* metadata char_data: */
"qtgrpc.tests.SimpleStringMessage\0" /* = full message name */
/* field char_data: */
"testFieldString\0"
};
const QtProtobufPrivate::QProtobufPropertyOrdering SimpleStringMessage::propertyOrdering = {
&qt_protobuf_SimpleStringMessage_metadata.data
};
void SimpleStringMessage::registerTypes()
{
qRegisterMetaType<SimpleStringMessage>();
qRegisterMetaType<SimpleStringMessageRepeated>();
}
SimpleStringMessage::SimpleStringMessage() : QProtobufMessage(&SimpleStringMessage::staticMetaObject)
{
}
SimpleStringMessage::SimpleStringMessage(const SimpleStringMessage &other) : QProtobufMessage(other)
{
setTestFieldString(other.m_testFieldString);
}
SimpleStringMessage &SimpleStringMessage::operator =(const SimpleStringMessage &other)
{
QProtobufMessage::operator=(other);
setTestFieldString(other.m_testFieldString);
return *this;
}
SimpleStringMessage::SimpleStringMessage(SimpleStringMessage &&other) noexcept : QProtobufMessage(std::move(other))
{
m_testFieldString = std::move(other.m_testFieldString);
}
SimpleStringMessage &SimpleStringMessage::operator =(SimpleStringMessage &&other) noexcept
{
QProtobufMessage::operator=(std::move(other));
if (m_testFieldString != other.m_testFieldString)
m_testFieldString = std::move(other.m_testFieldString);
return *this;
}
bool SimpleStringMessage::operator ==(const SimpleStringMessage &other) const
{
return QProtobufMessage::isEqual(*this, other)
&& m_testFieldString == other.m_testFieldString;
}
bool SimpleStringMessage::operator !=(const SimpleStringMessage &other) const
{
return !this->operator ==(other);
}
void SimpleStringMessage::setTestFieldString(const QString &testFieldString)
{
if (m_testFieldString != testFieldString)
m_testFieldString = testFieldString;
}
SimpleIntMessage::~SimpleIntMessage() = default;
static constexpr struct {
QtProtobufPrivate::QProtobufPropertyOrdering::Data data;
const std::array<uint, 5> qt_protobuf_SimpleIntMessage_uint_data;
const char qt_protobuf_SimpleIntMessage_char_data[41];
} qt_protobuf_SimpleIntMessage_metadata {
// data
{
0, /* = version */
1, /* = num fields */
2, /* = field number offset */
3, /* = property index offset */
4, /* = field flags offset */
29, /* = message full name length */
},
// uint_data
{
// JSON name offsets:
30, /* = testField */
40, /* = end-of-string-marker */
// Field numbers:
1, /* = testField */
// Property indices:
0, /* = testField */
// Field flags:
QtProtobufPrivate::NoFlags, /* = testField */
},
// char_data
/* metadata char_data: */
"qtgrpc.tests.SimpleIntMessage\0" /* = full message name */
/* field char_data: */
"testField\0"
};
const QtProtobufPrivate::QProtobufPropertyOrdering SimpleIntMessage::propertyOrdering = {
&qt_protobuf_SimpleIntMessage_metadata.data
};
void SimpleIntMessage::registerTypes()
{
qRegisterMetaType<SimpleIntMessage>();
qRegisterMetaType<SimpleIntMessageRepeated>();
}
SimpleIntMessage::SimpleIntMessage() : QProtobufMessage(&SimpleIntMessage::staticMetaObject),
m_testField(0)
{
}
SimpleIntMessage::SimpleIntMessage(const SimpleIntMessage &other) : QProtobufMessage(other)
{
setTestField(other.m_testField);
}
SimpleIntMessage &SimpleIntMessage::operator =(const SimpleIntMessage &other)
{
QProtobufMessage::operator=(other);
setTestField(other.m_testField);
return *this;
}
SimpleIntMessage::SimpleIntMessage(SimpleIntMessage &&other) noexcept : QProtobufMessage(std::move(other))
{
setTestField(std::exchange(other.m_testField, 0));
}
SimpleIntMessage &SimpleIntMessage::operator =(SimpleIntMessage &&other) noexcept
{
QProtobufMessage::operator=(std::move(other));
setTestField(std::exchange(other.m_testField, 0));
return *this;
}
bool SimpleIntMessage::operator ==(const SimpleIntMessage &other) const
{
return QProtobufMessage::isEqual(*this, other)
&& m_testField == other.m_testField;
}
bool SimpleIntMessage::operator !=(const SimpleIntMessage &other) const
{
return !this->operator ==(other);
}
BlobMessage::~BlobMessage() = default;
static constexpr struct {
QtProtobufPrivate::QProtobufPropertyOrdering::Data data;
const std::array<uint, 5> qt_protobuf_BlobMessage_uint_data;
const char qt_protobuf_BlobMessage_char_data[36];
} qt_protobuf_BlobMessage_metadata {
// data
{
0, /* = version */
1, /* = num fields */
2, /* = field number offset */
3, /* = property index offset */
4, /* = field flags offset */
24, /* = message full name length */
},
// uint_data
{
// JSON name offsets:
25, /* = testBytes */
35, /* = end-of-string-marker */
// Field numbers:
1, /* = testBytes */
// Property indices:
0, /* = testBytes */
// Field flags:
QtProtobufPrivate::NoFlags, /* = testBytes */
},
// char_data
/* metadata char_data: */
"qtgrpc.tests.BlobMessage\0" /* = full message name */
/* field char_data: */
"testBytes\0"
};
const QtProtobufPrivate::QProtobufPropertyOrdering BlobMessage::propertyOrdering = {
&qt_protobuf_BlobMessage_metadata.data
};
void BlobMessage::registerTypes()
{
qRegisterMetaType<BlobMessage>();
qRegisterMetaType<BlobMessageRepeated>();
}
BlobMessage::BlobMessage() : QProtobufMessage(&BlobMessage::staticMetaObject)
{
}
BlobMessage::BlobMessage(const BlobMessage &other) : QProtobufMessage(other)
{
setTestBytes(other.m_testBytes);
}
BlobMessage &BlobMessage::operator =(const BlobMessage &other)
{
QProtobufMessage::operator=(other);
setTestBytes(other.m_testBytes);
return *this;
}
BlobMessage::BlobMessage(BlobMessage &&other) noexcept : QProtobufMessage(std::move(other))
{
m_testBytes = std::move(other.m_testBytes);
}
BlobMessage &BlobMessage::operator =(BlobMessage &&other) noexcept
{
QProtobufMessage::operator=(std::move(other));
if (m_testBytes != other.m_testBytes)
m_testBytes = std::move(other.m_testBytes);
return *this;
}
bool BlobMessage::operator ==(const BlobMessage &other) const
{
return QProtobufMessage::isEqual(*this, other)
&& m_testBytes == other.m_testBytes;
}
bool BlobMessage::operator !=(const BlobMessage &other) const
{
return !this->operator ==(other);
}
void BlobMessage::setTestBytes(const QByteArray &testBytes)
{
if (m_testBytes != testBytes)
m_testBytes = testBytes;
}
} // namespace qtgrpc::tests
#include "moc_testservice.qpb.cpp"

View File

@ -0,0 +1,137 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#ifndef Q_PROTOBUF_testservice_H
#define Q_PROTOBUF_testservice_H
#include <QtProtobuf/QProtobufMessage>
#include <QtCore/QMetaType>
#include <QtCore/QList>
#include <QtProtobuf/qprotobufobject.h>
#include <QtProtobuf/qprotobuflazymessagepointer.h>
#include <memory>
#include <QByteArray>
#include <QString>
namespace qtgrpc::tests {
class SimpleStringMessage;
using SimpleStringMessageRepeated = QList<std::shared_ptr<SimpleStringMessage>>;
class SimpleIntMessage;
using SimpleIntMessageRepeated = QList<std::shared_ptr<SimpleIntMessage>>;
class BlobMessage;
using BlobMessageRepeated = QList<std::shared_ptr<BlobMessage>>;
class SimpleStringMessage : public QProtobufMessage
{
Q_GADGET
Q_PROTOBUF_OBJECT
Q_DECLARE_PROTOBUF_SERIALIZERS(SimpleStringMessage)
Q_PROPERTY(QString testFieldString READ testFieldString WRITE setTestFieldString SCRIPTABLE true)
public:
enum QtProtobufFieldEnum {
TestFieldStringProtoFieldNumber = 6,
};
Q_ENUM(QtProtobufFieldEnum)
SimpleStringMessage();
~SimpleStringMessage() override;
SimpleStringMessage(const SimpleStringMessage &other);
SimpleStringMessage &operator =(const SimpleStringMessage &other);
SimpleStringMessage(SimpleStringMessage &&other) noexcept;
SimpleStringMessage &operator =(SimpleStringMessage &&other) noexcept;
bool operator ==(const SimpleStringMessage &other) const;
bool operator !=(const SimpleStringMessage &other) const;
QString testFieldString() const {
return m_testFieldString;
}
void setTestFieldString(const QString &testFieldString);
static void registerTypes();
private:
QString m_testFieldString;
};
class SimpleIntMessage : public QProtobufMessage
{
Q_GADGET
Q_PROTOBUF_OBJECT
Q_DECLARE_PROTOBUF_SERIALIZERS(SimpleIntMessage)
Q_PROPERTY(QtProtobuf::sint32 testField READ testField WRITE setTestField SCRIPTABLE true)
public:
enum QtProtobufFieldEnum {
TestFieldProtoFieldNumber = 1,
};
Q_ENUM(QtProtobufFieldEnum)
SimpleIntMessage();
~SimpleIntMessage() override;
SimpleIntMessage(const SimpleIntMessage &other);
SimpleIntMessage &operator =(const SimpleIntMessage &other);
SimpleIntMessage(SimpleIntMessage &&other) noexcept;
SimpleIntMessage &operator =(SimpleIntMessage &&other) noexcept;
bool operator ==(const SimpleIntMessage &other) const;
bool operator !=(const SimpleIntMessage &other) const;
QtProtobuf::sint32 testField() const {
return m_testField;
}
void setTestField(const QtProtobuf::sint32 &testField) {
if (m_testField != testField)
m_testField = testField;
}
static void registerTypes();
private:
QtProtobuf::sint32 m_testField;
};
class BlobMessage : public QProtobufMessage
{
Q_GADGET
Q_PROTOBUF_OBJECT
Q_DECLARE_PROTOBUF_SERIALIZERS(BlobMessage)
Q_PROPERTY(QByteArray testBytes READ testBytes WRITE setTestBytes SCRIPTABLE true)
public:
enum QtProtobufFieldEnum {
TestBytesProtoFieldNumber = 1,
};
Q_ENUM(QtProtobufFieldEnum)
BlobMessage();
~BlobMessage() override;
BlobMessage(const BlobMessage &other);
BlobMessage &operator =(const BlobMessage &other);
BlobMessage(BlobMessage &&other) noexcept;
BlobMessage &operator =(BlobMessage &&other) noexcept;
bool operator ==(const BlobMessage &other) const;
bool operator !=(const BlobMessage &other) const;
QByteArray testBytes() const {
return m_testBytes;
}
void setTestBytes(const QByteArray &testBytes);
static void registerTypes();
private:
QByteArray m_testBytes;
};
} // namespace qtgrpc::tests
Q_DECLARE_METATYPE(qtgrpc::tests::SimpleStringMessage)
Q_DECLARE_METATYPE(qtgrpc::tests::SimpleIntMessage)
Q_DECLARE_METATYPE(qtgrpc::tests::BlobMessage)
#endif // Q_PROTOBUF_testservice_H

View File

@ -0,0 +1,65 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#include "qtgrpc/tests/testservice_client.grpc.qpb.h"
namespace qtgrpc::tests {
namespace TestService {
Client::Client(QObject *parent) : QAbstractGrpcClient("qtgrpc.tests.TestService", parent)
{
}
QGrpcStatus Client::testMethod(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethod", arg, ret);
}
std::shared_ptr<QGrpcCallReply> Client::testMethod(const qtgrpc::tests::SimpleStringMessage &arg)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethod", arg);
}
void Client::testMethod(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback)
{
std::shared_ptr<QGrpcCallReply> reply = call<qtgrpc::tests::SimpleStringMessage>("testMethod", arg);
QObject::connect(reply.get(), &QGrpcCallReply::finished, context, [reply, callback]() {
callback(reply);
});
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodServerStream", arg);
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodServerStream", arg, ret);
}
QGrpcStatus Client::testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethodClientStream", arg, ret);
}
std::shared_ptr<QGrpcCallReply> Client::testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethodClientStream", arg);
}
void Client::testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback)
{
std::shared_ptr<QGrpcCallReply> reply = call<qtgrpc::tests::SimpleStringMessage>("testMethodClientStream", arg);
QObject::connect(reply.get(), &QGrpcCallReply::finished, context, [reply, callback]() {
callback(reply);
});
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodBiStream", arg);
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodBiStream", arg, ret);
}
} // namespace TestService
} // namespace qtgrpc::tests

View File

@ -0,0 +1,52 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#ifndef Q_PROTOBUF_testservice_client_H
#define Q_PROTOBUF_testservice_client_H
#include <QtProtobuf/QProtobufMessage>
#include <QtCore/QMetaType>
#include <QtCore/QList>
#include <QtProtobuf/qprotobufobject.h>
#include <QtProtobuf/qprotobuflazymessagepointer.h>
#include <memory>
#include <QAbstractGrpcClient>
#include <QGrpcCallReply>
#include <QGrpcStream>
#include "qtgrpc/tests/testservice.qpb.h"
namespace qtgrpc::tests {
namespace TestService {
class Client : public QAbstractGrpcClient
{
Q_OBJECT
public:
explicit Client(QObject *parent = nullptr);
QGrpcStatus testMethod(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret);
std::shared_ptr<QGrpcCallReply> testMethod(const qtgrpc::tests::SimpleStringMessage &arg);
Q_INVOKABLE void testMethod(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback);
std::shared_ptr<QGrpcStream> streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg);
std::shared_ptr<QGrpcStream> streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret);
QGrpcStatus testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret);
std::shared_ptr<QGrpcCallReply> testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg);
Q_INVOKABLE void testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback);
std::shared_ptr<QGrpcStream> streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg);
std::shared_ptr<QGrpcStream> streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret);
private:
};
} // namespace TestService
} // namespace qtgrpc::tests
#endif // Q_PROTOBUF_testservice_client_H

View File

@ -0,0 +1,10 @@
#include <QProtobufSerializer>
#include <array>
#include "qtgrpc/tests/testservice.qpb.h"
namespace qtgrpc::tests {
static QtProtobuf::ProtoTypeRegistrar ProtoTypeRegistrarSimpleStringMessage(qRegisterProtobufType<SimpleStringMessage>);
static QtProtobuf::ProtoTypeRegistrar ProtoTypeRegistrarSimpleIntMessage(qRegisterProtobufType<SimpleIntMessage>);
static QtProtobuf::ProtoTypeRegistrar ProtoTypeRegistrarBlobMessage(qRegisterProtobufType<BlobMessage>);
} // namespace qtgrpc::tests

View File

@ -0,0 +1,39 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#ifndef Q_PROTOBUF_testservice_service_H
#define Q_PROTOBUF_testservice_service_H
#include <QtProtobuf/QProtobufMessage>
#include <QtCore/QMetaType>
#include <QtCore/QList>
#include <QtProtobuf/qprotobufobject.h>
#include <QtProtobuf/qprotobuflazymessagepointer.h>
#include <memory>
#include <QAbstractGrpcClient>
#include <QGrpcCallReply>
#include <QGrpcStream>
#include <QAbstractGrpcService>
#include "qtgrpc/tests/testservice.qpb.h"
namespace qtgrpc::tests {
namespace TestService {
class Service : public QAbstractGrpcService
{
Q_OBJECT
public:
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethod(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
};
} // namespace TestService
} // namespace qtgrpc::tests
#endif // Q_PROTOBUF_testservice_service_H

View File

@ -0,0 +1,65 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#include "testservice_client.grpc.qpb.h"
namespace qtgrpc::tests {
namespace TestService {
Client::Client(QObject *parent) : QAbstractGrpcClient("qtgrpc.tests.TestService", parent)
{
}
QGrpcStatus Client::testMethod(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethod", arg, ret);
}
std::shared_ptr<QGrpcCallReply> Client::testMethod(const qtgrpc::tests::SimpleStringMessage &arg)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethod", arg);
}
void Client::testMethod(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback)
{
std::shared_ptr<QGrpcCallReply> reply = call<qtgrpc::tests::SimpleStringMessage>("testMethod", arg);
QObject::connect(reply.get(), &QGrpcCallReply::finished, context, [reply, callback]() {
callback(reply);
});
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodServerStream", arg);
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodServerStream", arg, ret);
}
QGrpcStatus Client::testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethodClientStream", arg, ret);
}
std::shared_ptr<QGrpcCallReply> Client::testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg)
{
return call<qtgrpc::tests::SimpleStringMessage>("testMethodClientStream", arg);
}
void Client::testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback)
{
std::shared_ptr<QGrpcCallReply> reply = call<qtgrpc::tests::SimpleStringMessage>("testMethodClientStream", arg);
QObject::connect(reply.get(), &QGrpcCallReply::finished, context, [reply, callback]() {
callback(reply);
});
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodBiStream", arg);
}
std::shared_ptr<QGrpcStream> Client::streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret)
{
return stream<qtgrpc::tests::SimpleStringMessage>("testMethodBiStream", arg, ret);
}
} // namespace TestService
} // namespace qtgrpc::tests

View File

@ -0,0 +1,52 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#ifndef Q_PROTOBUF_testservice_client_H
#define Q_PROTOBUF_testservice_client_H
#include <QtProtobuf/QProtobufMessage>
#include <QtCore/QMetaType>
#include <QtCore/QList>
#include <QtProtobuf/qprotobufobject.h>
#include <QtProtobuf/qprotobuflazymessagepointer.h>
#include <memory>
#include <QAbstractGrpcClient>
#include <QGrpcCallReply>
#include <QGrpcStream>
#include "testservice.qpb.h"
namespace qtgrpc::tests {
namespace TestService {
class Client : public QAbstractGrpcClient
{
Q_OBJECT
public:
explicit Client(QObject *parent = nullptr);
QGrpcStatus testMethod(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret);
std::shared_ptr<QGrpcCallReply> testMethod(const qtgrpc::tests::SimpleStringMessage &arg);
Q_INVOKABLE void testMethod(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback);
std::shared_ptr<QGrpcStream> streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg);
std::shared_ptr<QGrpcStream> streamTestMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret);
QGrpcStatus testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, qtgrpc::tests::SimpleStringMessage *ret);
std::shared_ptr<QGrpcCallReply> testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg);
Q_INVOKABLE void testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg, const QObject *context, const std::function<void(std::shared_ptr<QGrpcCallReply>)> &callback);
std::shared_ptr<QGrpcStream> streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg);
std::shared_ptr<QGrpcStream> streamTestMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg, const QWeakPointer<qtgrpc::tests::SimpleStringMessage> &ret);
private:
};
} // namespace TestService
} // namespace qtgrpc::tests
#endif // Q_PROTOBUF_testservice_client_H

View File

@ -0,0 +1,39 @@
/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */
#ifndef Q_PROTOBUF_testservice_service_H
#define Q_PROTOBUF_testservice_service_H
#include <QtProtobuf/QProtobufMessage>
#include <QtCore/QMetaType>
#include <QtCore/QList>
#include <QtProtobuf/qprotobufobject.h>
#include <QtProtobuf/qprotobuflazymessagepointer.h>
#include <memory>
#include <QAbstractGrpcClient>
#include <QGrpcCallReply>
#include <QGrpcStream>
#include <QAbstractGrpcService>
#include "testservice.qpb.h"
namespace qtgrpc::tests {
namespace TestService {
class Service : public QAbstractGrpcService
{
Q_OBJECT
public:
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethod(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethodServerStream(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethodClientStream(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
Q_INVOKABLE virtual qtgrpc::tests::SimpleStringMessage testMethodBiStream(const qtgrpc::tests::SimpleStringMessage &arg) = 0;
};
} // namespace TestService
} // namespace qtgrpc::tests
#endif // Q_PROTOBUF_testservice_service_H

View File

@ -0,0 +1,314 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtTest/QtTest>
#include <QString>
#include <QProcess>
#include <QCryptographicHash>
#include <qtprotobuftypes.h>
#define XSTR(x) DEFSTR(x)
#define DEFSTR(x) #x
using namespace Qt::StringLiterals;
const QLatin1StringView serviceHeaderExtension("_service.grpc.qpb.h");
const QLatin1StringView cppExtension("_client.grpc.qpb.cpp");
const QLatin1StringView headerExtension("_client.grpc.qpb.h");
const QLatin1StringView grpcGenQtprotobufKey(" --plugin=protoc-gen-qtgrpc=");
const QLatin1StringView optKey(" --qtgrpc_opt=");
const QLatin1StringView outputKey(" --qtgrpc_out=");
const QLatin1StringView includeKey(" -I");
#if defined(PROTOC_EXECUTABLE)
const QLatin1StringView protocolBufferCompiler(XSTR(PROTOC_EXECUTABLE));
#else
#if defined(Q_OS_WIN)
const QLatin1StringView protocolBufferCompiler("protoc.exe");
#else
const QLatin1StringView protocolBufferCompiler("protoc");
#endif
#endif
#if defined(Q_OS_WIN)
const QLatin1StringView qtgrpcgen("/qtgrpcgen.exe");
#else
const QLatin1StringView qtgrpcgen("/qtgrpcgen");
#endif
QByteArray msgProcessStartFailed(const QProcess &p)
{
const QString result = QLatin1StringView("Could not start \"")
+ QDir::toNativeSeparators(p.program()) + QLatin1StringView("\": ")
+ p.errorString();
return result.toLocal8Bit();
}
QByteArray msgProcessTimeout(const QProcess &p)
{
return '"' + QDir::toNativeSeparators(p.program()).toLocal8Bit()
+ "\" timed out.";
}
QByteArray msgProcessCrashed(QProcess &p)
{
return '"' + QDir::toNativeSeparators(p.program()).toLocal8Bit()
+ "\" crashed.\n" + p.readAllStandardError();
}
QByteArray msgProcessFailed(QProcess &p)
{
return '"' + QDir::toNativeSeparators(p.program()).toLocal8Bit()
+ "\" returned " + QByteArray::number(p.exitCode()) + ":\n"
+ p.readAllStandardError();
}
QByteArray hash(const QByteArray &fileData)
{
return QCryptographicHash::hash(fileData, QCryptographicHash::Sha1);
}
QByteArrayList splitToLines(const QByteArray &data)
{
return data.split('\n');
}
// Return size diff and first NOT equal line;
QByteArray doCompare(const QByteArrayList &actual, const QByteArrayList &expected)
{
QByteArray ba;
if (actual.size() != expected.size()) {
ba.append(QString("Length count different: actual: %1, expected: %2")
.arg(actual.size()).arg(expected.size()).toUtf8());
}
for (int i = 0, n = expected.size(); i != n; ++i) {
QString expectedLine = expected.at(i);
if (expectedLine != actual.at(i)) {
ba.append("\n<<<<<< ACTUAL\n" + actual.at(i)
+ "\n======\n" + expectedLine.toUtf8()
+ "\n>>>>>> EXPECTED\n"
);
break;
}
}
return ba;
}
QByteArray msgCannotReadFile(const QFile &file)
{
const QString result = QLatin1StringView("Could not read file: ")
+ QDir::toNativeSeparators(file.fileName())
+ QLatin1StringView(": ") + file.errorString();
return result.toLocal8Bit();
}
void cleanFolder(const QString &folderName)
{
QDir dir(folderName);
dir.removeRecursively();
}
bool protocolCompilerAvailableToRun()
{
QProcess protoc;
protoc.startCommand(protocolBufferCompiler + " --version");
if (!protoc.waitForStarted())
return false;
if (!protoc.waitForFinished()) {
protoc.kill();
return false;
}
return protoc.exitStatus() == QProcess::NormalExit;
}
class tst_qtgrpcgen : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
//! Test qt_add_grpc() cmake function
void cmakeGeneratedFile_data();
void cmakeGeneratedFile();
//! Test command-line call of qtgrpcgen
void cmdLineGeneratedFile_data();
void cmdLineGeneratedFile();
void cleanupTestCase();
private:
QString m_grpcgen;
QString m_cmakeGenerated;
QString m_commandLineGenerated;
QString m_expectedResult;
QString m_protoFiles;
};
void tst_qtgrpcgen::initTestCase()
{
m_grpcgen = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) + qtgrpcgen;
m_cmakeGenerated = QFINDTESTDATA("qt_grpc_generated");
QVERIFY(!m_cmakeGenerated.isEmpty());
m_expectedResult = QFINDTESTDATA("data/expected_result");
QVERIFY(!m_expectedResult.isEmpty());
m_protoFiles = QFINDTESTDATA("../shared/data/proto/");
QVERIFY(!m_protoFiles.isEmpty());
QDir testOutputBaseDir(QCoreApplication::applicationDirPath());
testOutputBaseDir.mkdir(QLatin1StringView("cmd_line_generation"));
QLatin1StringView folders[] = {"comments"_L1, "extra-namespace"_L1,
"fieldenum"_L1, "folder"_L1, "no-options"_L1};
for (QLatin1StringView folder : folders)
testOutputBaseDir.mkdir("cmd_line_generation/"_L1 + folder);
m_commandLineGenerated = testOutputBaseDir.absolutePath() +
QLatin1StringView("/cmd_line_generation");
QVERIFY(!m_commandLineGenerated.isEmpty());
#ifdef Q_OS_MACOS
if (!protocolCompilerAvailableToRun())
QSKIP("Protocol buffer compiler is not provisioned for macOS ARM VMs: QTBUG-109130");
#else
QVERIFY(protocolCompilerAvailableToRun());
#endif
}
void tst_qtgrpcgen::cmakeGeneratedFile_data()
{
QTest::addColumn<QString>("fileName");
QTest::addColumn<QString>("folder");
QTest::addColumn<QString>("extension");
const QLatin1StringView extensions[]
= {serviceHeaderExtension, cppExtension, headerExtension};
for (const auto extension : extensions) {
QTest::addRow("testservice%s", extension.data())
<< "testservice"
<< "/folder/qtgrpc/tests/"
<< QString(extension);
}
}
void tst_qtgrpcgen::cmakeGeneratedFile()
{
QFETCH(QString, fileName);
QFETCH(QString, folder);
QFETCH(QString, extension);
QFile expectedResultFile(m_expectedResult + folder + fileName + extension);
QFile generatedFile(m_cmakeGenerated + folder + fileName + extension);
QVERIFY(expectedResultFile.exists());
QVERIFY(generatedFile.exists());
QVERIFY2(expectedResultFile.open(QIODevice::ReadOnly | QIODevice::Text),
msgCannotReadFile(expectedResultFile).constData());
QVERIFY2(generatedFile.open(QIODevice::ReadOnly | QIODevice::Text),
msgCannotReadFile(generatedFile).constData());
QByteArray expectedData = expectedResultFile.readAll();
QByteArray generatedData = generatedFile.readAll();
expectedResultFile.close();
generatedFile.close();
if (hash(expectedData).toHex() != hash(generatedData).toHex())
{
const QString diff = doCompare(splitToLines(generatedData),
splitToLines(expectedData));
QCOMPARE_GT(diff.size(), 0); // Hashes can only differ if content does.
QFAIL(qPrintable(diff));
}
// Ensure we do see a failure, even in the unlikely case of a hash collision:
QVERIFY(generatedData == expectedData);
}
void tst_qtgrpcgen::cmdLineGeneratedFile_data()
{
QTest::addColumn<QString>("fileName");
QTest::addColumn<QString>("folder");
QTest::addColumn<QString>("extension");
const QLatin1StringView extensions[]
= {serviceHeaderExtension, cppExtension, headerExtension};
for (const auto extension : extensions) {
QTest::addRow("testservice%s", extension.data())
<< "testservice"
<< "/no-options/"
<< QString(extension);
}
}
void tst_qtgrpcgen::cmdLineGeneratedFile()
{
QFETCH(QString, fileName);
QFETCH(QString, folder);
QFETCH(QString, extension);
QProcess process;
process.setWorkingDirectory(m_commandLineGenerated);
/* Call command:
protoc --plugin=protoc-gen-qtgrpc=<path/to/bin/>qtgrpcgen \
--qtgrpc_opt=<option> \
--qtgrpc_out=<output_dir> [-I/extra/proto/include/path] <protofile>.proto */
process.startCommand(protocolBufferCompiler + QString(" ")
+ grpcGenQtprotobufKey + m_grpcgen
+ optKey + outputKey
+ m_commandLineGenerated + folder
+ includeKey + m_protoFiles
+ " " + fileName + ".proto");
QVERIFY2(process.waitForStarted(), msgProcessStartFailed(process).constData());
if (!process.waitForFinished()) {
process.kill();
QFAIL(msgProcessTimeout(process).constData());
}
QVERIFY2(process.exitStatus() == QProcess::NormalExit, msgProcessCrashed(process).constData());
QVERIFY2(process.exitCode() == 0, msgProcessFailed(process).constData());
QFile expectedResultFile(m_expectedResult + folder + fileName + extension);
QFile generatedFile(m_commandLineGenerated + folder + fileName + extension);
QVERIFY(generatedFile.exists());
QVERIFY(expectedResultFile.exists());
QVERIFY2(expectedResultFile.open(QIODevice::ReadOnly | QIODevice::Text),
msgCannotReadFile(expectedResultFile).constData());
QVERIFY2(generatedFile.open(QIODevice::ReadOnly | QIODevice::Text),
msgCannotReadFile(generatedFile).constData());
QByteArray expectedData = expectedResultFile.readAll();
QByteArray generatedData = generatedFile.readAll();
expectedResultFile.close();
generatedFile.close();
if (hash(expectedData).toHex() != hash(generatedData).toHex())
{
const QString diff = doCompare(splitToLines(generatedData),
splitToLines(expectedData));
QCOMPARE_GT(diff.size(), 0); // Hashes can only differ if content does.
QFAIL(qPrintable(diff));
}
// Ensure we do see a failure, even in the unlikely case of a hash collision:
QVERIFY(generatedData == expectedData);
}
void tst_qtgrpcgen::cleanupTestCase()
{
// Leave this function at the bottom. It removes generated content.
cleanFolder(m_commandLineGenerated);
}
QTEST_MAIN(tst_qtgrpcgen)
#include "tst_qtgrpcgen.moc"

View File

@ -148,6 +148,7 @@ qt_internal_add_test(tst_protobuf_non_packed_repeatedtypes
LIBRARIES
Qt::Test
Qt::CorePrivate
Qt::Protobuf
)
qt6_add_protobuf(tst_protobuf_non_packed_repeatedtypes
PROTO_FILES

View File

@ -1,4 +1,4 @@
# Blacklist for testing
# Blacklist for testing on ARM macos due to QTBUG-109130
[initTestCase]
macos arm ci
[cmakeGeneratedFile_data]

View File

@ -0,0 +1,22 @@
syntax = "proto3";
package qtgrpc.tests;
message SimpleStringMessage {
string testFieldString = 6;
}
message SimpleIntMessage {
sint32 testField= 1;
}
message BlobMessage {
bytes testBytes = 1;
}
service TestService {
rpc testMethod(SimpleStringMessage) returns (SimpleStringMessage) {}
rpc testMethodServerStream(SimpleStringMessage) returns (stream SimpleStringMessage) {}
rpc testMethodClientStream(stream SimpleStringMessage) returns (SimpleStringMessage) {}
rpc testMethodBiStream(stream SimpleStringMessage) returns (stream SimpleStringMessage) {}
}