parent
fd14316f38
commit
306123e2e8
35 changed files with 4480 additions and 10 deletions
@ -0,0 +1,98 @@ |
|||||||
|
# Copyright (c) 2009-2021, Google LLC |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are met: |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer in the |
||||||
|
# documentation and/or other materials provided with the distribution. |
||||||
|
# * Neither the name of Google LLC nor the |
||||||
|
# names of its contributors may be used to endorse or promote products |
||||||
|
# derived from this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY |
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
load( |
||||||
|
"//bazel:build_defs.bzl", |
||||||
|
"UPB_DEFAULT_CPPOPTS", |
||||||
|
) |
||||||
|
load( |
||||||
|
"//protos/bazel:upb_cc_proto_library.bzl", |
||||||
|
"upb_cc_proto_library_copts", |
||||||
|
) |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
cc_library( |
||||||
|
name = "protos", |
||||||
|
srcs = ["protos.cc"], |
||||||
|
hdrs = ["protos.h"], |
||||||
|
copts = UPB_DEFAULT_CPPOPTS, |
||||||
|
visibility = ["//visibility:public"], |
||||||
|
deps = [ |
||||||
|
"//:mini_table", |
||||||
|
"//:upb", |
||||||
|
"@com_google_absl//absl/status", |
||||||
|
"@com_google_absl//absl/status:statusor", |
||||||
|
"@com_google_absl//absl/strings:str_format", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_library( |
||||||
|
name = "protos_internal", |
||||||
|
hdrs = ["protos_internal.h"], |
||||||
|
copts = UPB_DEFAULT_CPPOPTS, |
||||||
|
visibility = ["//visibility:public"], |
||||||
|
deps = [ |
||||||
|
":protos", |
||||||
|
"//:mini_table", |
||||||
|
"//:upb", |
||||||
|
"@com_google_absl//absl/status", |
||||||
|
"@com_google_absl//absl/status:statusor", |
||||||
|
"@com_google_absl//absl/strings:str_format", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Common support code for C++ generated code. |
||||||
|
cc_library( |
||||||
|
name = "generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", |
||||||
|
hdrs = [ |
||||||
|
"protos_internal.h", |
||||||
|
], |
||||||
|
copts = UPB_DEFAULT_CPPOPTS, |
||||||
|
visibility = ["//visibility:public"], |
||||||
|
deps = [ |
||||||
|
":protos", |
||||||
|
":protos_internal", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_test( |
||||||
|
name = "protos_internal_test", |
||||||
|
srcs = ["protos_internal_test.cc"], |
||||||
|
copts = UPB_DEFAULT_CPPOPTS, |
||||||
|
deps = [ |
||||||
|
":protos_internal", |
||||||
|
"//:upb", |
||||||
|
"//protos_generator/tests:test_model_upb_cc_proto", |
||||||
|
"//protos_generator/tests:test_model_upb_proto", |
||||||
|
"@com_google_googletest//:gtest_main", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
upb_cc_proto_library_copts( |
||||||
|
name = "upb_cc_proto_library_copts__for_generated_code_only_do_not_use", |
||||||
|
copts = UPB_DEFAULT_CPPOPTS, |
||||||
|
visibility = ["//visibility:public"], |
||||||
|
) |
@ -0,0 +1,39 @@ |
|||||||
|
# Copyright (c) 2009-2021, Google LLC |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are met: |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer in the |
||||||
|
# documentation and/or other materials provided with the distribution. |
||||||
|
# * Neither the name of Google LLC nor the |
||||||
|
# names of its contributors may be used to endorse or promote products |
||||||
|
# derived from this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY |
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
load("@bazel_skylib//:bzl_library.bzl", "bzl_library") |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
bzl_library( |
||||||
|
name = "upb_cc_proto_library_bzl", |
||||||
|
srcs = ["upb_cc_proto_library.bzl"], |
||||||
|
visibility = ["//visibility:public"], |
||||||
|
deps = [ |
||||||
|
"@bazel_skylib//lib:paths", |
||||||
|
"//bazel:upb_proto_library_bzl", |
||||||
|
"@bazel_tools//tools/cpp:toolchain_utils.bzl", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,346 @@ |
|||||||
|
# Copyright (c) 2009-2021, Google LLC |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are met: |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer in the |
||||||
|
# documentation and/or other materials provided with the distribution. |
||||||
|
# * Neither the name of Google LLC nor the |
||||||
|
# names of its contributors may be used to endorse or promote products |
||||||
|
# derived from this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY |
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
"""Public rules for using upb protos: |
||||||
|
- upb_cc_proto_library() |
||||||
|
""" |
||||||
|
|
||||||
|
load("@bazel_skylib//lib:paths.bzl", "paths") |
||||||
|
load("//bazel:upb_proto_library.bzl", "GeneratedSrcsInfo", "UpbWrappedCcInfo", "UpbWrappedGeneratedSrcsInfo", "upb_proto_library_aspect") |
||||||
|
|
||||||
|
# begin:google_only |
||||||
|
# load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain") |
||||||
|
# |
||||||
|
# end:google_only |
||||||
|
# begin:github_only |
||||||
|
# Compatibility code for Bazel 4.x. Remove this when we drop support for Bazel 4.x. |
||||||
|
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") |
||||||
|
|
||||||
|
def use_cpp_toolchain(): |
||||||
|
return ["@bazel_tools//tools/cpp:toolchain_type"] |
||||||
|
# end:github_only |
||||||
|
|
||||||
|
# Generic support code ######################################################### |
||||||
|
|
||||||
|
# begin:github_only |
||||||
|
_is_google3 = False |
||||||
|
# end:github_only |
||||||
|
|
||||||
|
# begin:google_only |
||||||
|
# _is_google3 = True |
||||||
|
# end:google_only |
||||||
|
|
||||||
|
def _get_real_short_path(file): |
||||||
|
# For some reason, files from other archives have short paths that look like: |
||||||
|
# ../com_google_protobuf/google/protobuf/descriptor.proto |
||||||
|
short_path = file.short_path |
||||||
|
if short_path.startswith("../"): |
||||||
|
second_slash = short_path.index("/", 3) |
||||||
|
short_path = short_path[second_slash + 1:] |
||||||
|
|
||||||
|
# Sometimes it has another few prefixes like: |
||||||
|
# _virtual_imports/any_proto/google/protobuf/any.proto |
||||||
|
# benchmarks/_virtual_imports/100_msgs_proto/benchmarks/100_msgs.proto |
||||||
|
# We want just google/protobuf/any.proto. |
||||||
|
virtual_imports = "_virtual_imports/" |
||||||
|
if virtual_imports in short_path: |
||||||
|
short_path = short_path.split(virtual_imports)[1].split("/", 1)[1] |
||||||
|
return short_path |
||||||
|
|
||||||
|
def _get_real_root(file): |
||||||
|
real_short_path = _get_real_short_path(file) |
||||||
|
return file.path[:-len(real_short_path) - 1] |
||||||
|
|
||||||
|
def _generate_output_file(ctx, src, extension): |
||||||
|
real_short_path = _get_real_short_path(src) |
||||||
|
real_short_path = paths.relativize(real_short_path, ctx.label.package) |
||||||
|
output_filename = paths.replace_extension(real_short_path, extension) |
||||||
|
ret = ctx.actions.declare_file(output_filename) |
||||||
|
return ret |
||||||
|
|
||||||
|
def _filter_none(elems): |
||||||
|
out = [] |
||||||
|
for elem in elems: |
||||||
|
if elem: |
||||||
|
out.append(elem) |
||||||
|
return out |
||||||
|
|
||||||
|
def _cc_library_func(ctx, name, hdrs, srcs, copts, dep_ccinfos): |
||||||
|
"""Like cc_library(), but callable from rules. |
||||||
|
|
||||||
|
Args: |
||||||
|
ctx: Rule context. |
||||||
|
name: Unique name used to generate output files. |
||||||
|
hdrs: Public headers that can be #included from other rules. |
||||||
|
srcs: C/C++ source files. |
||||||
|
copts: Additional options for cc compilation. |
||||||
|
dep_ccinfos: CcInfo providers of dependencies we should build/link against. |
||||||
|
|
||||||
|
Returns: |
||||||
|
CcInfo provider for this compilation. |
||||||
|
""" |
||||||
|
|
||||||
|
compilation_contexts = [info.compilation_context for info in dep_ccinfos] |
||||||
|
linking_contexts = [info.linking_context for info in dep_ccinfos] |
||||||
|
toolchain = find_cpp_toolchain(ctx) |
||||||
|
feature_configuration = cc_common.configure_features( |
||||||
|
ctx = ctx, |
||||||
|
cc_toolchain = toolchain, |
||||||
|
requested_features = ctx.features, |
||||||
|
unsupported_features = ctx.disabled_features, |
||||||
|
) |
||||||
|
|
||||||
|
blaze_only_args = {} |
||||||
|
|
||||||
|
if _is_google3: |
||||||
|
blaze_only_args["grep_includes"] = ctx.file._grep_includes |
||||||
|
|
||||||
|
(compilation_context, compilation_outputs) = cc_common.compile( |
||||||
|
actions = ctx.actions, |
||||||
|
feature_configuration = feature_configuration, |
||||||
|
cc_toolchain = toolchain, |
||||||
|
name = name, |
||||||
|
srcs = srcs, |
||||||
|
public_hdrs = hdrs, |
||||||
|
user_compile_flags = copts, |
||||||
|
compilation_contexts = compilation_contexts, |
||||||
|
**blaze_only_args |
||||||
|
) |
||||||
|
|
||||||
|
# buildifier: disable=unused-variable |
||||||
|
(linking_context, linking_outputs) = cc_common.create_linking_context_from_compilation_outputs( |
||||||
|
actions = ctx.actions, |
||||||
|
name = name, |
||||||
|
feature_configuration = feature_configuration, |
||||||
|
cc_toolchain = toolchain, |
||||||
|
compilation_outputs = compilation_outputs, |
||||||
|
linking_contexts = linking_contexts, |
||||||
|
**blaze_only_args |
||||||
|
) |
||||||
|
|
||||||
|
return CcInfo( |
||||||
|
compilation_context = compilation_context, |
||||||
|
linking_context = linking_context, |
||||||
|
) |
||||||
|
|
||||||
|
# Build setting for whether fasttable code generation is enabled ############### |
||||||
|
|
||||||
|
FastTableEnabledInfo = provider( |
||||||
|
"Provides fasttable configuration to compiler", |
||||||
|
fields = { |
||||||
|
"enabled": "whether fasttable is enabled", |
||||||
|
}, |
||||||
|
) |
||||||
|
|
||||||
|
def fasttable_enabled_impl(ctx): |
||||||
|
raw_setting = ctx.build_setting_value |
||||||
|
|
||||||
|
if raw_setting: |
||||||
|
# TODO(haberman): check that the target CPU supports fasttable. |
||||||
|
pass |
||||||
|
|
||||||
|
return FastTableEnabledInfo(enabled = raw_setting) |
||||||
|
|
||||||
|
upb_fasttable_enabled = rule( |
||||||
|
implementation = fasttable_enabled_impl, |
||||||
|
build_setting = config.bool(flag = True), |
||||||
|
) |
||||||
|
|
||||||
|
# Dummy rule to expose select() copts to aspects ############################## |
||||||
|
|
||||||
|
UpbCcProtoLibraryCoptsInfo = provider( |
||||||
|
"Provides copts for upb cc proto targets", |
||||||
|
fields = { |
||||||
|
"copts": "copts for upb_cc_proto_library()", |
||||||
|
}, |
||||||
|
) |
||||||
|
|
||||||
|
def upb_cc_proto_library_copts_impl(ctx): |
||||||
|
return UpbCcProtoLibraryCoptsInfo(copts = ctx.attr.copts) |
||||||
|
|
||||||
|
upb_cc_proto_library_copts = rule( |
||||||
|
implementation = upb_cc_proto_library_copts_impl, |
||||||
|
attrs = {"copts": attr.string_list(default = [])}, |
||||||
|
) |
||||||
|
|
||||||
|
_UpbCcWrappedCcInfo = provider("Provider for cc_info for protos", fields = ["cc_info"]) |
||||||
|
_WrappedCcGeneratedSrcsInfo = provider("Provider for generated sources", fields = ["srcs"]) |
||||||
|
|
||||||
|
def _compile_upb_cc_protos(ctx, generator, proto_info, proto_sources): |
||||||
|
if len(proto_sources) == 0: |
||||||
|
return GeneratedSrcsInfo(srcs = [], hdrs = []) |
||||||
|
|
||||||
|
tool = getattr(ctx.executable, "_gen_" + generator) |
||||||
|
srcs = [_generate_output_file(ctx, name, ".upb.proto.cc") for name in proto_sources] |
||||||
|
hdrs = [_generate_output_file(ctx, name, ".upb.proto.h") for name in proto_sources] |
||||||
|
hdrs += [_generate_output_file(ctx, name, ".upb.fwd.h") for name in proto_sources] |
||||||
|
transitive_sets = proto_info.transitive_descriptor_sets.to_list() |
||||||
|
fasttable_enabled = (hasattr(ctx.attr, "_fasttable_enabled") and |
||||||
|
ctx.attr._fasttable_enabled[FastTableEnabledInfo].enabled) |
||||||
|
codegen_params = "fasttable:" if fasttable_enabled else "" |
||||||
|
ctx.actions.run( |
||||||
|
inputs = depset( |
||||||
|
direct = [proto_info.direct_descriptor_set], |
||||||
|
transitive = [proto_info.transitive_descriptor_sets], |
||||||
|
), |
||||||
|
tools = [tool], |
||||||
|
outputs = srcs + hdrs, |
||||||
|
executable = ctx.executable._protoc, |
||||||
|
arguments = [ |
||||||
|
"--" + generator + "_out=" + codegen_params + _get_real_root(srcs[0]), |
||||||
|
"--plugin=protoc-gen-" + generator + "=" + tool.path, |
||||||
|
"--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets]), |
||||||
|
] + |
||||||
|
[_get_real_short_path(file) for file in proto_sources], |
||||||
|
progress_message = "Generating upb cc protos for :" + ctx.label.name, |
||||||
|
) |
||||||
|
return GeneratedSrcsInfo(srcs = srcs, hdrs = hdrs) |
||||||
|
|
||||||
|
def _upb_cc_proto_rule_impl(ctx): |
||||||
|
if len(ctx.attr.deps) != 1: |
||||||
|
fail("only one deps dependency allowed.") |
||||||
|
dep = ctx.attr.deps[0] |
||||||
|
|
||||||
|
if _WrappedCcGeneratedSrcsInfo in dep: |
||||||
|
srcs = dep[_WrappedCcGeneratedSrcsInfo].srcs |
||||||
|
elif UpbWrappedGeneratedSrcsInfo in dep: |
||||||
|
srcs = dep[UpbWrappedGeneratedSrcsInfo].srcs |
||||||
|
else: |
||||||
|
fail("proto_library rule must generate UpbWrappedGeneratedSrcsInfo or " + |
||||||
|
"_WrappedCcGeneratedSrcsInfo (aspect should have handled this).") |
||||||
|
|
||||||
|
if _UpbCcWrappedCcInfo in dep: |
||||||
|
cc_info = dep[_UpbCcWrappedCcInfo].cc_info |
||||||
|
elif UpbWrappedCcInfo in dep: |
||||||
|
cc_info = dep[UpbWrappedCcInfo].cc_info |
||||||
|
else: |
||||||
|
fail("proto_library rule must generate UpbWrappedCcInfo or " + |
||||||
|
"_UpbCcWrappedCcInfo (aspect should have handled this).") |
||||||
|
|
||||||
|
lib = cc_info.linking_context.linker_inputs.to_list()[0].libraries[0] |
||||||
|
files = _filter_none([ |
||||||
|
lib.static_library, |
||||||
|
lib.pic_static_library, |
||||||
|
lib.dynamic_library, |
||||||
|
]) |
||||||
|
return [ |
||||||
|
DefaultInfo(files = depset(files + srcs.hdrs + srcs.srcs)), |
||||||
|
srcs, |
||||||
|
cc_info, |
||||||
|
] |
||||||
|
|
||||||
|
def _upb_cc_proto_aspect_impl(target, ctx, generator, cc_provider, file_provider): |
||||||
|
proto_info = target[ProtoInfo] |
||||||
|
files = _compile_upb_cc_protos(ctx, generator, proto_info, proto_info.direct_sources) |
||||||
|
deps = ctx.rule.attr.deps + getattr(ctx.attr, "_" + generator) |
||||||
|
dep_ccinfos = [dep[CcInfo] for dep in deps if CcInfo in dep] |
||||||
|
dep_ccinfos += [dep[UpbWrappedCcInfo].cc_info for dep in deps if UpbWrappedCcInfo in dep] |
||||||
|
dep_ccinfos += [dep[_UpbCcWrappedCcInfo].cc_info for dep in deps if _UpbCcWrappedCcInfo in dep] |
||||||
|
if UpbWrappedCcInfo not in target: |
||||||
|
fail("Target should have UpbWrappedCcInfo provider") |
||||||
|
dep_ccinfos.append(target[UpbWrappedCcInfo].cc_info) |
||||||
|
cc_info = _cc_library_func( |
||||||
|
ctx = ctx, |
||||||
|
name = ctx.rule.attr.name + "." + generator, |
||||||
|
hdrs = files.hdrs, |
||||||
|
srcs = files.srcs, |
||||||
|
copts = ctx.attr._ccopts[UpbCcProtoLibraryCoptsInfo].copts, |
||||||
|
dep_ccinfos = dep_ccinfos, |
||||||
|
) |
||||||
|
return [cc_provider(cc_info = cc_info), file_provider(srcs = files)] |
||||||
|
|
||||||
|
def _upb_cc_proto_library_aspect_impl(target, ctx): |
||||||
|
return _upb_cc_proto_aspect_impl(target, ctx, "upbprotos", _UpbCcWrappedCcInfo, _WrappedCcGeneratedSrcsInfo) |
||||||
|
|
||||||
|
def _maybe_add(d): |
||||||
|
if _is_google3: |
||||||
|
d["_grep_includes"] = attr.label( |
||||||
|
allow_single_file = True, |
||||||
|
cfg = "exec", |
||||||
|
default = "@bazel_tools//tools/cpp:grep-includes", |
||||||
|
) |
||||||
|
return d |
||||||
|
|
||||||
|
_upb_cc_proto_library_aspect = aspect( |
||||||
|
attrs = _maybe_add({ |
||||||
|
"_ccopts": attr.label( |
||||||
|
default = "//protos:upb_cc_proto_library_copts__for_generated_code_only_do_not_use", |
||||||
|
), |
||||||
|
"_gen_upbprotos": attr.label( |
||||||
|
executable = True, |
||||||
|
cfg = "exec", |
||||||
|
default = "//protos_generator:protoc-gen-upb-protos", |
||||||
|
), |
||||||
|
"_protoc": attr.label( |
||||||
|
executable = True, |
||||||
|
cfg = "exec", |
||||||
|
default = "@com_google_protobuf//:protoc", |
||||||
|
), |
||||||
|
"_cc_toolchain": attr.label( |
||||||
|
default = "@bazel_tools//tools/cpp:current_cc_toolchain", |
||||||
|
), |
||||||
|
"_upbprotos": attr.label_list( |
||||||
|
default = [ |
||||||
|
# TODO: Add dependencies for cc runtime (absl/string etc..) |
||||||
|
"//:generated_cpp_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", |
||||||
|
"//protos:generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", |
||||||
|
"@com_google_absl//absl/strings", |
||||||
|
"@com_google_absl//absl/status:statusor", |
||||||
|
"//protos", |
||||||
|
], |
||||||
|
), |
||||||
|
}), |
||||||
|
implementation = _upb_cc_proto_library_aspect_impl, |
||||||
|
provides = [ |
||||||
|
_UpbCcWrappedCcInfo, |
||||||
|
_WrappedCcGeneratedSrcsInfo, |
||||||
|
], |
||||||
|
required_aspect_providers = [ |
||||||
|
UpbWrappedCcInfo, |
||||||
|
UpbWrappedGeneratedSrcsInfo, |
||||||
|
], |
||||||
|
attr_aspects = ["deps"], |
||||||
|
fragments = ["cpp"], |
||||||
|
toolchains = use_cpp_toolchain(), |
||||||
|
incompatible_use_toolchain_transition = True, |
||||||
|
) |
||||||
|
|
||||||
|
upb_cc_proto_library = rule( |
||||||
|
output_to_genfiles = True, |
||||||
|
implementation = _upb_cc_proto_rule_impl, |
||||||
|
attrs = { |
||||||
|
"deps": attr.label_list( |
||||||
|
aspects = [ |
||||||
|
upb_proto_library_aspect, |
||||||
|
_upb_cc_proto_library_aspect, |
||||||
|
], |
||||||
|
allow_rules = ["proto_library"], |
||||||
|
providers = [ProtoInfo], |
||||||
|
), |
||||||
|
"_ccopts": attr.label( |
||||||
|
default = "//protos:upb_cc_proto_library_copts__for_generated_code_only_do_not_use", |
||||||
|
), |
||||||
|
}, |
||||||
|
) |
@ -0,0 +1,108 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "protos/protos.h" |
||||||
|
|
||||||
|
#include "absl/strings/str_format.h" |
||||||
|
|
||||||
|
namespace protos { |
||||||
|
|
||||||
|
// begin:google_only
|
||||||
|
// absl::Status MessageAllocationError(SourceLocation loc) {
|
||||||
|
// return absl::Status(absl::StatusCode::kInternal,
|
||||||
|
// "Upb message allocation error", loc);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// absl::Status ExtensionNotFoundError(int extension_number, SourceLocation loc) {
|
||||||
|
// return absl::Status(
|
||||||
|
// absl::StatusCode::kInternal,
|
||||||
|
// absl::StrFormat("Extension %d not found", extension_number), loc);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// absl::Status MessageEncodeError(upb_EncodeStatus status, SourceLocation loc) {
|
||||||
|
// return absl::Status(absl::StatusCode::kInternal,
|
||||||
|
// absl::StrFormat("Upb message encoding error %d", status),
|
||||||
|
// loc
|
||||||
|
//
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc
|
||||||
|
//
|
||||||
|
// ) {
|
||||||
|
// return absl::Status(absl::StatusCode::kInternal,
|
||||||
|
// absl::StrFormat("Upb message parse error %d", status), loc
|
||||||
|
//
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// end:google_only
|
||||||
|
|
||||||
|
// begin:github_only
|
||||||
|
absl::Status MessageAllocationError(SourceLocation loc) { |
||||||
|
return absl::Status(absl::StatusCode::kUnknown, |
||||||
|
"Upb message allocation error"); |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status ExtensionNotFoundError(int ext_number, SourceLocation loc) { |
||||||
|
return absl::Status(absl::StatusCode::kUnknown, |
||||||
|
absl::StrFormat("Extension %d not found", ext_number)); |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status MessageEncodeError(upb_EncodeStatus s, SourceLocation loc) { |
||||||
|
return absl::Status(absl::StatusCode::kUnknown, "Encoding error"); |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc |
||||||
|
|
||||||
|
) { |
||||||
|
return absl::Status(absl::StatusCode::kUnknown, "Upb message parse error"); |
||||||
|
} |
||||||
|
// end:github_only
|
||||||
|
|
||||||
|
namespace internal { |
||||||
|
|
||||||
|
upb_ExtensionRegistry* GetUpbExtensions( |
||||||
|
const ExtensionRegistry& extension_registry) { |
||||||
|
return extension_registry.registry_; |
||||||
|
} |
||||||
|
|
||||||
|
absl::StatusOr<absl::string_view> Serialize(const upb_Message* message, |
||||||
|
const upb_MiniTable* mini_table, |
||||||
|
upb_Arena* arena, int options) { |
||||||
|
size_t len; |
||||||
|
char* ptr; |
||||||
|
upb_EncodeStatus status = |
||||||
|
upb_Encode(message, mini_table, options, arena, &ptr, &len); |
||||||
|
if (status == kUpb_EncodeStatus_Ok) { |
||||||
|
return absl::string_view(ptr, len); |
||||||
|
} |
||||||
|
return MessageEncodeError(status); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
} // namespace protos
|
@ -0,0 +1,407 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_PROTOS_H_ |
||||||
|
#define UPB_PROTOS_PROTOS_H_ |
||||||
|
|
||||||
|
#include <type_traits> |
||||||
|
|
||||||
|
#include "absl/status/status.h" |
||||||
|
#include "absl/status/statusor.h" |
||||||
|
#include "upb/decode.h" |
||||||
|
#include "upb/encode.h" |
||||||
|
#include "upb/mini_table.h" |
||||||
|
#include "upb/upb.hpp" |
||||||
|
|
||||||
|
namespace protos { |
||||||
|
|
||||||
|
using Arena = ::upb::Arena; |
||||||
|
class ExtensionRegistry; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
using Proxy = std::conditional_t<std::is_const<T>::value, |
||||||
|
typename std::remove_const_t<T>::CProxy, |
||||||
|
typename T::Proxy>; |
||||||
|
|
||||||
|
// Provides convenient access to Proxy and CProxy message types.
|
||||||
|
//
|
||||||
|
// Using rebinding and handling of const, Ptr<Message> and Ptr<const Message>
|
||||||
|
// allows copying const with T* const and avoids using non-copyable Proxy types
|
||||||
|
// directly.
|
||||||
|
template <typename T> |
||||||
|
class Ptr final { |
||||||
|
public: |
||||||
|
Ptr() = delete; |
||||||
|
|
||||||
|
// Implicit conversions
|
||||||
|
Ptr(T* m) : p_(m) {} // NOLINT
|
||||||
|
Ptr(const Proxy<T>* p) : p_(*p) {} // NOLINT
|
||||||
|
Ptr(Proxy<T> p) : p_(p) {} // NOLINT
|
||||||
|
Ptr(const Ptr& m) = default; |
||||||
|
|
||||||
|
Ptr& operator=(Ptr v) & { |
||||||
|
Proxy<T>::Rebind(p_, v.p_); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
Proxy<T> operator*() const { return p_; } |
||||||
|
Proxy<T>* operator->() const { |
||||||
|
return const_cast<Proxy<T>*>(std::addressof(p_)); |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef __clang__ |
||||||
|
#pragma clang diagnostic push |
||||||
|
#pragma clang diagnostic ignored "-Wclass-conversion" |
||||||
|
#endif |
||||||
|
template <typename U = T, std::enable_if_t<!std::is_const<U>::value, int> = 0> |
||||||
|
operator Ptr<const T>() const { |
||||||
|
Proxy<const T> p(p_); |
||||||
|
return Ptr<const T>(&p); |
||||||
|
} |
||||||
|
#ifdef __clang__ |
||||||
|
#pragma clang diagnostic pop |
||||||
|
#endif |
||||||
|
|
||||||
|
private: |
||||||
|
Ptr(void* msg, upb_Arena* arena) : p_(msg, arena) {} // NOLINT
|
||||||
|
|
||||||
|
friend class Ptr<const T>; |
||||||
|
friend typename T::Access; |
||||||
|
|
||||||
|
Proxy<T> p_; |
||||||
|
}; |
||||||
|
|
||||||
|
inline absl::string_view UpbStrToStringView(upb_StringView str) { |
||||||
|
return absl::string_view(str.data, str.size); |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: update bzl and move to upb runtime / protos.cc.
|
||||||
|
inline upb_StringView UpbStrFromStringView(absl::string_view str, |
||||||
|
upb_Arena* arena) { |
||||||
|
upb_alloc* alloc = upb_Arena_Alloc(arena); |
||||||
|
const size_t str_size = str.size(); |
||||||
|
char* buffer = static_cast<char*>(upb_malloc(alloc, str_size)); |
||||||
|
memcpy(buffer, str.data(), str_size); |
||||||
|
return upb_StringView_FromDataAndSize(buffer, str_size); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
typename T::Proxy CreateMessage(::protos::Arena& arena) { |
||||||
|
return typename T::Proxy(upb_Message_New(T::minitable(), arena.ptr()), |
||||||
|
arena.ptr()); |
||||||
|
} |
||||||
|
|
||||||
|
// begin:github_only
|
||||||
|
// This type exists to work around an absl type that has not yet been
|
||||||
|
// released.
|
||||||
|
struct SourceLocation { |
||||||
|
static SourceLocation current() { return {}; } |
||||||
|
absl::string_view file_name() { return "<unknown>"; } |
||||||
|
int line() { return 0; } |
||||||
|
}; |
||||||
|
// end:github_only
|
||||||
|
|
||||||
|
// begin:google_only
|
||||||
|
// using SourceLocation = absl::SourceLocation;
|
||||||
|
// end:google_only
|
||||||
|
|
||||||
|
absl::Status MessageAllocationError( |
||||||
|
SourceLocation loc = SourceLocation::current()); |
||||||
|
|
||||||
|
absl::Status ExtensionNotFoundError( |
||||||
|
int extension_number, SourceLocation loc = SourceLocation::current()); |
||||||
|
|
||||||
|
absl::Status MessageDecodeError(upb_DecodeStatus status, |
||||||
|
SourceLocation loc = SourceLocation::current()); |
||||||
|
|
||||||
|
absl::Status MessageEncodeError(upb_EncodeStatus status, |
||||||
|
SourceLocation loc = SourceLocation::current()); |
||||||
|
|
||||||
|
namespace internal { |
||||||
|
template <typename T> |
||||||
|
T CreateMessage() { |
||||||
|
return T(); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
typename T::Proxy CreateMessageProxy(void* msg, upb_Arena* arena) { |
||||||
|
return typename T::Proxy(msg, arena); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
typename T::CProxy CreateMessage(upb_Message* msg) { |
||||||
|
return typename T::CProxy(msg); |
||||||
|
} |
||||||
|
|
||||||
|
class ExtensionMiniTableProvider { |
||||||
|
public: |
||||||
|
ExtensionMiniTableProvider(const upb_MiniTable_Extension* mini_table_ext) |
||||||
|
: mini_table_ext_(mini_table_ext) {} |
||||||
|
const upb_MiniTable_Extension* mini_table_ext() const { |
||||||
|
return mini_table_ext_; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
const upb_MiniTable_Extension* mini_table_ext_; |
||||||
|
}; |
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// ExtensionIdentifier
|
||||||
|
// This is the type of actual extension objects. E.g. if you have:
|
||||||
|
// extend Foo {
|
||||||
|
// optional MyExtension bar = 1234;
|
||||||
|
// }
|
||||||
|
// then "bar" will be defined in C++ as:
|
||||||
|
// ExtensionIdentifier<Foo, MyExtension> bar(&namespace_bar_ext);
|
||||||
|
template <typename ExtendeeType, typename ExtensionType> |
||||||
|
class ExtensionIdentifier : public ExtensionMiniTableProvider { |
||||||
|
public: |
||||||
|
using Extension = ExtensionType; |
||||||
|
using Extendee = ExtendeeType; |
||||||
|
|
||||||
|
ExtensionIdentifier(const upb_MiniTable_Extension* mini_table_ext) |
||||||
|
: ExtensionMiniTableProvider(mini_table_ext) {} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
void* GetInternalMsg(const T& message) { |
||||||
|
return message.msg(); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
void* GetInternalMsg(const Ptr<T>& message) { |
||||||
|
return message->msg(); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
upb_Arena* GetArena(const T& message) { |
||||||
|
return static_cast<upb_Arena*>(message.GetInternalArena()); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
upb_Arena* GetArena(const Ptr<T>& message) { |
||||||
|
return static_cast<upb_Arena*>(message->GetInternalArena()); |
||||||
|
} |
||||||
|
|
||||||
|
upb_ExtensionRegistry* GetUpbExtensions( |
||||||
|
const ExtensionRegistry& extension_registry); |
||||||
|
|
||||||
|
absl::StatusOr<absl::string_view> Serialize(const upb_Message* message, |
||||||
|
const upb_MiniTable* mini_table, |
||||||
|
upb_Arena* arena, int options); |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
class ExtensionRegistry { |
||||||
|
public: |
||||||
|
ExtensionRegistry( |
||||||
|
const std::vector<const ::protos::internal::ExtensionMiniTableProvider*> |
||||||
|
extensions, |
||||||
|
const upb::Arena& arena) |
||||||
|
: registry_(upb_ExtensionRegistry_New(arena.ptr())) { |
||||||
|
if (registry_) { |
||||||
|
for (const auto& ext_provider : extensions) { |
||||||
|
const auto* ext = ext_provider->mini_table_ext(); |
||||||
|
bool success = upb_ExtensionRegistry_AddArray(registry_, &ext, 1); |
||||||
|
if (!success) { |
||||||
|
registry_ = nullptr; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
friend upb_ExtensionRegistry* ::protos::internal::GetUpbExtensions( |
||||||
|
const ExtensionRegistry& extension_registry); |
||||||
|
upb_ExtensionRegistry* registry_; |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
using EnableIfProtosClass = std::enable_if_t< |
||||||
|
std::is_base_of<typename T::Access, T>::value && |
||||||
|
std::is_base_of<typename T::Access, typename T::ExtendableType>::value>; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
using EnableIfMutableProto = std::enable_if_t<!std::is_const<T>::value>; |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>> |
||||||
|
bool HasExtension( |
||||||
|
const T& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||||
|
return _upb_Message_Getext(message.msg(), id.mini_table_ext()) != nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>> |
||||||
|
bool HasExtension( |
||||||
|
const Ptr<T>& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||||
|
return _upb_Message_Getext(message->msg(), id.mini_table_ext()) != nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>, typename = EnableIfMutableProto<T>> |
||||||
|
void ClearExtension( |
||||||
|
const Ptr<T>& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||||
|
_upb_Message_Clearext(message->msg(), id.mini_table_ext()); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>> |
||||||
|
void ClearExtension( |
||||||
|
const T& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||||
|
_upb_Message_Clearext(message.msg(), id.mini_table_ext()); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>> |
||||||
|
absl::Status SetExtension( |
||||||
|
const T& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id, |
||||||
|
Extension& value) { |
||||||
|
auto* message_arena = static_cast<upb_Arena*>(message.GetInternalArena()); |
||||||
|
upb_Message_Extension* msg_ext = _upb_Message_GetOrCreateExtension( |
||||||
|
message.msg(), id.mini_table_ext(), message_arena); |
||||||
|
if (!msg_ext) { |
||||||
|
return MessageAllocationError(); |
||||||
|
} |
||||||
|
auto* extension_arena = static_cast<upb_Arena*>(value.GetInternalArena()); |
||||||
|
if (message_arena != extension_arena) { |
||||||
|
upb_Arena_Fuse(message_arena, extension_arena); |
||||||
|
} |
||||||
|
msg_ext->data.ptr = value.msg(); |
||||||
|
return absl::OkStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>, typename = EnableIfMutableProto<T>> |
||||||
|
absl::Status SetExtension( |
||||||
|
const Ptr<T>& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id, |
||||||
|
Extension& value) { |
||||||
|
auto* message_arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||||
|
upb_Message_Extension* msg_ext = _upb_Message_GetOrCreateExtension( |
||||||
|
message->msg(), id.mini_table_ext(), message_arena); |
||||||
|
if (!msg_ext) { |
||||||
|
return MessageAllocationError(); |
||||||
|
} |
||||||
|
auto* extension_arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||||
|
if (message_arena != extension_arena) { |
||||||
|
upb_Arena_Fuse(message_arena, extension_arena); |
||||||
|
} |
||||||
|
msg_ext->data.ptr = ::protos::internal::GetInternalMsg(value); |
||||||
|
return absl::OkStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>> |
||||||
|
absl::StatusOr<Ptr<const Extension>> GetExtension( |
||||||
|
const T& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||||
|
const upb_Message_Extension* ext = |
||||||
|
_upb_Message_Getext(message.msg(), id.mini_table_ext()); |
||||||
|
if (!ext) { |
||||||
|
return ExtensionNotFoundError(id.mini_table_ext()->field.number); |
||||||
|
} |
||||||
|
return Ptr<const Extension>( |
||||||
|
::protos::internal::CreateMessage<Extension>(ext->data.ptr)); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename Extendee, typename Extension, |
||||||
|
typename = EnableIfProtosClass<T>> |
||||||
|
absl::StatusOr<Ptr<const Extension>> GetExtension( |
||||||
|
const Ptr<T>& message, |
||||||
|
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||||
|
const upb_Message_Extension* ext = |
||||||
|
_upb_Message_Getext(message->msg(), id.mini_table_ext()); |
||||||
|
if (!ext) { |
||||||
|
return ExtensionNotFoundError(id.mini_table_ext()->field.number); |
||||||
|
} |
||||||
|
return Ptr<const Extension>( |
||||||
|
::protos::internal::CreateMessage<Extension>(ext->data.ptr)); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
bool Parse(T& message, absl::string_view bytes) { |
||||||
|
_upb_Message_Clear(message.msg(), T::minitable()); |
||||||
|
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena()); |
||||||
|
return upb_Decode(bytes.data(), bytes.size(), message.msg(), T::minitable(), |
||||||
|
/* extreg= */ nullptr, /* options= */ 0, |
||||||
|
arena) == kUpb_DecodeStatus_Ok; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
absl::StatusOr<T> Parse(absl::string_view bytes, int options = 0) { |
||||||
|
T message; |
||||||
|
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena()); |
||||||
|
upb_DecodeStatus status = |
||||||
|
upb_Decode(bytes.data(), bytes.size(), message.msg(), T::minitable(), |
||||||
|
/* extreg= */ nullptr, /* options= */ 0, arena); |
||||||
|
if (status == kUpb_DecodeStatus_Ok) { |
||||||
|
return message; |
||||||
|
} |
||||||
|
return MessageDecodeError(status); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
absl::StatusOr<T> Parse(absl::string_view bytes, |
||||||
|
const ::protos::ExtensionRegistry& extension_registry, |
||||||
|
int options = 0) { |
||||||
|
T message; |
||||||
|
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena()); |
||||||
|
upb_DecodeStatus status = |
||||||
|
upb_Decode(bytes.data(), bytes.size(), message.msg(), T::minitable(), |
||||||
|
::protos::internal::GetUpbExtensions(extension_registry), |
||||||
|
/* options= */ 0, arena); |
||||||
|
if (status == kUpb_DecodeStatus_Ok) { |
||||||
|
return message; |
||||||
|
} |
||||||
|
return MessageDecodeError(status); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
absl::StatusOr<absl::string_view> Serialize(const T& message, upb::Arena& arena, |
||||||
|
int options = 0) { |
||||||
|
return ::protos::internal::Serialize(message.msg(), T::minitable(), |
||||||
|
arena.ptr(), options); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
absl::StatusOr<absl::string_view> Serialize(Ptr<const T> message, |
||||||
|
upb::Arena& arena, |
||||||
|
int options = 0) { |
||||||
|
return ::protos::internal::Serialize(message->msg(), T::minitable(), |
||||||
|
arena.ptr(), options); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_PROTOS_H_
|
@ -0,0 +1,44 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_PROTOS_INTERNAL_H_ |
||||||
|
#define UPB_PROTOS_PROTOS_INTERNAL_H_ |
||||||
|
|
||||||
|
#include "protos/protos.h" |
||||||
|
|
||||||
|
namespace protos::internal { |
||||||
|
|
||||||
|
// Moves ownership of a message created in a source arena.
|
||||||
|
//
|
||||||
|
// Utility function to provide a way to move ownership across languages or VMs.
|
||||||
|
template <typename T> |
||||||
|
T MoveMessage(upb_Message* msg, upb_Arena* arena) { |
||||||
|
return T(msg, arena); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos::internal
|
||||||
|
#endif |
@ -0,0 +1,55 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "protos/protos_internal.h" |
||||||
|
|
||||||
|
#include "gmock/gmock.h" |
||||||
|
#include "gtest/gtest.h" |
||||||
|
#include "protos_generator/tests/test_model.upb.h" |
||||||
|
#include "protos_generator/tests/test_model.upb.proto.h" |
||||||
|
#include "upb/arena.h" |
||||||
|
|
||||||
|
namespace protos::testing { |
||||||
|
namespace { |
||||||
|
using ::protos_generator::test::protos::TestModel; |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, InternalMoveMessage) { |
||||||
|
// Generate message (simulating message created in another VM/language)
|
||||||
|
upb_Arena* source_arena = upb_Arena_New(); |
||||||
|
protos_generator_test_TestModel* message = |
||||||
|
protos_generator_test_TestModel_new(source_arena); |
||||||
|
protos_generator_test_TestModel_set_int_value_with_default(message, 123); |
||||||
|
|
||||||
|
EXPECT_NE(message, nullptr); |
||||||
|
// Move ownership.
|
||||||
|
TestModel model = |
||||||
|
protos::internal::MoveMessage<TestModel>(message, source_arena); |
||||||
|
// Now that we have moved ownership, free original arena.
|
||||||
|
upb_Arena_Free(source_arena); |
||||||
|
EXPECT_EQ(model.int_value_with_default(), 123); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace protos::testing
|
@ -0,0 +1,85 @@ |
|||||||
|
# Copyright (c) 2009-2021, Google LLC |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are met: |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer in the |
||||||
|
# documentation and/or other materials provided with the distribution. |
||||||
|
# * Neither the name of Google LLC nor the |
||||||
|
# names of its contributors may be used to endorse or promote products |
||||||
|
# derived from this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY |
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
load( |
||||||
|
"//bazel:build_defs.bzl", |
||||||
|
"UPB_DEFAULT_CPPOPTS", |
||||||
|
) |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
cc_binary( |
||||||
|
name = "protoc-gen-upb-protos", |
||||||
|
srcs = [ |
||||||
|
"protoc-gen-upb-protos.cc", |
||||||
|
], |
||||||
|
copts = UPB_DEFAULT_CPPOPTS, |
||||||
|
visibility = ["//visibility:public"], |
||||||
|
deps = [ |
||||||
|
":generator", |
||||||
|
"//:mini_table", |
||||||
|
"//upbc:file_layout", |
||||||
|
"@com_google_absl//absl/base:core_headers", |
||||||
|
"@com_google_absl//absl/container:flat_hash_map", |
||||||
|
"@com_google_absl//absl/container:flat_hash_set", |
||||||
|
"@com_google_absl//absl/strings", |
||||||
|
"@com_google_protobuf//:protobuf", |
||||||
|
"@com_google_protobuf//src/google/protobuf/compiler:code_generator", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_library( |
||||||
|
name = "generator", |
||||||
|
srcs = [ |
||||||
|
"gen_accessors.cc", |
||||||
|
"gen_enums.cc", |
||||||
|
"gen_extensions.cc", |
||||||
|
"gen_messages.cc", |
||||||
|
"gen_utils.cc", |
||||||
|
"output.cc", |
||||||
|
], |
||||||
|
hdrs = [ |
||||||
|
"gen_accessors.h", |
||||||
|
"gen_enums.h", |
||||||
|
"gen_extensions.h", |
||||||
|
"gen_messages.h", |
||||||
|
"gen_utils.h", |
||||||
|
"output.h", |
||||||
|
], |
||||||
|
visibility = ["//visibility:private"], |
||||||
|
deps = [ |
||||||
|
"//upbc:common", |
||||||
|
"//upbc:file_layout", |
||||||
|
"//upbc:keywords", |
||||||
|
"@com_google_absl//absl/base:log_severity", |
||||||
|
"@com_google_absl//absl/container:flat_hash_map", |
||||||
|
"@com_google_absl//absl/container:flat_hash_set", |
||||||
|
"@com_google_absl//absl/log", |
||||||
|
"@com_google_absl//absl/log:check", |
||||||
|
"@com_google_absl//absl/strings", |
||||||
|
"@com_google_protobuf//:protobuf", |
||||||
|
"@com_google_protobuf//src/google/protobuf/compiler:code_generator", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,722 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "protos_generator/gen_accessors.h" |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "absl/container/flat_hash_set.h" |
||||||
|
#include "absl/strings/match.h" |
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
#include "protos_generator/gen_utils.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
#include "upbc/file_layout.h" |
||||||
|
#include "upbc/keywords.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
using FileLayout = ::upbc::FileLayout; |
||||||
|
using NameToFieldDescriptorMap = |
||||||
|
absl::flat_hash_map<absl::string_view, const protobuf::FieldDescriptor*>; |
||||||
|
|
||||||
|
void WriteFieldAccessorHazzer(const protobuf::Descriptor* desc, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const FileLayout& layout, Output& output); |
||||||
|
void WriteFieldAccessorClear(const protobuf::Descriptor* desc, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const FileLayout& layout, Output& output); |
||||||
|
void WriteMapFieldAccessors(const protobuf::Descriptor* desc, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
Output& output); |
||||||
|
|
||||||
|
void WriteMapAccessorDefinitions(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const absl::string_view class_name, |
||||||
|
Output& output); |
||||||
|
void WriteRepeatedMessageAccessor(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
absl::string_view class_name, Output& output); |
||||||
|
void WriteRepeatedStringAccessor(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const absl::string_view class_name, |
||||||
|
Output& output); |
||||||
|
void WriteRepeatedScalarAccessor(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
absl::string_view class_name, Output& output); |
||||||
|
|
||||||
|
// Returns C++ class member name by resolving naming conflicts across
|
||||||
|
// proto field names (such as clear_ prefixes) and keyword collisions.
|
||||||
|
//
|
||||||
|
// The Upb C generator prefixes all accessors with package and class names
|
||||||
|
// avoiding collisions. Therefore we need to use raw field names when calling
|
||||||
|
// into C accessors but need to fully resolve conflicts for C++ class members.
|
||||||
|
std::string ResolveFieldName(const protobuf::FieldDescriptor* field, |
||||||
|
const NameToFieldDescriptorMap& field_names); |
||||||
|
|
||||||
|
NameToFieldDescriptorMap CreateFieldNameMap( |
||||||
|
const protobuf::Descriptor* message) { |
||||||
|
NameToFieldDescriptorMap field_names; |
||||||
|
for (int i = 0; i < message->field_count(); i++) { |
||||||
|
const protobuf::FieldDescriptor* field = message->field(i); |
||||||
|
field_names.emplace(field->name(), field); |
||||||
|
} |
||||||
|
return field_names; |
||||||
|
} |
||||||
|
|
||||||
|
void WriteFieldAccessorsInHeader(const protobuf::Descriptor* desc, |
||||||
|
Output& output) { |
||||||
|
FileLayout layout(desc->file()); |
||||||
|
|
||||||
|
// Generate const methods.
|
||||||
|
OutputIndenter i(output); |
||||||
|
|
||||||
|
auto field_names = CreateFieldNameMap(desc); |
||||||
|
|
||||||
|
for (auto field : ::upbc::FieldNumberOrder(desc)) { |
||||||
|
std::string resolved_field_name = ResolveFieldName(field, field_names); |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
WriteFieldAccessorHazzer(desc, field, resolved_field_name, layout, output); |
||||||
|
WriteFieldAccessorClear(desc, field, resolved_field_name, layout, output); |
||||||
|
|
||||||
|
if (field->is_map()) { |
||||||
|
WriteMapFieldAccessors(desc, field, resolved_field_name, output); |
||||||
|
} else if (desc->options().map_entry()) { |
||||||
|
// TODO(b/237399867) Implement map entry
|
||||||
|
} else if (field->is_repeated()) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
inline size_t $1_size() const { |
||||||
|
size_t len; |
||||||
|
$0_$2(msg_, &len); |
||||||
|
return len; |
||||||
|
} |
||||||
|
|
||||||
|
inline void clear_$1() { $0_clear_$2(msg_); } |
||||||
|
)cc", |
||||||
|
MessageName(desc), resolved_field_name, upbc_name); |
||||||
|
|
||||||
|
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $2(size_t index) const; |
||||||
|
absl::StatusOr<$0> add_$2(); |
||||||
|
$0 mutable_$3(size_t index) const; |
||||||
|
)cc", |
||||||
|
MessagePtrConstType(field, /* const */ false), |
||||||
|
MessagePtrConstType(field, /* const */ true), resolved_field_name, |
||||||
|
upbc_name); |
||||||
|
} else { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$0 $1(size_t index) const; |
||||||
|
bool add_$1($0 val); |
||||||
|
void set_$1(size_t index, $0 val); |
||||||
|
bool resize_$1(size_t len); |
||||||
|
)cc", |
||||||
|
CppConstType(field), resolved_field_name); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// non-repeated.
|
||||||
|
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) { |
||||||
|
output(R"cc( |
||||||
|
$0 $1() const; |
||||||
|
void set_$1($0 value); |
||||||
|
)cc", |
||||||
|
CppConstType(field), resolved_field_name); |
||||||
|
} else if (field->cpp_type() == |
||||||
|
protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
output(R"cc( |
||||||
|
$1 $2() const; |
||||||
|
$0 mutable_$3(); |
||||||
|
)cc", |
||||||
|
MessagePtrConstType(field, /* const */ false), |
||||||
|
MessagePtrConstType(field, /* const */ true), |
||||||
|
resolved_field_name, upbc_name); |
||||||
|
} else { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
inline $0 $1() const { return $2_$3(msg_); } |
||||||
|
inline void set_$1($0 value) { return $2_set_$3(msg_, value); } |
||||||
|
)cc", |
||||||
|
CppConstType(field), resolved_field_name, MessageName(desc), |
||||||
|
upbc_name); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteFieldAccessorHazzer(const protobuf::Descriptor* desc, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const FileLayout& layout, Output& output) { |
||||||
|
// Generate hazzer (if any).
|
||||||
|
if (layout.HasHasbit(field) || field->real_containing_oneof()) { |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
// Has presence.
|
||||||
|
output("inline bool has_$0() const { return $1_has_$2(msg_); }\n", |
||||||
|
resolved_field_name, MessageName(desc), upbc_name); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteFieldAccessorClear(const protobuf::Descriptor* desc, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const FileLayout& layout, Output& output) { |
||||||
|
if (layout.HasHasbit(field) || field->real_containing_oneof()) { |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
output("void clear_$0() { $2_clear_$1(msg_); }\n", resolved_field_name, |
||||||
|
upbc_name, MessageName(desc)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteMapFieldAccessors(const protobuf::Descriptor* desc, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
Output& output) { |
||||||
|
const protobuf::Descriptor* entry = field->message_type(); |
||||||
|
const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1); |
||||||
|
const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2); |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
inline size_t $0_size() const { return $1_$3_size(msg_); } |
||||||
|
inline void clear_$0() { $1_clear_$3(msg_); } |
||||||
|
void delete_$0($2 key); |
||||||
|
)cc", |
||||||
|
resolved_field_name, MessageName(desc), CppConstType(key), upbc_name); |
||||||
|
|
||||||
|
if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool set_$0($1 key, $3 value); |
||||||
|
bool set_$0($1 key, $4 value); |
||||||
|
absl::StatusOr<$3> get_$0($1 key); |
||||||
|
)cc", |
||||||
|
resolved_field_name, CppConstType(key), CppConstType(val), |
||||||
|
MessagePtrConstType(val, /* is_const */ true), |
||||||
|
MessagePtrConstType(val, /* is_const */ false)); |
||||||
|
} else { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool set_$0($1 key, $2 value); |
||||||
|
absl::StatusOr<$2> get_$0($1 key); |
||||||
|
)cc", |
||||||
|
resolved_field_name, CppConstType(key), CppConstType(val)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteAccessorsInSource(const protobuf::Descriptor* desc, |
||||||
|
const FileLayout& layout, Output& output) { |
||||||
|
std::string class_name = ClassName(desc); |
||||||
|
absl::StrAppend(&class_name, "Access"); |
||||||
|
output("namespace internal {\n"); |
||||||
|
const char arena_expression[] = "arena_"; |
||||||
|
auto field_names = CreateFieldNameMap(desc); |
||||||
|
|
||||||
|
// Generate const methods.
|
||||||
|
OutputIndenter i(output); |
||||||
|
for (auto field : ::upbc::FieldNumberOrder(desc)) { |
||||||
|
std::string resolved_field_name = ResolveFieldName(field, field_names); |
||||||
|
if (field->is_map()) { |
||||||
|
WriteMapAccessorDefinitions(desc, field, resolved_field_name, class_name, |
||||||
|
output); |
||||||
|
} else if (desc->options().map_entry()) { |
||||||
|
// TODO(b/237399867) Implement map entry
|
||||||
|
} else if (field->is_repeated()) { |
||||||
|
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
WriteRepeatedMessageAccessor(desc, field, resolved_field_name, |
||||||
|
class_name, output); |
||||||
|
} else if (field->cpp_type() == |
||||||
|
protobuf::FieldDescriptor::CPPTYPE_STRING) { |
||||||
|
WriteRepeatedStringAccessor(desc, field, resolved_field_name, |
||||||
|
class_name, output); |
||||||
|
} else { |
||||||
|
WriteRepeatedScalarAccessor(desc, field, resolved_field_name, |
||||||
|
class_name, output); |
||||||
|
} |
||||||
|
} else { |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
// non-repeated field.
|
||||||
|
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $0::$2() const { |
||||||
|
return ::protos::UpbStrToStringView($3_$4(msg_)); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, |
||||||
|
MessageName(desc), upbc_name); |
||||||
|
// Set string.
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
void $0::set_$2($1 value) { |
||||||
|
$4_set_$3(msg_, ::protos::UpbStrFromStringView(value, $5)); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, upbc_name, |
||||||
|
MessageName(desc), arena_expression); |
||||||
|
} else if (field->cpp_type() == |
||||||
|
protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $0::$2() const { |
||||||
|
if (!has_$2()) { |
||||||
|
return $4::default_instance(); |
||||||
|
} |
||||||
|
return ::protos::internal::CreateMessage<$4>((upb_Message*)($3_$5(msg_))); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, MessagePtrConstType(field, /* is_const */ true), |
||||||
|
resolved_field_name, MessageName(desc), |
||||||
|
MessageBaseType(field, /* maybe_const */ false), upbc_name); |
||||||
|
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $0::mutable_$2() { |
||||||
|
return ::protos::internal::CreateMessageProxy<$4>( |
||||||
|
(upb_Message*)($3_mutable_$5(msg_, $6)), $6); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, MessagePtrConstType(field, /* is_const */ false), |
||||||
|
resolved_field_name, MessageName(desc), |
||||||
|
MessageBaseType(field, /* maybe_const */ false), upbc_name, |
||||||
|
arena_expression); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
output("\n"); |
||||||
|
output("} // namespace internal\n\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteRepeatedMessageAccessor(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const absl::string_view class_name, |
||||||
|
Output& output) { |
||||||
|
const char arena_expression[] = "arena_"; |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $0::$2(size_t index) const { |
||||||
|
size_t len; |
||||||
|
auto* ptr = $3_$5(msg_, &len); |
||||||
|
assert(0 <= index && index < len); |
||||||
|
return ::protos::internal::CreateMessage<$4>((upb_Message*)*(ptr + index)); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, MessagePtrConstType(field, /* is_const */ true), |
||||||
|
resolved_field_name, MessageName(message), |
||||||
|
MessageBaseType(field, /* maybe_const */ false), upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
absl::StatusOr<$1> $0::add_$2() { |
||||||
|
auto new_msg = $3_add_$6(msg_, $5); |
||||||
|
if (!new_msg) { |
||||||
|
return ::protos::MessageAllocationError(); |
||||||
|
} |
||||||
|
return ::protos::internal::CreateMessageProxy<$4>((upb_Message*)new_msg, $5); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, MessagePtrConstType(field, /* const */ false), |
||||||
|
resolved_field_name, MessageName(message), |
||||||
|
MessageBaseType(field, /* maybe_const */ false), arena_expression, |
||||||
|
upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $0::mutable_$2(size_t index) const { |
||||||
|
size_t len; |
||||||
|
auto* ptr = $3_$6(msg_, &len); |
||||||
|
assert(0 <= index && index < len); |
||||||
|
return ::protos::internal::CreateMessageProxy<$4>( |
||||||
|
(upb_Message*)*(ptr + index), $5); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, MessagePtrConstType(field, /* is_const */ false), |
||||||
|
resolved_field_name, MessageName(message), |
||||||
|
MessageBaseType(field, /* maybe_const */ false), arena_expression, |
||||||
|
upbc_name); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteRepeatedStringAccessor(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const absl::string_view class_name, |
||||||
|
Output& output) { |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $0::$2(size_t index) const { |
||||||
|
size_t len; |
||||||
|
auto* ptr = $3_mutable_$4(msg_, &len); |
||||||
|
assert(0 <= index && index < len); |
||||||
|
return ::protos::UpbStrToStringView(*(ptr + index)); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, |
||||||
|
MessageName(message), upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::resize_$1(size_t len) { |
||||||
|
return $2_resize_$3(msg_, len, arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, MessageName(message), upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::add_$2($1 val) { |
||||||
|
return $3_add_$4(msg_, ::protos::UpbStrFromStringView(val, arena_), arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, |
||||||
|
MessageName(message), upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
void $0::set_$2(size_t index, $1 val) { |
||||||
|
size_t len; |
||||||
|
auto* ptr = $3_mutable_$4(msg_, &len); |
||||||
|
assert(0 <= index && index < len); |
||||||
|
*(ptr + index) = ::protos::UpbStrFromStringView(val, arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, |
||||||
|
MessageName(message), upbc_name); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteRepeatedScalarAccessor(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const absl::string_view class_name, |
||||||
|
Output& output) { |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$1 $0::$2(size_t index) const { |
||||||
|
size_t len; |
||||||
|
auto* ptr = $3_mutable_$4(msg_, &len); |
||||||
|
assert(0 <= index && index < len); |
||||||
|
return *(ptr + index); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, |
||||||
|
MessageName(message), upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::resize_$1(size_t len) { |
||||||
|
return $2_resize_$3(msg_, len, arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, MessageName(message), upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::add_$2($1 val) { return $3_add_$4(msg_, val, arena_); } |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, |
||||||
|
MessageName(message), upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
void $0::set_$2(size_t index, $1 val) { |
||||||
|
size_t len; |
||||||
|
auto* ptr = $3_mutable_$4(msg_, &len); |
||||||
|
assert(0 <= index && index < len); |
||||||
|
*(ptr + index) = val; |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, CppConstType(field), resolved_field_name, |
||||||
|
MessageName(message), upbc_name); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteMapAccessorDefinitions(const protobuf::Descriptor* message, |
||||||
|
const protobuf::FieldDescriptor* field, |
||||||
|
const absl::string_view resolved_field_name, |
||||||
|
const absl::string_view class_name, |
||||||
|
Output& output) { |
||||||
|
const protobuf::Descriptor* entry = field->message_type(); |
||||||
|
const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1); |
||||||
|
const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2); |
||||||
|
absl::string_view upbc_name = field->name(); |
||||||
|
absl::string_view converted_key_name = "key"; |
||||||
|
absl::string_view optional_conversion_code = ""; |
||||||
|
|
||||||
|
if (key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) { |
||||||
|
// Insert conversion from absl::string_view to upb_StringView.
|
||||||
|
// Creates upb_StringView on stack to prevent allocation.
|
||||||
|
converted_key_name = "upb_key"; |
||||||
|
optional_conversion_code = |
||||||
|
"upb_StringView upb_key = {key.data(), key.size()};\n"; |
||||||
|
} |
||||||
|
if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::set_$1($2 key, $3 value) { |
||||||
|
$6return $4_$8_set(msg_, $7, ($5*)value->msg(), arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), |
||||||
|
MessagePtrConstType(val, /* is_const */ true), MessageName(message), |
||||||
|
MessageName(val->message_type()), optional_conversion_code, |
||||||
|
converted_key_name, upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::set_$1($2 key, $3 value) { |
||||||
|
$6return $4_$8_set(msg_, $7, ($5*)value->msg(), arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), |
||||||
|
MessagePtrConstType(val, /* is_const */ false), MessageName(message), |
||||||
|
MessageName(val->message_type()), optional_conversion_code, |
||||||
|
converted_key_name, upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
absl::StatusOr<$3> $0::get_$1($2 key) { |
||||||
|
$5* msg_value; |
||||||
|
$7bool success = $4_$9_get(msg_, $8, &msg_value); |
||||||
|
if (success) { |
||||||
|
return ::protos::internal::CreateMessage<$6>(msg_value); |
||||||
|
} |
||||||
|
return absl::NotFoundError(""); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), |
||||||
|
MessagePtrConstType(val, /* is_const */ true), MessageName(message), |
||||||
|
MessageName(val->message_type()), |
||||||
|
QualifiedClassName(val->message_type()), optional_conversion_code, |
||||||
|
converted_key_name, upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
void $0::delete_$1($2 key) { $6$4_$8_delete(msg_, $7); } |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), |
||||||
|
MessagePtrConstType(val, /* is_const */ false), MessageName(message), |
||||||
|
MessageName(val->message_type()), optional_conversion_code, |
||||||
|
converted_key_name, upbc_name); |
||||||
|
} else if (val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::set_$1($2 key, $3 value) { |
||||||
|
$5return $4_$7_set(msg_, $6, |
||||||
|
::protos::UpbStrFromStringView(value, arena_), |
||||||
|
arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), CppConstType(val), |
||||||
|
MessageName(message), optional_conversion_code, converted_key_name, |
||||||
|
upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
absl::StatusOr<$3> $0::get_$1($2 key) { |
||||||
|
upb_StringView value; |
||||||
|
$5bool success = $4_$7_get(msg_, $6, &value); |
||||||
|
if (success) { |
||||||
|
return absl::string_view(value.data, value.size); |
||||||
|
} |
||||||
|
return absl::NotFoundError(""); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), CppConstType(val), |
||||||
|
MessageName(message), optional_conversion_code, converted_key_name, |
||||||
|
upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
void $0::delete_$1($2 key) { $5$4_$7_delete(msg_, $6); } |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), CppConstType(val), |
||||||
|
MessageName(message), optional_conversion_code, converted_key_name, |
||||||
|
upbc_name); |
||||||
|
} else { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
bool $0::set_$1($2 key, $3 value) { |
||||||
|
$5return $4_$7_set(msg_, $6, value, arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), CppConstType(val), |
||||||
|
MessageName(message), optional_conversion_code, converted_key_name, |
||||||
|
upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
absl::StatusOr<$3> $0::get_$1($2 key) { |
||||||
|
$3 value; |
||||||
|
$5bool success = $4_$7_get(msg_, $6, &value); |
||||||
|
if (success) { |
||||||
|
return value; |
||||||
|
} |
||||||
|
return absl::NotFoundError(""); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), CppConstType(val), |
||||||
|
MessageName(message), optional_conversion_code, converted_key_name, |
||||||
|
upbc_name); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
void $0::delete_$1($2 key) { $5$4_$7_delete(msg_, $6); } |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name, CppConstType(key), CppConstType(val), |
||||||
|
MessageName(message), optional_conversion_code, converted_key_name, |
||||||
|
upbc_name); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteUsingAccessorsInHeader(const protobuf::Descriptor* desc, |
||||||
|
MessageClassType handle_type, Output& output) { |
||||||
|
FileLayout layout(desc->file()); |
||||||
|
bool read_only = handle_type == MessageClassType::kMessageCProxy; |
||||||
|
|
||||||
|
// Generate const methods.
|
||||||
|
OutputIndenter i(output); |
||||||
|
std::string class_name = ClassName(desc); |
||||||
|
auto field_names = CreateFieldNameMap(desc); |
||||||
|
|
||||||
|
for (auto field : ::upbc::FieldNumberOrder(desc)) { |
||||||
|
std::string resolved_field_name = ResolveFieldName(field, field_names); |
||||||
|
// Generate hazzer (if any).
|
||||||
|
if (layout.HasHasbit(field) || field->real_containing_oneof()) { |
||||||
|
// Has presence.
|
||||||
|
output("using $0Access::has_$1;\n", class_name, resolved_field_name); |
||||||
|
} |
||||||
|
// Generate clear.
|
||||||
|
if (layout.HasHasbit(field) || field->real_containing_oneof()) { |
||||||
|
output("using $0Access::clear_$1;\n", class_name, resolved_field_name); |
||||||
|
} |
||||||
|
if (field->is_map()) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
using $0Access::$1_size; |
||||||
|
using $0Access::clear_$1; |
||||||
|
using $0Access::delete_$1; |
||||||
|
using $0Access::get_$1; |
||||||
|
using $0Access::set_$1; |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name); |
||||||
|
} else if (desc->options().map_entry()) { |
||||||
|
// TODO(b/237399867) Implement map entry
|
||||||
|
} else if (field->is_repeated()) { |
||||||
|
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
using $0Access::$1; |
||||||
|
using $0Access::$1_size; |
||||||
|
using $0Access::mutable_$1; |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name); |
||||||
|
if (!read_only) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
using $0Access::add_$1; |
||||||
|
using $0Access::clear_$1; |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name); |
||||||
|
} |
||||||
|
} else { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
using $0Access::$1; |
||||||
|
using $0Access::$1_size; |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name); |
||||||
|
if (!read_only) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
using $0Access::add_$1; |
||||||
|
using $0Access::clear_$1; |
||||||
|
using $0Access::resize_$1; |
||||||
|
using $0Access::set_$1; |
||||||
|
)cc", |
||||||
|
class_name, resolved_field_name); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
output("using $0Access::$1;\n", ClassName(desc), resolved_field_name); |
||||||
|
if (!read_only) { |
||||||
|
output("using $0Access::mutable_$1;\n", class_name, |
||||||
|
resolved_field_name); |
||||||
|
} |
||||||
|
} else { |
||||||
|
output("using $0Access::$1;\n", class_name, resolved_field_name); |
||||||
|
if (!read_only) { |
||||||
|
output("using $0Access::set_$1;\n", class_name, resolved_field_name); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
output("using $0Access::msg;\n", class_name); |
||||||
|
} |
||||||
|
|
||||||
|
std::string ResolveFieldName(const protobuf::FieldDescriptor* field, |
||||||
|
const NameToFieldDescriptorMap& field_names) { |
||||||
|
// C++ implementation specific reserved names.
|
||||||
|
static const auto& kReservedNames = |
||||||
|
*new absl::flat_hash_set<absl::string_view>({ |
||||||
|
"msg", |
||||||
|
"msg_", |
||||||
|
"arena", |
||||||
|
"arena_", |
||||||
|
}); |
||||||
|
|
||||||
|
// List of generated accessor prefixes to check against.
|
||||||
|
// Example:
|
||||||
|
// optional repeated string phase = 236;
|
||||||
|
// optional bool clear_phase = 237;
|
||||||
|
static constexpr absl::string_view kAccessorPrefixes[] = { |
||||||
|
"clear_", |
||||||
|
"delete_", |
||||||
|
"add_", |
||||||
|
"resize_", |
||||||
|
}; |
||||||
|
|
||||||
|
absl::string_view field_name = field->name(); |
||||||
|
if (kReservedNames.count(field_name) > 0) { |
||||||
|
if (absl::EndsWith(field_name, "_")) { |
||||||
|
return absl::StrCat(field_name, "_"); |
||||||
|
} else { |
||||||
|
return absl::StrCat(field_name, "__"); |
||||||
|
} |
||||||
|
} |
||||||
|
for (const auto prefix : kAccessorPrefixes) { |
||||||
|
// If field name starts with a prefix such as clear_ and the proto
|
||||||
|
// contains a field name with trailing end, depending on type of field
|
||||||
|
// (repeated, map, message) we have a conflict to resolve.
|
||||||
|
if (absl::StartsWith(field_name, prefix)) { |
||||||
|
auto match = field_names.find(field_name.substr(prefix.size())); |
||||||
|
if (match != field_names.end()) { |
||||||
|
const auto* candidate = match->second; |
||||||
|
if (candidate->is_repeated() || candidate->is_map()) { |
||||||
|
return absl::StrCat(field_name, "_"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return upbc::ResolveKeywordConflict(std::string(field_name)); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos_generator
|
@ -0,0 +1,46 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_GENERATOR_ACCESSORS_H_ |
||||||
|
#define UPB_PROTOS_GENERATOR_ACCESSORS_H_ |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "protos_generator/gen_utils.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
#include "upbc/file_layout.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
void WriteFieldAccessorsInHeader(const protobuf::Descriptor* desc, |
||||||
|
Output& output); |
||||||
|
void WriteAccessorsInSource(const protobuf::Descriptor* desc, |
||||||
|
const ::upbc::FileLayout& layout, Output& output); |
||||||
|
void WriteUsingAccessorsInHeader(const protobuf::Descriptor* desc, |
||||||
|
MessageClassType handle_type, Output& output); |
||||||
|
} // namespace protos_generator
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_GENERATOR_ACCESSORS_H_
|
@ -0,0 +1,126 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "protos_generator/gen_enums.h" |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.pb.h" |
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
// Convert enum value to C++ literal.
|
||||||
|
//
|
||||||
|
// In C++, an value of -2147483648 gets interpreted as the negative of
|
||||||
|
// 2147483648, and since 2147483648 can't fit in an integer, this produces a
|
||||||
|
// compiler warning. This works around that issue.
|
||||||
|
std::string EnumInt32ToString(int number) { |
||||||
|
if (number == std::numeric_limits<int32_t>::min()) { |
||||||
|
// This needs to be special-cased, see explanation here:
|
||||||
|
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661
|
||||||
|
return absl::StrCat(number + 1, " - 1"); |
||||||
|
} else { |
||||||
|
return absl::StrCat(number); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
std::string EnumTypeName(const protobuf::EnumDescriptor* enum_descriptor) { |
||||||
|
auto containing_type = enum_descriptor->containing_type(); |
||||||
|
if (containing_type == nullptr) { |
||||||
|
// enums types with no package name are prefixed with protos_ to prevent
|
||||||
|
// conflicts with generated C headers.
|
||||||
|
if (enum_descriptor->file()->package().empty()) { |
||||||
|
return absl::StrCat("protos_", ToCIdent(enum_descriptor->name())); |
||||||
|
} |
||||||
|
return ToCIdent(enum_descriptor->name()); |
||||||
|
} else { |
||||||
|
return ToCIdent( |
||||||
|
absl::StrCat(containing_type->name(), "_", enum_descriptor->name())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
std::string EnumValueSymbolInNameSpace( |
||||||
|
const protobuf::EnumDescriptor* desc, |
||||||
|
const protobuf::EnumValueDescriptor* value) { |
||||||
|
auto containing_type = desc->containing_type(); |
||||||
|
if (containing_type != nullptr) { |
||||||
|
return ToCIdent(absl::StrCat(containing_type->name(), "_", desc->name(), |
||||||
|
"_", value->name())); |
||||||
|
} else { |
||||||
|
// protos enum values with no package name are prefixed with protos_ to
|
||||||
|
// prevent conflicts with generated C headers.
|
||||||
|
if (desc->file()->package().empty()) { |
||||||
|
return absl::StrCat("protos_", ToCIdent(value->name())); |
||||||
|
} |
||||||
|
return ToCIdent(value->name()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteEnumValues(const protobuf::EnumDescriptor* desc, Output& output) { |
||||||
|
std::vector<const protobuf::EnumValueDescriptor*> values; |
||||||
|
auto value_count = desc->value_count(); |
||||||
|
values.reserve(value_count); |
||||||
|
for (int i = 0; i < value_count; i++) { |
||||||
|
values.push_back(desc->value(i)); |
||||||
|
} |
||||||
|
std::sort(values.begin(), values.end(), |
||||||
|
[](const protobuf::EnumValueDescriptor* a, |
||||||
|
const protobuf::EnumValueDescriptor* b) { |
||||||
|
return a->number() < b->number(); |
||||||
|
}); |
||||||
|
|
||||||
|
for (size_t i = 0; i < values.size(); i++) { |
||||||
|
auto value = values[i]; |
||||||
|
output(" $0", EnumValueSymbolInNameSpace(desc, value)); |
||||||
|
if (value->options().deprecated()) { |
||||||
|
output(" ABSL_DEPRECATED(\"Proto enum $0\")", |
||||||
|
EnumValueSymbolInNameSpace(desc, value)); |
||||||
|
} |
||||||
|
output(" = $0", EnumInt32ToString(value->number())); |
||||||
|
if (i != values.size() - 1) { |
||||||
|
output(","); |
||||||
|
} |
||||||
|
output("\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteEnumDeclarations( |
||||||
|
const std::vector<const protobuf::EnumDescriptor*>& enums, Output& output) { |
||||||
|
for (auto enumdesc : enums) { |
||||||
|
output("enum $0 : int {\n", EnumTypeName(enumdesc)); |
||||||
|
WriteEnumValues(enumdesc, output); |
||||||
|
output("};\n\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteHeaderEnumForwardDecls( |
||||||
|
std::vector<const protobuf::EnumDescriptor*>& enums, Output& output) { |
||||||
|
for (const auto* enumdesc : enums) { |
||||||
|
output("enum $0 : int;\n", EnumTypeName(enumdesc)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos_generator
|
@ -0,0 +1,44 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_GENERATOR_ENUMS_H_ |
||||||
|
#define UPB_PROTOS_GENERATOR_ENUMS_H_ |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
std::string EnumTypeName(const protobuf::EnumDescriptor* enum_descriptor); |
||||||
|
void WriteHeaderEnumForwardDecls( |
||||||
|
std::vector<const protobuf::EnumDescriptor*>& enums, Output& output); |
||||||
|
void WriteEnumDeclarations( |
||||||
|
const std::vector<const protobuf::EnumDescriptor*>& enums, Output& output); |
||||||
|
|
||||||
|
} // namespace protos_generator
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_GENERATOR_ENUMS_H_
|
@ -0,0 +1,110 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "protos_generator/gen_extensions.h" |
||||||
|
|
||||||
|
#include "absl/strings/str_cat.h" |
||||||
|
#include "protos_generator/gen_utils.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
std::string ExtensionIdentifierBase(const protobuf::FieldDescriptor* ext) { |
||||||
|
assert(ext->is_extension()); |
||||||
|
std::string ext_scope; |
||||||
|
if (ext->extension_scope()) { |
||||||
|
return MessageName(ext->extension_scope()); |
||||||
|
} else { |
||||||
|
return ToCIdent(ext->file()->package()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
std::string ContainingTypeName(const protobuf::FieldDescriptor* ext) { |
||||||
|
return ext->containing_type()->file() != ext->file() |
||||||
|
? QualifiedClassName(ext->containing_type()) |
||||||
|
: ClassName(ext->containing_type()); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteExtensionIdentifierHeader(const protobuf::FieldDescriptor* ext, |
||||||
|
Output& output) { |
||||||
|
std::string mini_table_name = |
||||||
|
absl::StrCat(ExtensionIdentifierBase(ext), "_", ext->name(), "_ext"); |
||||||
|
if (ext->extension_scope()) { |
||||||
|
output(R"cc( |
||||||
|
static ::protos::internal::ExtensionIdentifier<$0, $1> $2; |
||||||
|
)cc", |
||||||
|
ContainingTypeName(ext), CppTypeParameterName(ext), ext->name()); |
||||||
|
} else { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
extern ::protos::internal::ExtensionIdentifier<$0, $1> $2; |
||||||
|
)cc", |
||||||
|
ContainingTypeName(ext), CppTypeParameterName(ext), ext->name()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteExtensionIdentifiersHeader( |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& extensions, |
||||||
|
Output& output) { |
||||||
|
for (const auto* ext : extensions) { |
||||||
|
if (!ext->extension_scope()) { |
||||||
|
WriteExtensionIdentifierHeader(ext, output); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteExtensionIdentifier(const protobuf::FieldDescriptor* ext, |
||||||
|
Output& output) { |
||||||
|
std::string mini_table_name = |
||||||
|
absl::StrCat(ExtensionIdentifierBase(ext), "_", ext->name(), "_ext"); |
||||||
|
if (ext->extension_scope()) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
::protos::internal::ExtensionIdentifier<$0, $3> $4::$2(&$1); |
||||||
|
)cc", |
||||||
|
ContainingTypeName(ext), mini_table_name, ext->name(), |
||||||
|
CppTypeParameterName(ext), ClassName(ext->extension_scope())); |
||||||
|
} else { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
::protos::internal::ExtensionIdentifier<$0, $3> $2(&$1); |
||||||
|
)cc", |
||||||
|
ContainingTypeName(ext), mini_table_name, ext->name(), |
||||||
|
CppTypeParameterName(ext)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteExtensionIdentifiers( |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& extensions, |
||||||
|
Output& output) { |
||||||
|
for (const auto* ext : extensions) { |
||||||
|
if (!ext->extension_scope()) { |
||||||
|
WriteExtensionIdentifier(ext, output); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos_generator
|
@ -0,0 +1,49 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_GENERATOR_GEN_EXTENSIONS_H_ |
||||||
|
#define UPB_PROTOS_GENERATOR_GEN_EXTENSIONS_H_ |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
void WriteExtensionIdentifiersHeader( |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& extensions, |
||||||
|
Output& output); |
||||||
|
void WriteExtensionIdentifierHeader(const protobuf::FieldDescriptor* ext, |
||||||
|
Output& output); |
||||||
|
void WriteExtensionIdentifiers( |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& extensions, |
||||||
|
Output& output); |
||||||
|
void WriteExtensionIdentifier(const protobuf::FieldDescriptor* ext, |
||||||
|
Output& output); |
||||||
|
|
||||||
|
} // namespace protos_generator
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_GENERATOR_GEN_EXTENSIONS_H_
|
@ -0,0 +1,380 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "protos_generator/gen_messages.h" |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.pb.h" |
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "protos_generator/gen_accessors.h" |
||||||
|
#include "protos_generator/gen_extensions.h" |
||||||
|
#include "protos_generator/gen_utils.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
#include "upbc/common.h" |
||||||
|
#include "upbc/file_layout.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor, |
||||||
|
Output& output); |
||||||
|
void WriteModelPublicDeclaration( |
||||||
|
const protobuf::Descriptor* descriptor, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output); |
||||||
|
void WriteExtensionIdentifiersInClassHeader( |
||||||
|
const protobuf::Descriptor* message, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output); |
||||||
|
void WriteModelProxyDeclaration(const protobuf::Descriptor* descriptor, |
||||||
|
Output& output); |
||||||
|
void WriteModelCProxyDeclaration(const protobuf::Descriptor* descriptor, |
||||||
|
Output& output); |
||||||
|
void WriteInternalForwardDeclarationsInHeader( |
||||||
|
const protobuf::Descriptor* message, Output& output); |
||||||
|
void WriteDefaultInstanceHeader(const protobuf::Descriptor* message, |
||||||
|
Output& output); |
||||||
|
void WriteExtensionIdentifiersImplementation( |
||||||
|
const protobuf::Descriptor* message, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output); |
||||||
|
|
||||||
|
// Writes message class declarations into .upb.proto.h.
|
||||||
|
//
|
||||||
|
// For each proto Foo, FooAccess and FooProxy/FooCProxy are generated
|
||||||
|
// that are exposed to users as Foo , Ptr<Foo> and Ptr<const Foo>.
|
||||||
|
void WriteMessageClassDeclarations( |
||||||
|
const protobuf::Descriptor* descriptor, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output) { |
||||||
|
if (IsMapEntryMessage(descriptor)) { |
||||||
|
// Skip map entry generation. Low level accessors for maps are
|
||||||
|
// generated that don't require a separate map type.
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Forward declaration of Proto Class for GCC handling of free friend method.
|
||||||
|
output("class $0;", ClassName(descriptor)); |
||||||
|
output("namespace internal {\n"); |
||||||
|
WriteModelAccessDeclaration(descriptor, output); |
||||||
|
output("\n"); |
||||||
|
WriteInternalForwardDeclarationsInHeader(descriptor, output); |
||||||
|
output("\n"); |
||||||
|
output("} // namespace internal\n"); |
||||||
|
WriteModelPublicDeclaration(descriptor, file_exts, output); |
||||||
|
output("namespace internal {\n"); |
||||||
|
WriteModelProxyDeclaration(descriptor, output); |
||||||
|
WriteModelCProxyDeclaration(descriptor, output); |
||||||
|
output("} // namespace internal\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor, |
||||||
|
Output& output) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
|
||||||
|
class $0Access { |
||||||
|
public: |
||||||
|
$0Access() {} |
||||||
|
$0Access($1* msg, upb_Arena* arena) : msg_(msg), arena_(arena) {} // NOLINT
|
||||||
|
$0Access(const $1* msg, upb_Arena* arena) |
||||||
|
: msg_(const_cast<$1*>(msg)), arena_(arena) {} // NOLINT
|
||||||
|
void* GetInternalArena() const { return arena_; } |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor)); |
||||||
|
WriteFieldAccessorsInHeader(descriptor, output); |
||||||
|
output.Indent(); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
private: |
||||||
|
void* msg() const { return msg_; } |
||||||
|
|
||||||
|
friend class $2; |
||||||
|
friend class $0Proxy; |
||||||
|
friend class $0CProxy; |
||||||
|
friend void* ::protos::internal::GetInternalMsg<$2>(const $2& message); |
||||||
|
friend void* ::protos::internal::GetInternalMsg<$2>( |
||||||
|
const ::protos::Ptr<$2>& message); |
||||||
|
$1* msg_; |
||||||
|
upb_Arena* arena_; |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor), |
||||||
|
QualifiedClassName(descriptor)); |
||||||
|
output.Outdent(); |
||||||
|
output("};\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteModelPublicDeclaration( |
||||||
|
const protobuf::Descriptor* descriptor, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
class $0 final : private internal::$0Access { |
||||||
|
public: |
||||||
|
using Access = internal::$0Access; |
||||||
|
using Proxy = internal::$0Proxy; |
||||||
|
using CProxy = internal::$0CProxy; |
||||||
|
$0(); |
||||||
|
$0(const $0& m) = delete; |
||||||
|
$0& operator=(const $0& m) = delete; |
||||||
|
$0($0&& m) |
||||||
|
: Access(m.msg_, m.arena_), |
||||||
|
owned_arena_(std::move(m.owned_arena_)) {} |
||||||
|
$0& operator=($0&& m) { |
||||||
|
msg_ = m.msg_; |
||||||
|
arena_ = m.arena_; |
||||||
|
m.msg_ = nullptr; |
||||||
|
m.arena_ = nullptr; |
||||||
|
owned_arena_ = std::move(m.owned_arena_); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
)cc", |
||||||
|
ClassName(descriptor)); |
||||||
|
|
||||||
|
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessage, output); |
||||||
|
WriteDefaultInstanceHeader(descriptor, output); |
||||||
|
WriteExtensionIdentifiersInClassHeader(descriptor, file_exts, output); |
||||||
|
output.Indent(); |
||||||
|
output.Indent(); |
||||||
|
if (descriptor->extension_range_count()) { |
||||||
|
// for typetrait checking
|
||||||
|
output("using ExtendableType = $0;\n", ClassName(descriptor)); |
||||||
|
} |
||||||
|
// Note: free function friends that are templates such as ::protos::Parse
|
||||||
|
// require explicit <$2> type parameter in declaration to be able to compile
|
||||||
|
// with gcc otherwise the compiler will fail with
|
||||||
|
// "has not been declared within namespace" error. Even though there is a
|
||||||
|
// namespace qualifier, cross namespace matching fails.
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
static const upb_MiniTable* minitable(); |
||||||
|
using $0Access::GetInternalArena; |
||||||
|
|
||||||
|
private: |
||||||
|
$0(upb_Message* msg, upb_Arena* arena) : $0Access() { |
||||||
|
msg_ = ($1*)msg; |
||||||
|
arena_ = owned_arena_.ptr(); |
||||||
|
upb_Arena_Fuse(arena_, arena); |
||||||
|
} |
||||||
|
::protos::Arena owned_arena_; |
||||||
|
friend Proxy; |
||||||
|
friend CProxy; |
||||||
|
friend absl::StatusOr<$2>(::protos::Parse<$2>(absl::string_view bytes, |
||||||
|
int options)); |
||||||
|
friend absl::StatusOr<$2>(::protos::Parse<$2>( |
||||||
|
absl::string_view bytes, |
||||||
|
const ::protos::ExtensionRegistry& extension_registry, |
||||||
|
int options)); |
||||||
|
friend upb_Arena* ::protos::internal::GetArena<$0>(const $0& message); |
||||||
|
friend upb_Arena* ::protos::internal::GetArena<$0>( |
||||||
|
const ::protos::Ptr<$0>& message); |
||||||
|
friend $0(::protos::internal::MoveMessage<$0>(upb_Message* msg, |
||||||
|
upb_Arena* arena)); |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor), |
||||||
|
QualifiedClassName(descriptor)); |
||||||
|
output.Outdent(); |
||||||
|
output("};\n\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteModelProxyDeclaration(const protobuf::Descriptor* descriptor, |
||||||
|
Output& output) { |
||||||
|
// Foo::Proxy.
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
class $0Proxy final : private internal::$0Access { |
||||||
|
public: |
||||||
|
$0Proxy() = delete; |
||||||
|
$0Proxy(const $0Proxy& m) : internal::$0Access() { |
||||||
|
msg_ = m.msg_; |
||||||
|
arena_ = m.arena_; |
||||||
|
} |
||||||
|
$0Proxy operator=(const $0Proxy& m) { |
||||||
|
msg_ = m.msg_; |
||||||
|
arena_ = m.arena_; |
||||||
|
return *this; |
||||||
|
} |
||||||
|
using $0Access::GetInternalArena; |
||||||
|
)cc", |
||||||
|
ClassName(descriptor)); |
||||||
|
|
||||||
|
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessageProxy, |
||||||
|
output); |
||||||
|
output("\n"); |
||||||
|
output.Indent(1); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
private: |
||||||
|
$0Proxy(void* msg, upb_Arena* arena) : internal::$0Access(($1*)msg, arena) {} |
||||||
|
friend $0::Proxy(::protos::CreateMessage<$0>(::protos::Arena& arena)); |
||||||
|
friend $0::Proxy(::protos::internal::CreateMessageProxy<$0>( |
||||||
|
upb_Message*, upb_Arena*)); |
||||||
|
friend class $0CProxy; |
||||||
|
friend class $0Access; |
||||||
|
friend class ::protos::Ptr<$0>; |
||||||
|
friend class ::protos::Ptr<const $0>; |
||||||
|
friend upb_Arena* ::protos::internal::GetArena<$2>(const $2& message); |
||||||
|
friend upb_Arena* ::protos::internal::GetArena<$2>( |
||||||
|
const ::protos::Ptr<$2>& message); |
||||||
|
static void Rebind($0Proxy& lhs, const $0Proxy& rhs) { |
||||||
|
lhs.msg_ = rhs.msg_; |
||||||
|
lhs.arena_ = rhs.arena_; |
||||||
|
} |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor), |
||||||
|
QualifiedClassName(descriptor)); |
||||||
|
output.Outdent(1); |
||||||
|
output("};\n\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteModelCProxyDeclaration(const protobuf::Descriptor* descriptor, |
||||||
|
Output& output) { |
||||||
|
// Foo::CProxy.
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
class $0CProxy final : private internal::$0Access { |
||||||
|
public: |
||||||
|
$0CProxy() = delete; |
||||||
|
$0CProxy(const $0* m) : internal::$0Access(m->msg_, nullptr) {} |
||||||
|
using $0Access::GetInternalArena; |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor)); |
||||||
|
|
||||||
|
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessageProxy, |
||||||
|
output); |
||||||
|
|
||||||
|
output.Indent(1); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
private: |
||||||
|
$0CProxy(void* msg) : internal::$0Access(($1*)msg, nullptr){}; |
||||||
|
friend $0::CProxy(::protos::internal::CreateMessage<$0>(upb_Message* msg)); |
||||||
|
friend class ::protos::Ptr<$0>; |
||||||
|
friend class ::protos::Ptr<const $0>; |
||||||
|
static void Rebind($0CProxy& lhs, const $0CProxy& rhs) { |
||||||
|
lhs.msg_ = rhs.msg_; |
||||||
|
lhs.arena_ = rhs.arena_; |
||||||
|
} |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor)); |
||||||
|
output.Outdent(1); |
||||||
|
output("};\n\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteDefaultInstanceHeader(const protobuf::Descriptor* message, |
||||||
|
Output& output) { |
||||||
|
output(" static ::protos::Ptr<const $0> default_instance();\n", |
||||||
|
ClassName(message)); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteMessageImplementation( |
||||||
|
const protobuf::Descriptor* descriptor, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output) { |
||||||
|
bool message_is_map_entry = descriptor->options().map_entry(); |
||||||
|
if (!message_is_map_entry) { |
||||||
|
// Constructor.
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
$0::$0() : $0Access() { |
||||||
|
arena_ = owned_arena_.ptr(); |
||||||
|
msg_ = $1_new(arena_); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor)); |
||||||
|
// Minitable
|
||||||
|
OutputIndenter i(output); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
const upb_MiniTable* $0::minitable() { return &$1; } |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), ::upbc::MessageInit(descriptor)); |
||||||
|
} |
||||||
|
|
||||||
|
::upbc::FileLayout layout(descriptor->file()); |
||||||
|
WriteAccessorsInSource(descriptor, layout, output); |
||||||
|
|
||||||
|
if (!message_is_map_entry) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
struct $0DefaultTypeInternal { |
||||||
|
$1* msg; |
||||||
|
}; |
||||||
|
$0DefaultTypeInternal _$0_default_instance_ = |
||||||
|
$0DefaultTypeInternal{$1_new(upb_Arena_New())}; |
||||||
|
)cc", |
||||||
|
ClassName(descriptor), MessageName(descriptor)); |
||||||
|
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
::protos::Ptr<const $0> $0::default_instance() { |
||||||
|
return ::protos::internal::CreateMessage<$0>( |
||||||
|
(upb_Message *)_$0_default_instance_.msg); |
||||||
|
} |
||||||
|
)cc", |
||||||
|
ClassName(descriptor)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteInternalForwardDeclarationsInHeader( |
||||||
|
const protobuf::Descriptor* message, Output& output) { |
||||||
|
// Write declaration for internal re-usable default_instance without
|
||||||
|
// leaking implementation.
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
struct $0DefaultTypeInternal; |
||||||
|
extern $0DefaultTypeInternal _$0_default_instance_; |
||||||
|
)cc", |
||||||
|
ClassName(message)); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteExtensionIdentifiersInClassHeader( |
||||||
|
const protobuf::Descriptor* message, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output) { |
||||||
|
for (auto* ext : file_exts) { |
||||||
|
if (ext->extension_scope() && |
||||||
|
ext->extension_scope()->full_name() == message->full_name()) { |
||||||
|
WriteExtensionIdentifierHeader(ext, output); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteExtensionIdentifiersImplementation( |
||||||
|
const protobuf::Descriptor* message, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output) { |
||||||
|
for (auto* ext : file_exts) { |
||||||
|
if (ext->extension_scope() && |
||||||
|
ext->extension_scope()->full_name() == message->full_name()) { |
||||||
|
WriteExtensionIdentifier(ext, output); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos_generator
|
@ -0,0 +1,47 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_GENERATOR_GEN_MESSAGES_H_ |
||||||
|
#define UPB_PROTOS_GENERATOR_GEN_MESSAGES_H_ |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
void WriteMessageClassDeclarations( |
||||||
|
const protobuf::Descriptor* descriptor, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output); |
||||||
|
void WriteMessageImplementation( |
||||||
|
const protobuf::Descriptor* descriptor, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output); |
||||||
|
} // namespace protos_generator
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_GENERATOR_GEN_MESSAGES_H_
|
@ -0,0 +1,203 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "protos_generator/gen_utils.h" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/strings/str_cat.h" |
||||||
|
// begin:google_only
|
||||||
|
// #include "absl/log/check.h"
|
||||||
|
// #include "absl/strings/str_replace.h"
|
||||||
|
// end:google_only
|
||||||
|
#include "absl/strings/str_split.h" |
||||||
|
#include "upbc/keywords.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
// begin:github_only
|
||||||
|
#ifndef DCHECK |
||||||
|
#ifndef NDEBUG |
||||||
|
#define DCHECK(condition) if(!(condition)) LOG(FATAL); |
||||||
|
#else |
||||||
|
#define DCHECK(condition) if(!(true || condition)) LOG(FATAL); |
||||||
|
#endif |
||||||
|
#endif |
||||||
|
// end:github_only
|
||||||
|
|
||||||
|
std::string DotsToColons(const std::string& name) { |
||||||
|
return absl::StrReplaceAll(name, {{".", "::"}}); |
||||||
|
} |
||||||
|
|
||||||
|
std::string Namespace(const std::string& package) { |
||||||
|
if (package.empty()) return ""; |
||||||
|
return "::" + DotsToColons(package); |
||||||
|
} |
||||||
|
|
||||||
|
// Return the qualified C++ name for a file level symbol.
|
||||||
|
std::string QualifiedFileLevelSymbol(const protobuf::FileDescriptor* file, |
||||||
|
const std::string& name) { |
||||||
|
if (file->package().empty()) { |
||||||
|
return absl::StrCat("::", name); |
||||||
|
} |
||||||
|
// Append ::protos postfix to package name.
|
||||||
|
return absl::StrCat(Namespace(file->package()), "::protos::", name); |
||||||
|
} |
||||||
|
|
||||||
|
std::string ClassName(const protobuf::Descriptor* descriptor) { |
||||||
|
const protobuf::Descriptor* parent = descriptor->containing_type(); |
||||||
|
std::string res; |
||||||
|
if (parent) res += ClassName(parent) + "_"; |
||||||
|
absl::StrAppend(&res, descriptor->name()); |
||||||
|
return ::upbc::ResolveKeywordConflict(res); |
||||||
|
} |
||||||
|
|
||||||
|
std::string QualifiedClassName(const protobuf::Descriptor* descriptor) { |
||||||
|
return QualifiedFileLevelSymbol(descriptor->file(), ClassName(descriptor)); |
||||||
|
} |
||||||
|
|
||||||
|
std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor) { |
||||||
|
return QualifiedFileLevelSymbol( |
||||||
|
descriptor->file(), absl::StrCat("internal::", ClassName(descriptor))); |
||||||
|
} |
||||||
|
|
||||||
|
std::string CppSourceFilename(const google::protobuf::FileDescriptor* file) { |
||||||
|
return StripExtension(file->name()) + ".upb.proto.cc"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string UpbCFilename(const google::protobuf::FileDescriptor* file) { |
||||||
|
return StripExtension(file->name()) + ".upb.h"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file) { |
||||||
|
return StripExtension(file->name()) + ".upb.fwd.h"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file) { |
||||||
|
return StripExtension(file->name()) + ".upb.proto.h"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string NamespaceFromPackageName(absl::string_view package_name) { |
||||||
|
return absl::StrCat(absl::StrReplaceAll(package_name, {{".", "::"}}), |
||||||
|
"::protos"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output) { |
||||||
|
// Skip namespace generation if package name is not specified.
|
||||||
|
if (file->package().empty()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
output("namespace $0 {\n\n", NamespaceFromPackageName(file->package())); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output) { |
||||||
|
if (file->package().empty()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
output("} // namespace $0\n\n", NamespaceFromPackageName(file->package())); |
||||||
|
} |
||||||
|
|
||||||
|
std::string CppTypeInternal(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const, bool is_type_parameter) { |
||||||
|
std::string maybe_const = is_const ? "const " : ""; |
||||||
|
switch (field->cpp_type()) { |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { |
||||||
|
if (is_type_parameter) { |
||||||
|
return absl::StrCat(maybe_const, |
||||||
|
QualifiedClassName(field->message_type())); |
||||||
|
} else { |
||||||
|
return absl::StrCat(maybe_const, |
||||||
|
QualifiedClassName(field->message_type()), "*"); |
||||||
|
} |
||||||
|
} |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_BOOL: |
||||||
|
return "bool"; |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_FLOAT: |
||||||
|
return "float"; |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_INT32: |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_ENUM: |
||||||
|
return "int32_t"; |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_UINT32: |
||||||
|
return "uint32_t"; |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_DOUBLE: |
||||||
|
return "double"; |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_INT64: |
||||||
|
return "int64_t"; |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_UINT64: |
||||||
|
return "uint64_t"; |
||||||
|
case protobuf::FieldDescriptor::CPPTYPE_STRING: |
||||||
|
return "absl::string_view"; |
||||||
|
default: |
||||||
|
LOG(FATAL) << "Unexpected type: " << field->cpp_type(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
std::string CppConstType(const protobuf::FieldDescriptor* field) { |
||||||
|
return CppTypeInternal(field, /* is_const= */ true, |
||||||
|
/* is_type_parameter= */ false); |
||||||
|
} |
||||||
|
|
||||||
|
std::string CppTypeParameterName(const protobuf::FieldDescriptor* field) { |
||||||
|
return CppTypeInternal(field, /* is_const= */ false, |
||||||
|
/* is_type_parameter= */ true); |
||||||
|
} |
||||||
|
|
||||||
|
std::string MessageBaseType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const) { |
||||||
|
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE); |
||||||
|
std::string maybe_const = is_const ? "const " : ""; |
||||||
|
return maybe_const + QualifiedClassName(field->message_type()); |
||||||
|
} |
||||||
|
|
||||||
|
std::string MessagePtrConstType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const) { |
||||||
|
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE); |
||||||
|
std::string maybe_const = is_const ? "const " : ""; |
||||||
|
return "::protos::Ptr<" + maybe_const + |
||||||
|
QualifiedClassName(field->message_type()) + ">"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string MessageCProxyType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const) { |
||||||
|
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE); |
||||||
|
std::string maybe_const = is_const ? "const " : ""; |
||||||
|
return maybe_const + QualifiedInternalClassName(field->message_type()) + |
||||||
|
"CProxy"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string MessageProxyType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const) { |
||||||
|
DCHECK(field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE); |
||||||
|
std::string maybe_const = is_const ? "const " : ""; |
||||||
|
return maybe_const + QualifiedInternalClassName(field->message_type()) + |
||||||
|
"Proxy"; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos_generator
|
@ -0,0 +1,81 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_GENERATOR_GEN_UTILS_H_ |
||||||
|
#define UPB_PROTOS_GENERATOR_GEN_UTILS_H_ |
||||||
|
|
||||||
|
#include "google/protobuf/compiler/code_generator.h" |
||||||
|
#include "google/protobuf/compiler/plugin.h" |
||||||
|
#include "google/protobuf/descriptor.pb.h" |
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "google/protobuf/wire_format.h" |
||||||
|
#include "absl/container/flat_hash_map.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
enum class MessageClassType { |
||||||
|
kMessage, |
||||||
|
kMessageCProxy, |
||||||
|
kMessageProxy, |
||||||
|
kMessageAccess, |
||||||
|
}; |
||||||
|
|
||||||
|
std::string ClassName(const protobuf::Descriptor* descriptor); |
||||||
|
std::string QualifiedClassName(const protobuf::Descriptor* descriptor); |
||||||
|
std::string QualifiedInternalClassName(const protobuf::Descriptor* descriptor); |
||||||
|
|
||||||
|
inline bool IsMapEntryMessage(const protobuf::Descriptor* descriptor) { |
||||||
|
return descriptor->options().map_entry(); |
||||||
|
} |
||||||
|
std::string CppSourceFilename(const google::protobuf::FileDescriptor* file); |
||||||
|
std::string ForwardingHeaderFilename(const google::protobuf::FileDescriptor* file); |
||||||
|
std::string UpbCFilename(const google::protobuf::FileDescriptor* file); |
||||||
|
std::string CppHeaderFilename(const google::protobuf::FileDescriptor* file); |
||||||
|
|
||||||
|
void WriteStartNamespace(const protobuf::FileDescriptor* file, Output& output); |
||||||
|
void WriteEndNamespace(const protobuf::FileDescriptor* file, Output& output); |
||||||
|
|
||||||
|
std::string CppConstType(const protobuf::FieldDescriptor* field); |
||||||
|
std::string CppTypeParameterName(const protobuf::FieldDescriptor* field); |
||||||
|
|
||||||
|
std::string MessageBaseType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const); |
||||||
|
// Generate protos::Ptr<const Model> to be used in accessors as public
|
||||||
|
// signatures.
|
||||||
|
std::string MessagePtrConstType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const); |
||||||
|
std::string MessageCProxyType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const); |
||||||
|
std::string MessageProxyType(const protobuf::FieldDescriptor* field, |
||||||
|
bool is_const); |
||||||
|
|
||||||
|
} // namespace protos_generator
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_GENERATOR_GEN_UTILS_H_
|
@ -0,0 +1,85 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "protos_generator/output.h" |
||||||
|
|
||||||
|
#include "absl/strings/str_replace.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
namespace { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::string StripExtension(absl::string_view fname) { |
||||||
|
size_t lastdot = fname.find_last_of('.'); |
||||||
|
if (lastdot == std::string::npos) { |
||||||
|
return std::string(fname); |
||||||
|
} |
||||||
|
return std::string(fname.substr(0, lastdot)); |
||||||
|
} |
||||||
|
|
||||||
|
std::string ToCIdent(absl::string_view str) { |
||||||
|
return absl::StrReplaceAll(str, {{".", "_"}, {"/", "_"}, {"-", "_"}}); |
||||||
|
} |
||||||
|
|
||||||
|
std::string ToPreproc(absl::string_view str) { |
||||||
|
return absl::AsciiStrToUpper(ToCIdent(str)); |
||||||
|
} |
||||||
|
|
||||||
|
void EmitFileWarning(const protobuf::FileDescriptor* file, Output& output) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
/* This file was generated by protos_generator (the upb C++ compiler) "
|
||||||
|
from the input |
||||||
|
* file: |
||||||
|
* |
||||||
|
* $0 |
||||||
|
* |
||||||
|
* Do not edit -- your changes will be discarded when the file is |
||||||
|
* regenerated. */ |
||||||
|
)cc", |
||||||
|
file->name()); |
||||||
|
output("\n"); |
||||||
|
} |
||||||
|
|
||||||
|
std::string MessageName(const protobuf::Descriptor* descriptor) { |
||||||
|
return ToCIdent(descriptor->full_name()); |
||||||
|
} |
||||||
|
|
||||||
|
std::string FileLayoutName(const google::protobuf::FileDescriptor* file) { |
||||||
|
return ToCIdent(file->name()) + "_upb_file_layout"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string CHeaderFilename(const google::protobuf::FileDescriptor* file) { |
||||||
|
return StripExtension(file->name()) + ".upb.h"; |
||||||
|
} |
||||||
|
|
||||||
|
std::string CSourceFilename(const google::protobuf::FileDescriptor* file) { |
||||||
|
return StripExtension(file->name()) + ".upb.c"; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace protos_generator
|
@ -0,0 +1,172 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_GENERATOR_OUTPUT_H |
||||||
|
#define UPB_PROTOS_GENERATOR_OUTPUT_H |
||||||
|
|
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "google/protobuf/io/zero_copy_stream.h" |
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "absl/base/log_severity.h" |
||||||
|
#include "absl/log/log.h" |
||||||
|
#include "absl/strings/str_replace.h" |
||||||
|
#include "absl/strings/substitute.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
|
||||||
|
class Output { |
||||||
|
public: |
||||||
|
Output(google::protobuf::io::ZeroCopyOutputStream* stream) : stream_(stream) {} |
||||||
|
~Output() { stream_->BackUp((int)buffer_size_); } |
||||||
|
|
||||||
|
template <class... Arg> |
||||||
|
void operator()(absl::string_view format, const Arg&... arg) { |
||||||
|
Write(absl::Substitute(format, arg...)); |
||||||
|
} |
||||||
|
|
||||||
|
// Indentation size in characters.
|
||||||
|
static constexpr size_t kIndentationSize = 2; |
||||||
|
|
||||||
|
void Indent() { Indent(kIndentationSize); } |
||||||
|
void Indent(size_t size) { indent_ += size; } |
||||||
|
|
||||||
|
void Outdent() { Outdent(kIndentationSize); } |
||||||
|
void Outdent(size_t size) { |
||||||
|
if (indent_ < size) { |
||||||
|
LOG(FATAL) << "mismatched Output indent/unindent calls"; |
||||||
|
} |
||||||
|
indent_ -= size; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
void Write(absl::string_view data) { |
||||||
|
std::string stripped; |
||||||
|
if (absl::StartsWith(data, "\n ")) { |
||||||
|
size_t indent = data.substr(1).find_first_not_of(' '); |
||||||
|
if (indent > indent_) { |
||||||
|
indent -= indent_; |
||||||
|
} |
||||||
|
if (indent != absl::string_view::npos) { |
||||||
|
// Remove indentation from all lines.
|
||||||
|
auto line_prefix = data.substr(0, indent + 1); |
||||||
|
// The final line has an extra newline and is indented two less, eg.
|
||||||
|
// R"cc(
|
||||||
|
// UPB_INLINE $0 $1_$2(const $1 *msg) {
|
||||||
|
// return $1_has_$2(msg) ? *UPB_PTR_AT(msg, $3, $0) : $4;
|
||||||
|
// }
|
||||||
|
// )cc",
|
||||||
|
std::string last_line_prefix = std::string(line_prefix); |
||||||
|
last_line_prefix.resize(last_line_prefix.size() - 2); |
||||||
|
data.remove_prefix(line_prefix.size()); |
||||||
|
stripped = absl::StrReplaceAll( |
||||||
|
data, {{line_prefix, "\n"}, {last_line_prefix, "\n"}}); |
||||||
|
data = stripped; |
||||||
|
} |
||||||
|
} else { |
||||||
|
WriteIndent(); |
||||||
|
} |
||||||
|
WriteRaw(data); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteRaw(absl::string_view data) { |
||||||
|
while (!data.empty()) { |
||||||
|
RefreshOutput(); |
||||||
|
size_t to_write = std::min(data.size(), buffer_size_); |
||||||
|
memcpy(output_buffer_, data.data(), to_write); |
||||||
|
data.remove_prefix(to_write); |
||||||
|
output_buffer_ += to_write; |
||||||
|
buffer_size_ -= to_write; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteIndent() { |
||||||
|
if (indent_ == 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
size_t size = indent_; |
||||||
|
while (size > buffer_size_) { |
||||||
|
if (buffer_size_ > 0) { |
||||||
|
memset(output_buffer_, ' ', buffer_size_); |
||||||
|
} |
||||||
|
size -= buffer_size_; |
||||||
|
buffer_size_ = 0; |
||||||
|
RefreshOutput(); |
||||||
|
} |
||||||
|
memset(output_buffer_, ' ', size); |
||||||
|
output_buffer_ += size; |
||||||
|
buffer_size_ -= size; |
||||||
|
} |
||||||
|
|
||||||
|
void RefreshOutput() { |
||||||
|
while (buffer_size_ == 0) { |
||||||
|
void* void_buffer; |
||||||
|
int size; |
||||||
|
if (!stream_->Next(&void_buffer, &size)) { |
||||||
|
fprintf(stderr, "upbc: Failed to write to to output\n"); |
||||||
|
abort(); |
||||||
|
} |
||||||
|
output_buffer_ = static_cast<char*>(void_buffer); |
||||||
|
buffer_size_ = size; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
google::protobuf::io::ZeroCopyOutputStream* stream_; |
||||||
|
char* output_buffer_ = nullptr; |
||||||
|
size_t buffer_size_ = 0; |
||||||
|
// Current indentation size in characters.
|
||||||
|
size_t indent_ = 0; |
||||||
|
friend class OutputIndenter; |
||||||
|
}; |
||||||
|
|
||||||
|
class OutputIndenter { |
||||||
|
public: |
||||||
|
OutputIndenter(Output& output) |
||||||
|
: OutputIndenter(output, Output::kIndentationSize) {} |
||||||
|
OutputIndenter(Output& output, size_t indent_size) |
||||||
|
: indent_size_(indent_size), output_(output) { |
||||||
|
output.Indent(indent_size); |
||||||
|
} |
||||||
|
~OutputIndenter() { output_.Outdent(indent_size_); } |
||||||
|
|
||||||
|
private: |
||||||
|
size_t indent_size_; |
||||||
|
Output& output_; |
||||||
|
}; |
||||||
|
|
||||||
|
std::string StripExtension(absl::string_view fname); |
||||||
|
std::string ToCIdent(absl::string_view str); |
||||||
|
std::string ToPreproc(absl::string_view str); |
||||||
|
void EmitFileWarning(const google::protobuf::FileDescriptor* file, Output& output); |
||||||
|
std::string MessageName(const google::protobuf::Descriptor* descriptor); |
||||||
|
std::string FileLayoutName(const google::protobuf::FileDescriptor* file); |
||||||
|
std::string CHeaderFilename(const google::protobuf::FileDescriptor* file); |
||||||
|
std::string CSourceFilename(const google::protobuf::FileDescriptor* file); |
||||||
|
|
||||||
|
} // namespace protos_generator
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_GENERATOR_OUTPUT_H
|
@ -0,0 +1,306 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "google/protobuf/compiler/code_generator.h" |
||||||
|
#include "google/protobuf/compiler/plugin.h" |
||||||
|
#include "google/protobuf/descriptor.pb.h" |
||||||
|
#include "protos_generator/gen_enums.h" |
||||||
|
#include "protos_generator/gen_extensions.h" |
||||||
|
#include "protos_generator/gen_messages.h" |
||||||
|
#include "protos_generator/gen_utils.h" |
||||||
|
#include "protos_generator/output.h" |
||||||
|
#include "upbc/file_layout.h" |
||||||
|
|
||||||
|
namespace protos_generator { |
||||||
|
namespace { |
||||||
|
|
||||||
|
namespace protoc = ::google::protobuf::compiler; |
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
using FileDescriptor = ::google::protobuf::FileDescriptor; |
||||||
|
using FileLayout = ::upbc::FileLayout; |
||||||
|
|
||||||
|
void WriteSource(const FileLayout& layout, Output& output, |
||||||
|
bool fasttable_enabled); |
||||||
|
void WriteHeader(const FileLayout& layout, Output& output); |
||||||
|
void WriteForwardingHeader(const FileLayout& layout, Output& output); |
||||||
|
void WriteMessageImplementations(const protobuf::FileDescriptor* file, |
||||||
|
Output& output); |
||||||
|
void WriteTypedefForwardingHeader( |
||||||
|
const protobuf::FileDescriptor* file, |
||||||
|
const std::vector<const protobuf::Descriptor*>& file_messages, |
||||||
|
Output& output); |
||||||
|
void WriteHeaderMessageForwardDecls( |
||||||
|
const protobuf::FileDescriptor* file, |
||||||
|
const std::vector<const protobuf::Descriptor*>& file_messages, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output); |
||||||
|
|
||||||
|
class Generator : public protoc::CodeGenerator { |
||||||
|
public: |
||||||
|
~Generator() override {} |
||||||
|
bool Generate(const protobuf::FileDescriptor* file, |
||||||
|
const std::string& parameter, protoc::GeneratorContext* context, |
||||||
|
std::string* error) const override; |
||||||
|
uint64_t GetSupportedFeatures() const override { |
||||||
|
return FEATURE_PROTO3_OPTIONAL; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
bool Generator::Generate(const protobuf::FileDescriptor* file, |
||||||
|
const std::string& parameter, |
||||||
|
protoc::GeneratorContext* context, |
||||||
|
std::string* error) const { |
||||||
|
bool fasttable_enabled = false; |
||||||
|
std::vector<std::pair<std::string, std::string>> params; |
||||||
|
google::protobuf::compiler::ParseGeneratorParameter(parameter, ¶ms); |
||||||
|
|
||||||
|
for (const auto& pair : params) { |
||||||
|
if (pair.first == "fasttable") { |
||||||
|
fasttable_enabled = true; |
||||||
|
} else { |
||||||
|
*error = "Unknown parameter: " + pair.first; |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
FileLayout layout(file); |
||||||
|
|
||||||
|
// Write model.upb.fwd.h
|
||||||
|
Output forwarding_header_output( |
||||||
|
context->Open(ForwardingHeaderFilename(file))); |
||||||
|
WriteForwardingHeader(layout, forwarding_header_output); |
||||||
|
// Write model.upb.proto.h
|
||||||
|
Output header_output(context->Open(CppHeaderFilename(file))); |
||||||
|
WriteHeader(layout, header_output); |
||||||
|
// Write model.upb.proto.cc
|
||||||
|
Output cc_output(context->Open(CppSourceFilename(file))); |
||||||
|
WriteSource(layout, cc_output, fasttable_enabled); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// The forwarding header defines Access/Proxy/CProxy for message classes
|
||||||
|
// used to include when referencing dependencies to prevent transitive
|
||||||
|
// dependency headers from being included.
|
||||||
|
void WriteForwardingHeader(const FileLayout& layout, Output& output) { |
||||||
|
const protobuf::FileDescriptor* file = layout.descriptor(); |
||||||
|
EmitFileWarning(file, output); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
#ifndef $0_UPB_FWD_H_ |
||||||
|
#define $0_UPB_FWD_H_ |
||||||
|
)cc", |
||||||
|
ToPreproc(file->name())); |
||||||
|
output("\n"); |
||||||
|
const std::vector<const protobuf::Descriptor*> this_file_messages = |
||||||
|
::upbc::SortedMessages(file); |
||||||
|
WriteTypedefForwardingHeader(file, this_file_messages, output); |
||||||
|
output("#endif /* $0_UPB_FWD_H_ */\n", ToPreproc(file->name())); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteHeader(const FileLayout& layout, Output& output) { |
||||||
|
const protobuf::FileDescriptor* file = layout.descriptor(); |
||||||
|
EmitFileWarning(file, output); |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
#ifndef $0_UPB_PROTO_H_ |
||||||
|
#define $0_UPB_PROTO_H_ |
||||||
|
|
||||||
|
#include "protos/protos.h" |
||||||
|
#include "protos/protos_internal.h" |
||||||
|
#include "upb/upb.hpp" |
||||||
|
|
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
#include "absl/status/statusor.h" |
||||||
|
#include "upb/msg_internal.h" |
||||||
|
)cc", |
||||||
|
ToPreproc(file->name())); |
||||||
|
|
||||||
|
// Import headers for proto public dependencies.
|
||||||
|
for (int i = 0; i < file->public_dependency_count(); i++) { |
||||||
|
if (i == 0) { |
||||||
|
output("// Public Imports.\n"); |
||||||
|
} |
||||||
|
output("#include \"$0\"\n", CppHeaderFilename(file->public_dependency(i))); |
||||||
|
if (i == file->public_dependency_count() - 1) { |
||||||
|
output("\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
output("#include \"upb/port_def.inc\"\n"); |
||||||
|
|
||||||
|
const std::vector<const protobuf::Descriptor*> this_file_messages = |
||||||
|
::upbc::SortedMessages(file); |
||||||
|
const std::vector<const protobuf::FieldDescriptor*> this_file_exts = |
||||||
|
::upbc::SortedExtensions(file); |
||||||
|
|
||||||
|
if (!this_file_messages.empty()) { |
||||||
|
output("\n"); |
||||||
|
} |
||||||
|
|
||||||
|
WriteHeaderMessageForwardDecls(file, this_file_messages, this_file_exts, |
||||||
|
output); |
||||||
|
WriteStartNamespace(file, output); |
||||||
|
|
||||||
|
std::vector<const protobuf::EnumDescriptor*> this_file_enums = |
||||||
|
::upbc::SortedEnums(file); |
||||||
|
|
||||||
|
// Write Class and Enums.
|
||||||
|
WriteEnumDeclarations(this_file_enums, output); |
||||||
|
output("\n"); |
||||||
|
|
||||||
|
for (auto message : this_file_messages) { |
||||||
|
WriteMessageClassDeclarations(message, this_file_exts, output); |
||||||
|
} |
||||||
|
output("\n"); |
||||||
|
|
||||||
|
WriteExtensionIdentifiersHeader(this_file_exts, output); |
||||||
|
output("\n"); |
||||||
|
|
||||||
|
WriteEndNamespace(file, output); |
||||||
|
|
||||||
|
output("\n#include \"upb/port_undef.inc\"\n\n"); |
||||||
|
// End of "C" section.
|
||||||
|
|
||||||
|
output("#endif /* $0_UPB_PROTO_H_ */\n", ToPreproc(file->name())); |
||||||
|
} |
||||||
|
|
||||||
|
// Writes a .upb.cc source file.
|
||||||
|
void WriteSource(const FileLayout& layout, Output& output, |
||||||
|
bool fasttable_enabled) { |
||||||
|
const protobuf::FileDescriptor* file = layout.descriptor(); |
||||||
|
EmitFileWarning(file, output); |
||||||
|
|
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
#include <stddef.h> |
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
#include "upb/msg_internal.h" |
||||||
|
#include "protos/protos.h" |
||||||
|
#include "$0" |
||||||
|
)cc", |
||||||
|
CppHeaderFilename(file)); |
||||||
|
|
||||||
|
for (int i = 0; i < file->dependency_count(); i++) { |
||||||
|
output("#include \"$0\"\n", CppHeaderFilename(file->dependency(i))); |
||||||
|
} |
||||||
|
output("#include \"upb/port_def.inc\"\n"); |
||||||
|
|
||||||
|
WriteStartNamespace(file, output); |
||||||
|
WriteMessageImplementations(file, output); |
||||||
|
const std::vector<const protobuf::FieldDescriptor*> this_file_exts = |
||||||
|
::upbc::SortedExtensions(file); |
||||||
|
WriteExtensionIdentifiers(this_file_exts, output); |
||||||
|
WriteEndNamespace(file, output); |
||||||
|
|
||||||
|
output("#include \"upb/port_undef.inc\"\n\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteMessageImplementations(const protobuf::FileDescriptor* file, |
||||||
|
Output& output) { |
||||||
|
const std::vector<const protobuf::FieldDescriptor*> file_exts = |
||||||
|
::upbc::SortedExtensions(file); |
||||||
|
const std::vector<const protobuf::Descriptor*> this_file_messages = |
||||||
|
::upbc::SortedMessages(file); |
||||||
|
for (auto message : this_file_messages) { |
||||||
|
WriteMessageImplementation(message, file_exts, output); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void WriteTypedefForwardingHeader( |
||||||
|
const protobuf::FileDescriptor* file, |
||||||
|
const std::vector<const protobuf::Descriptor*>& file_messages, |
||||||
|
Output& output) { |
||||||
|
WriteStartNamespace(file, output); |
||||||
|
|
||||||
|
// Forward-declare types defined in this file.
|
||||||
|
for (auto message : file_messages) { |
||||||
|
output( |
||||||
|
R"cc( |
||||||
|
class $0; |
||||||
|
namespace internal { |
||||||
|
class $0Access; |
||||||
|
class $0Proxy; |
||||||
|
class $0CProxy; |
||||||
|
} // namespace internal
|
||||||
|
)cc", |
||||||
|
ClassName(message)); |
||||||
|
} |
||||||
|
output("\n"); |
||||||
|
WriteEndNamespace(file, output); |
||||||
|
} |
||||||
|
|
||||||
|
/// Writes includes for upb C minitables and fwd.h for transitive typedefs.
|
||||||
|
void WriteHeaderMessageForwardDecls( |
||||||
|
const protobuf::FileDescriptor* file, |
||||||
|
const std::vector<const protobuf::Descriptor*>& file_messages, |
||||||
|
const std::vector<const protobuf::FieldDescriptor*>& file_exts, |
||||||
|
Output& output) { |
||||||
|
// Import forward-declaration of types defined in this file.
|
||||||
|
output("#include \"$0\"\n", UpbCFilename(file)); |
||||||
|
output("#include \"$0\"\n", ForwardingHeaderFilename(file)); |
||||||
|
// Forward-declare types not in this file, but used as submessages.
|
||||||
|
// Order by full name for consistent ordering.
|
||||||
|
std::map<std::string, const protobuf::Descriptor*> forward_messages; |
||||||
|
|
||||||
|
for (auto* message : file_messages) { |
||||||
|
for (int i = 0; i < message->field_count(); i++) { |
||||||
|
const protobuf::FieldDescriptor* field = message->field(i); |
||||||
|
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE && |
||||||
|
field->file() != field->message_type()->file()) { |
||||||
|
forward_messages[field->message_type()->full_name()] = |
||||||
|
field->message_type(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
for (auto* ext : file_exts) { |
||||||
|
if (ext->file() != ext->containing_type()->file()) { |
||||||
|
forward_messages[ext->containing_type()->full_name()] = |
||||||
|
ext->containing_type(); |
||||||
|
if (ext->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||||
|
forward_messages[ext->message_type()->full_name()] = |
||||||
|
ext->message_type(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
std::map<std::string, const protobuf::FileDescriptor*> files_to_import; |
||||||
|
for (const auto& pair : forward_messages) { |
||||||
|
files_to_import[ForwardingHeaderFilename(pair.second->file())] = file; |
||||||
|
} |
||||||
|
for (const auto& pair : files_to_import) { |
||||||
|
output("#include \"$0\"\n", UpbCFilename(pair.second)); |
||||||
|
output("#include \"$0\"\n", pair.first); |
||||||
|
} |
||||||
|
output("\n"); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace protos_generator
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
protos_generator::Generator generator_cc; |
||||||
|
return google::protobuf::compiler::PluginMain(argc, argv, &generator_cc); |
||||||
|
} |
@ -0,0 +1,118 @@ |
|||||||
|
# Copyright (c) 2009-2021, Google LLC |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are met: |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer in the |
||||||
|
# documentation and/or other materials provided with the distribution. |
||||||
|
# * Neither the name of Google LLC nor the |
||||||
|
# names of its contributors may be used to endorse or promote products |
||||||
|
# derived from this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY |
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
load( |
||||||
|
"//bazel:build_defs.bzl", |
||||||
|
"UPB_DEFAULT_CPPOPTS", |
||||||
|
) |
||||||
|
load( |
||||||
|
"//protos/bazel:upb_cc_proto_library.bzl", |
||||||
|
"upb_cc_proto_library", |
||||||
|
) |
||||||
|
load( |
||||||
|
"//bazel:upb_proto_library.bzl", |
||||||
|
"upb_proto_library", |
||||||
|
) |
||||||
|
load( |
||||||
|
"@rules_cc//cc:defs.bzl", |
||||||
|
"cc_proto_library", |
||||||
|
) |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
proto_library( |
||||||
|
name = "test_model_proto", |
||||||
|
srcs = [ |
||||||
|
"child_model.proto", |
||||||
|
"test_enum.proto", |
||||||
|
"test_extension.proto", |
||||||
|
"test_model.proto", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
proto_library( |
||||||
|
name = "no_package_proto", |
||||||
|
srcs = [ |
||||||
|
"no_package.proto", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
upb_proto_library( |
||||||
|
name = "test_model_upb_proto", |
||||||
|
visibility = [ |
||||||
|
"//protos:__pkg__", |
||||||
|
], |
||||||
|
deps = [":test_model_proto"], |
||||||
|
) |
||||||
|
|
||||||
|
upb_cc_proto_library( |
||||||
|
name = "test_model_upb_cc_proto", |
||||||
|
visibility = [ |
||||||
|
"//protos:__pkg__", |
||||||
|
"//protos_generator/nc_tests:__pkg__", |
||||||
|
], |
||||||
|
deps = [":test_model_proto"], |
||||||
|
) |
||||||
|
|
||||||
|
upb_cc_proto_library( |
||||||
|
name = "no_package_upb_cc_proto", |
||||||
|
deps = [":no_package_proto"], |
||||||
|
) |
||||||
|
|
||||||
|
cc_proto_library( |
||||||
|
name = "test_model_cc_proto", |
||||||
|
deps = [":test_model_proto"], |
||||||
|
) |
||||||
|
|
||||||
|
# begin:google_only |
||||||
|
# proto_library( |
||||||
|
# name = "legacy_name_proto", |
||||||
|
# srcs = [ |
||||||
|
# "legacy-name.proto", |
||||||
|
# ], |
||||||
|
# ) |
||||||
|
# |
||||||
|
# upb_cc_proto_library( |
||||||
|
# name = "legacy_name_test_proto", |
||||||
|
# visibility = ["//protos_generator/nc_tests:__pkg__"], |
||||||
|
# deps = [":legacy_name_proto"], |
||||||
|
# ) |
||||||
|
# end:google_only |
||||||
|
|
||||||
|
cc_test( |
||||||
|
name = "test_generated_cc_code", |
||||||
|
srcs = ["test_generated.cc"], |
||||||
|
copts = UPB_DEFAULT_CPPOPTS, |
||||||
|
deps = [ |
||||||
|
# begin:google_only |
||||||
|
# ":legacy_name_test_proto", |
||||||
|
# end:google_only |
||||||
|
":no_package_upb_cc_proto", |
||||||
|
":test_model_upb_cc_proto", |
||||||
|
":test_model_upb_proto", |
||||||
|
"@com_google_googletest//:gtest_main", |
||||||
|
"//:upb", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,19 @@ |
|||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package protos_generator.test; |
||||||
|
|
||||||
|
import public "protos_generator/tests/test_enum.proto"; |
||||||
|
|
||||||
|
message ChildModel1 { |
||||||
|
optional bool child_b1 = 44; |
||||||
|
optional string child_str1 = 56; |
||||||
|
} |
||||||
|
|
||||||
|
message ChildModel3 { |
||||||
|
string sub_key = 1; |
||||||
|
bool bool1 = 2; |
||||||
|
int32 i32 = 3; |
||||||
|
optional string opt_str = 4; |
||||||
|
optional bool opt_bool = 5; |
||||||
|
optional int32 opt_i32 = 6; |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package protos_generator.test; |
||||||
|
|
||||||
|
// option java_multiple_files = true; |
||||||
|
|
||||||
|
enum LegacyEnum { |
||||||
|
PHASE_DEFAULT = 0; |
||||||
|
PHASE_BUSY = 1; |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
syntax = "proto2"; |
||||||
|
|
||||||
|
// option java_multiple_files = true; |
||||||
|
|
||||||
|
enum EnumWithNoPackage { |
||||||
|
CELSIUS = 1; |
||||||
|
FAHRENHEIT = 2; |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package protos_generator.test; |
||||||
|
|
||||||
|
enum TestEnum { |
||||||
|
DEVICE_UNKNOWN = 0; |
||||||
|
DEVICE_KEYBOARD = 1; |
||||||
|
DEVICE_MOUSE = 2; |
||||||
|
DEVICE_MONITOR = 3; |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
syntax = "proto2"; |
||||||
|
|
||||||
|
package protos_generator.test.someotherpackage; |
||||||
|
|
||||||
|
import "protos_generator/tests/test_model.proto"; |
||||||
|
|
||||||
|
// Define extension that is extending proto outside this package with a type |
||||||
|
// defined in different file. |
||||||
|
|
||||||
|
extend TestModel { |
||||||
|
optional ThemeExtension styling = 13001; |
||||||
|
} |
@ -0,0 +1,582 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include <limits> |
||||||
|
|
||||||
|
#include "gtest/gtest.h" |
||||||
|
#include "protos_generator/tests/child_model.upb.proto.h" |
||||||
|
#include "protos_generator/tests/no_package.upb.proto.h" |
||||||
|
#include "protos_generator/tests/test_model.upb.proto.h" |
||||||
|
#include "upb/string_view.h" |
||||||
|
|
||||||
|
using ::protos_generator::test::protos::ChildModel1; |
||||||
|
using ::protos_generator::test::protos::other_ext; |
||||||
|
using ::protos_generator::test::protos::RED; |
||||||
|
using ::protos_generator::test::protos::TestEnum; |
||||||
|
using ::protos_generator::test::protos::TestModel; |
||||||
|
using ::protos_generator::test::protos::TestModel_Category_IMAGES; |
||||||
|
using ::protos_generator::test::protos::TestModel_Category_NEWS; |
||||||
|
using ::protos_generator::test::protos::TestModel_Category_VIDEO; |
||||||
|
using ::protos_generator::test::protos::theme; |
||||||
|
using ::protos_generator::test::protos::ThemeExtension; |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, Constructor) { TestModel test_model; } |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, MessageEnum) { EXPECT_EQ(5, TestModel_Category_IMAGES); } |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ImportedEnum) { EXPECT_EQ(3, TestEnum::DEVICE_MONITOR); } |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, Enum) { EXPECT_EQ(1, RED); } |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, EnumNoPackage) { EXPECT_EQ(1, ::protos_CELSIUS); } |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ArenaConstructor) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(false, testModel.has_b1()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, Booleans) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_FALSE(testModel.b1()); |
||||||
|
testModel.set_b1(true); |
||||||
|
EXPECT_TRUE(testModel.b1()); |
||||||
|
testModel.set_b1(false); |
||||||
|
EXPECT_FALSE(testModel.b1()); |
||||||
|
testModel.set_b1(true); |
||||||
|
EXPECT_TRUE(testModel.b1()); |
||||||
|
testModel.clear_b1(); |
||||||
|
EXPECT_FALSE(testModel.has_b1()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ScalarInt32) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
// Test int32 defaults.
|
||||||
|
EXPECT_EQ(testModel.value(), 0); |
||||||
|
EXPECT_FALSE(testModel.has_value()); |
||||||
|
// Floating point defautls.
|
||||||
|
EXPECT_EQ(std::numeric_limits<float>::infinity(), |
||||||
|
testModel.float_value_with_default()); |
||||||
|
EXPECT_EQ(-std::numeric_limits<double>::infinity(), |
||||||
|
testModel.double_value_with_default()); |
||||||
|
|
||||||
|
// Set value.
|
||||||
|
testModel.set_value(5); |
||||||
|
EXPECT_TRUE(testModel.has_value()); |
||||||
|
EXPECT_EQ(testModel.value(), 5); |
||||||
|
// Change value.
|
||||||
|
testModel.set_value(10); |
||||||
|
EXPECT_TRUE(testModel.has_value()); |
||||||
|
EXPECT_EQ(testModel.value(), 10); |
||||||
|
// Clear value.
|
||||||
|
testModel.clear_value(); |
||||||
|
EXPECT_FALSE(testModel.has_value()); |
||||||
|
EXPECT_EQ(testModel.value(), 0); |
||||||
|
} |
||||||
|
|
||||||
|
const char kTestStr1[] = "abcdefg"; |
||||||
|
const char kTestStr2[] = "just another test string"; |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, Strings) { |
||||||
|
TestModel testModel; |
||||||
|
testModel.set_str1(kTestStr1); |
||||||
|
testModel.set_str2(kTestStr2); |
||||||
|
EXPECT_EQ(testModel.str1(), kTestStr1); |
||||||
|
EXPECT_EQ(testModel.str2(), kTestStr2); |
||||||
|
EXPECT_TRUE(testModel.has_str1()); |
||||||
|
EXPECT_TRUE(testModel.has_str2()); |
||||||
|
|
||||||
|
testModel.clear_str1(); |
||||||
|
EXPECT_FALSE(testModel.has_str1()); |
||||||
|
EXPECT_TRUE(testModel.has_str2()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ScalarUInt32) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
// Test defaults.
|
||||||
|
EXPECT_EQ(testModel.optional_uint32(), 0); |
||||||
|
EXPECT_FALSE(testModel.has_optional_uint32()); |
||||||
|
// Set value.
|
||||||
|
testModel.set_optional_uint32(0xA0001000); |
||||||
|
EXPECT_TRUE(testModel.has_optional_uint32()); |
||||||
|
EXPECT_EQ(testModel.optional_uint32(), 0xA0001000); |
||||||
|
// Change value.
|
||||||
|
testModel.set_optional_uint32(0x70002000); |
||||||
|
EXPECT_TRUE(testModel.has_optional_uint32()); |
||||||
|
EXPECT_EQ(testModel.optional_uint32(), 0x70002000); |
||||||
|
// Clear value.
|
||||||
|
testModel.clear_optional_uint32(); |
||||||
|
EXPECT_FALSE(testModel.has_optional_uint32()); |
||||||
|
EXPECT_EQ(testModel.optional_uint32(), 0); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ScalarInt64) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
// Test defaults.
|
||||||
|
EXPECT_EQ(testModel.optional_int64(), 0); |
||||||
|
EXPECT_FALSE(testModel.has_optional_int64()); |
||||||
|
// Set value.
|
||||||
|
testModel.set_optional_int64(0xFF00CCDDA0001000); |
||||||
|
EXPECT_TRUE(testModel.has_optional_int64()); |
||||||
|
EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000); |
||||||
|
// Change value.
|
||||||
|
testModel.set_optional_int64(0xFF00CCDD70002000); |
||||||
|
EXPECT_TRUE(testModel.has_optional_int64()); |
||||||
|
EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDD70002000); |
||||||
|
// Clear value.
|
||||||
|
testModel.clear_optional_int64(); |
||||||
|
EXPECT_FALSE(testModel.has_optional_int64()); |
||||||
|
EXPECT_EQ(testModel.optional_int64(), 0); |
||||||
|
// Set after clear.
|
||||||
|
testModel.set_optional_int64(0xFF00CCDDA0001000); |
||||||
|
EXPECT_TRUE(testModel.has_optional_int64()); |
||||||
|
EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ScalarFloat) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
// Test defaults.
|
||||||
|
EXPECT_EQ(testModel.optional_float(), 0.0f); |
||||||
|
EXPECT_FALSE(testModel.has_optional_float()); |
||||||
|
EXPECT_EQ(std::numeric_limits<float>::infinity(), |
||||||
|
testModel.float_value_with_default()); |
||||||
|
EXPECT_EQ(-std::numeric_limits<double>::infinity(), |
||||||
|
testModel.double_value_with_default()); |
||||||
|
// Set value.
|
||||||
|
testModel.set_optional_float(3.14159265f); |
||||||
|
EXPECT_TRUE(testModel.has_optional_float()); |
||||||
|
EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f); |
||||||
|
// Change value.
|
||||||
|
testModel.set_optional_float(-2.0f); |
||||||
|
EXPECT_TRUE(testModel.has_optional_float()); |
||||||
|
EXPECT_NEAR(testModel.optional_float(), -2, 1e-9f); |
||||||
|
// Clear value.
|
||||||
|
testModel.clear_optional_float(); |
||||||
|
EXPECT_FALSE(testModel.has_optional_float()); |
||||||
|
EXPECT_EQ(testModel.optional_float(), 0.0f); |
||||||
|
// Set after clear.
|
||||||
|
testModel.set_optional_float(3.14159265f); |
||||||
|
EXPECT_TRUE(testModel.has_optional_float()); |
||||||
|
EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ScalarDouble) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
// Test defaults.
|
||||||
|
EXPECT_EQ(testModel.optional_double(), 0.0); |
||||||
|
EXPECT_FALSE(testModel.has_optional_double()); |
||||||
|
// Set value.
|
||||||
|
testModel.set_optional_double(3.141592653589793); |
||||||
|
EXPECT_TRUE(testModel.has_optional_double()); |
||||||
|
EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f); |
||||||
|
// Change value.
|
||||||
|
testModel.set_optional_double(-1.0); |
||||||
|
EXPECT_TRUE(testModel.has_optional_double()); |
||||||
|
EXPECT_NEAR(testModel.optional_double(), -1.0, 1e-16f); |
||||||
|
// Clear value.
|
||||||
|
testModel.clear_optional_double(); |
||||||
|
EXPECT_FALSE(testModel.has_optional_double()); |
||||||
|
EXPECT_EQ(testModel.optional_double(), 0.0f); |
||||||
|
// Set after clear.
|
||||||
|
testModel.set_optional_double(3.141592653589793); |
||||||
|
EXPECT_TRUE(testModel.has_optional_double()); |
||||||
|
EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, Enums) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
|
||||||
|
// Check enum default value.
|
||||||
|
EXPECT_EQ(TestModel_Category_IMAGES, 5); |
||||||
|
|
||||||
|
// Test defaults.
|
||||||
|
EXPECT_FALSE(testModel.has_category()); |
||||||
|
EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES); |
||||||
|
// Set value.
|
||||||
|
testModel.set_category(TestModel_Category_NEWS); |
||||||
|
EXPECT_TRUE(testModel.has_category()); |
||||||
|
EXPECT_EQ(testModel.category(), TestModel_Category_NEWS); |
||||||
|
// Change value.
|
||||||
|
testModel.set_category(TestModel_Category_VIDEO); |
||||||
|
EXPECT_TRUE(testModel.has_category()); |
||||||
|
EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO); |
||||||
|
// Clear value.
|
||||||
|
testModel.clear_category(); |
||||||
|
EXPECT_FALSE(testModel.has_category()); |
||||||
|
EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES); |
||||||
|
// Set after clear.
|
||||||
|
testModel.set_category(TestModel_Category_VIDEO); |
||||||
|
EXPECT_TRUE(testModel.has_category()); |
||||||
|
EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, FieldWithDefaultValue) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto testModel = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
|
||||||
|
EXPECT_FALSE(testModel.has_int_value_with_default()); |
||||||
|
EXPECT_EQ(testModel.int_value_with_default(), 65); |
||||||
|
testModel.set_int_value_with_default(10); |
||||||
|
EXPECT_EQ(testModel.int_value_with_default(), 10); |
||||||
|
|
||||||
|
EXPECT_FALSE(testModel.has_string_value_with_default()); |
||||||
|
EXPECT_EQ(testModel.string_value_with_default(), "hello"); |
||||||
|
testModel.set_string_value_with_default("new string"); |
||||||
|
EXPECT_EQ(testModel.string_value_with_default(), "new string"); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, OneOfFields) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
|
||||||
|
EXPECT_FALSE(test_model.has_oneof_member1()); |
||||||
|
EXPECT_FALSE(test_model.has_oneof_member2()); |
||||||
|
|
||||||
|
test_model.set_oneof_member1("one of string"); |
||||||
|
EXPECT_TRUE(test_model.has_oneof_member1()); |
||||||
|
EXPECT_FALSE(test_model.has_oneof_member2()); |
||||||
|
EXPECT_EQ(test_model.oneof_member1(), "one of string"); |
||||||
|
|
||||||
|
test_model.set_oneof_member2(true); |
||||||
|
EXPECT_FALSE(test_model.has_oneof_member1()); |
||||||
|
EXPECT_TRUE(test_model.has_oneof_member2()); |
||||||
|
EXPECT_EQ(test_model.oneof_member2(), true); |
||||||
|
|
||||||
|
test_model.clear_oneof_member2(); |
||||||
|
EXPECT_FALSE(test_model.has_oneof_member1()); |
||||||
|
EXPECT_FALSE(test_model.has_oneof_member2()); |
||||||
|
EXPECT_EQ(test_model.oneof_member1(), ""); |
||||||
|
EXPECT_EQ(test_model.oneof_member2(), false); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, Messages) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(false, test_model.has_child_model_1()); |
||||||
|
auto child_model = test_model.child_model_1(); |
||||||
|
EXPECT_EQ(false, child_model->has_child_b1()); |
||||||
|
EXPECT_EQ(false, child_model->child_b1()); |
||||||
|
auto mutable_child = test_model.mutable_child_model_1(); |
||||||
|
mutable_child->set_child_b1(true); |
||||||
|
EXPECT_EQ(true, mutable_child->has_child_b1()); |
||||||
|
EXPECT_EQ(true, mutable_child->child_b1()); |
||||||
|
// The View should not change due to mutation since it
|
||||||
|
// is default_instance.
|
||||||
|
EXPECT_EQ(false, child_model->has_child_b1()); |
||||||
|
// Readonly View should now show change.
|
||||||
|
child_model = test_model.child_model_1(); |
||||||
|
EXPECT_EQ(true, child_model->has_child_b1()); |
||||||
|
EXPECT_EQ(true, child_model->child_b1()); |
||||||
|
// Clear message field.
|
||||||
|
EXPECT_EQ(true, test_model.has_child_model_1()); |
||||||
|
test_model.clear_child_model_1(); |
||||||
|
EXPECT_EQ(false, test_model.has_child_model_1()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, NestedMessages) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
auto nested_child = test_model.nested_child_1(); |
||||||
|
EXPECT_EQ(0, nested_child->nested_child_name().size()); |
||||||
|
auto mutable_nested_child = test_model.mutable_nested_child_1(); |
||||||
|
EXPECT_EQ(false, mutable_nested_child->has_nested_child_name()); |
||||||
|
mutable_nested_child->set_nested_child_name(kTestStr1); |
||||||
|
EXPECT_EQ(true, mutable_nested_child->has_nested_child_name()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, RepeatedMessages) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(0, test_model.child_model_2_size()); |
||||||
|
// Should be able to clear repeated field when empty.
|
||||||
|
test_model.clear_child_model_2(); |
||||||
|
EXPECT_EQ(0, test_model.child_model_2_size()); |
||||||
|
// Add 2 children.
|
||||||
|
auto new_child = test_model.add_child_model_2(); |
||||||
|
EXPECT_EQ(true, new_child.ok()); |
||||||
|
new_child.value()->set_child_str1(kTestStr1); |
||||||
|
new_child = test_model.add_child_model_2(); |
||||||
|
EXPECT_EQ(true, new_child.ok()); |
||||||
|
new_child.value()->set_child_str1(kTestStr2); |
||||||
|
EXPECT_EQ(2, test_model.child_model_2_size()); |
||||||
|
// Mutable access.
|
||||||
|
auto mutable_first = test_model.mutable_child_model_2(0); |
||||||
|
EXPECT_EQ(mutable_first->child_str1(), kTestStr1); |
||||||
|
mutable_first->set_child_str1("change1"); |
||||||
|
auto mutable_second = test_model.mutable_child_model_2(1); |
||||||
|
EXPECT_EQ(mutable_second->child_str1(), kTestStr2); |
||||||
|
mutable_second->set_child_str1("change2"); |
||||||
|
// Check mutations using views.
|
||||||
|
auto view_first = test_model.child_model_2(0); |
||||||
|
EXPECT_EQ(view_first->child_str1(), "change1"); |
||||||
|
auto view_second = test_model.child_model_2(1); |
||||||
|
EXPECT_EQ(view_second->child_str1(), "change2"); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, RepeatedScalar) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(0, test_model.value_array_size()); |
||||||
|
// Should be able to clear repeated field when empty.
|
||||||
|
test_model.clear_value_array(); |
||||||
|
EXPECT_EQ(0, test_model.value_array_size()); |
||||||
|
// Add 2 children.
|
||||||
|
EXPECT_EQ(true, test_model.add_value_array(5)); |
||||||
|
EXPECT_EQ(true, test_model.add_value_array(6)); |
||||||
|
EXPECT_EQ(2, test_model.value_array_size()); |
||||||
|
EXPECT_EQ(5, test_model.value_array(0)); |
||||||
|
EXPECT_EQ(6, test_model.value_array(1)); |
||||||
|
EXPECT_EQ(true, test_model.resize_value_array(3)); |
||||||
|
EXPECT_EQ(3, test_model.value_array_size()); |
||||||
|
test_model.set_value_array(2, 7); |
||||||
|
EXPECT_EQ(5, test_model.value_array(0)); |
||||||
|
EXPECT_EQ(6, test_model.value_array(1)); |
||||||
|
EXPECT_EQ(7, test_model.value_array(2)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, RepeatedStrings) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(0, test_model.repeated_string_size()); |
||||||
|
// Should be able to clear repeated field when empty.
|
||||||
|
test_model.clear_repeated_string(); |
||||||
|
EXPECT_EQ(0, test_model.repeated_string_size()); |
||||||
|
// Add 2 children.
|
||||||
|
EXPECT_EQ(true, test_model.add_repeated_string("Hello")); |
||||||
|
EXPECT_EQ(true, test_model.add_repeated_string("World")); |
||||||
|
EXPECT_EQ(2, test_model.repeated_string_size()); |
||||||
|
EXPECT_EQ("Hello", test_model.repeated_string(0)); |
||||||
|
EXPECT_EQ("World", test_model.repeated_string(1)); |
||||||
|
EXPECT_EQ(true, test_model.resize_repeated_string(3)); |
||||||
|
EXPECT_EQ(3, test_model.repeated_string_size()); |
||||||
|
test_model.set_repeated_string(2, "Test"); |
||||||
|
EXPECT_EQ("Hello", test_model.repeated_string(0)); |
||||||
|
EXPECT_EQ("World", test_model.repeated_string(1)); |
||||||
|
EXPECT_EQ("Test", test_model.repeated_string(2)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, MessageMapInt32KeyMessageValue) { |
||||||
|
const int key_test_value = 3; |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(0, test_model.child_map_size()); |
||||||
|
test_model.clear_child_map(); |
||||||
|
EXPECT_EQ(0, test_model.child_map_size()); |
||||||
|
auto child_model1 = ::protos::CreateMessage<ChildModel1>(arena); |
||||||
|
child_model1.set_child_str1("abc"); |
||||||
|
test_model.set_child_map(key_test_value, child_model1); |
||||||
|
auto map_result = test_model.get_child_map(key_test_value); |
||||||
|
EXPECT_EQ(true, map_result.ok()); |
||||||
|
EXPECT_EQ("abc", map_result.value()->child_str1()); |
||||||
|
test_model.delete_child_map(key_test_value); |
||||||
|
auto map_result_after_delete = test_model.get_child_map(key_test_value); |
||||||
|
EXPECT_EQ(false, map_result_after_delete.ok()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, MessageMapStringKeyAndStringValue) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(0, test_model.str_to_str_map_size()); |
||||||
|
test_model.clear_str_to_str_map(); |
||||||
|
EXPECT_EQ(0, test_model.str_to_str_map_size()); |
||||||
|
test_model.set_str_to_str_map("first", "abc"); |
||||||
|
test_model.set_str_to_str_map("second", "def"); |
||||||
|
auto result = test_model.get_str_to_str_map("second"); |
||||||
|
EXPECT_EQ(true, result.ok()); |
||||||
|
EXPECT_EQ("def", result.value()); |
||||||
|
test_model.delete_str_to_str_map("first"); |
||||||
|
auto result_after_delete = test_model.get_str_to_str_map("first"); |
||||||
|
EXPECT_EQ(false, result_after_delete.ok()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, MessageMapStringKeyAndInt32Value) { |
||||||
|
::protos::Arena arena; |
||||||
|
auto test_model = ::protos::CreateMessage<TestModel>(arena); |
||||||
|
EXPECT_EQ(0, test_model.str_to_int_map_size()); |
||||||
|
test_model.clear_str_to_int_map(); |
||||||
|
EXPECT_EQ(0, test_model.str_to_int_map_size()); |
||||||
|
test_model.set_str_to_int_map("first", 10); |
||||||
|
test_model.set_str_to_int_map("second", 20); |
||||||
|
auto result = test_model.get_str_to_int_map("second"); |
||||||
|
EXPECT_EQ(true, result.ok()); |
||||||
|
EXPECT_EQ(20, result.value()); |
||||||
|
test_model.delete_str_to_int_map("first"); |
||||||
|
auto result_after_delete = test_model.get_str_to_int_map("first"); |
||||||
|
EXPECT_EQ(false, result_after_delete.ok()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, HasExtension) { |
||||||
|
TestModel model; |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(model, theme)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, HasExtensionPtr) { |
||||||
|
TestModel model; |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(model.recursive_child(), theme)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ClearExtensionWithEmptyExtension) { |
||||||
|
TestModel model; |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(model, theme)); |
||||||
|
::protos::ClearExtension(model, theme); |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(model, theme)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ClearExtensionWithEmptyExtensionPtr) { |
||||||
|
TestModel model; |
||||||
|
::protos::Ptr<TestModel> recursive_child = model.mutable_recursive_child(); |
||||||
|
::protos::ClearExtension(recursive_child, theme); |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(recursive_child, theme)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, SetExtension) { |
||||||
|
TestModel model; |
||||||
|
ThemeExtension extension1; |
||||||
|
extension1.set_ext_name("Hello World"); |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(model, theme)); |
||||||
|
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok()); |
||||||
|
EXPECT_EQ(true, ::protos::HasExtension(model, theme)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, SetExtensionOnMutableChild) { |
||||||
|
TestModel model; |
||||||
|
ThemeExtension extension1; |
||||||
|
extension1.set_ext_name("Hello World"); |
||||||
|
EXPECT_EQ(false, |
||||||
|
::protos::HasExtension(model.mutable_recursive_child(), theme)); |
||||||
|
EXPECT_EQ(true, ::protos::SetExtension(model.mutable_recursive_child(), theme, |
||||||
|
extension1) |
||||||
|
.ok()); |
||||||
|
EXPECT_EQ(true, |
||||||
|
::protos::HasExtension(model.mutable_recursive_child(), theme)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, GetExtension) { |
||||||
|
TestModel model; |
||||||
|
ThemeExtension extension1; |
||||||
|
extension1.set_ext_name("Hello World"); |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(model, theme)); |
||||||
|
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok()); |
||||||
|
EXPECT_EQ("Hello World", |
||||||
|
::protos::GetExtension(model, theme).value()->ext_name()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, GetExtensionOnMutableChild) { |
||||||
|
TestModel model; |
||||||
|
ThemeExtension extension1; |
||||||
|
extension1.set_ext_name("Hello World"); |
||||||
|
::protos::Ptr<TestModel> mutable_recursive_child = |
||||||
|
model.mutable_recursive_child(); |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(mutable_recursive_child, theme)); |
||||||
|
EXPECT_EQ( |
||||||
|
true, |
||||||
|
::protos::SetExtension(mutable_recursive_child, theme, extension1).ok()); |
||||||
|
EXPECT_EQ("Hello World", |
||||||
|
::protos::GetExtension(mutable_recursive_child, theme) |
||||||
|
.value() |
||||||
|
->ext_name()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, GetExtensionOnImmutableChild) { |
||||||
|
TestModel model; |
||||||
|
ThemeExtension extension1; |
||||||
|
extension1.set_ext_name("Hello World"); |
||||||
|
::protos::Ptr<TestModel> mutable_recursive_child = |
||||||
|
model.mutable_recursive_child(); |
||||||
|
EXPECT_EQ(false, ::protos::HasExtension(mutable_recursive_child, theme)); |
||||||
|
EXPECT_EQ( |
||||||
|
true, |
||||||
|
::protos::SetExtension(mutable_recursive_child, theme, extension1).ok()); |
||||||
|
::protos::Ptr<const TestModel> recursive_child = model.recursive_child(); |
||||||
|
EXPECT_EQ("Hello World", |
||||||
|
::protos::GetExtension(recursive_child, theme).value()->ext_name()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, SerializeUsingArena) { |
||||||
|
TestModel model; |
||||||
|
model.set_str1("Hello World"); |
||||||
|
::upb::Arena arena; |
||||||
|
absl::StatusOr<absl::string_view> bytes = ::protos::Serialize(model, arena); |
||||||
|
EXPECT_EQ(true, bytes.ok()); |
||||||
|
TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value(); |
||||||
|
EXPECT_EQ("Hello World", parsed_model.str1()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, SerializeNestedMessageUsingArena) { |
||||||
|
TestModel model; |
||||||
|
model.mutable_recursive_child()->set_str1("Hello World"); |
||||||
|
::upb::Arena arena; |
||||||
|
::protos::Ptr<const TestModel> child = model.recursive_child(); |
||||||
|
absl::StatusOr<absl::string_view> bytes = ::protos::Serialize(child, arena); |
||||||
|
EXPECT_EQ(true, bytes.ok()); |
||||||
|
TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value(); |
||||||
|
EXPECT_EQ("Hello World", parsed_model.str1()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, Parse) { |
||||||
|
TestModel model; |
||||||
|
model.set_str1("Test123"); |
||||||
|
ThemeExtension extension1; |
||||||
|
extension1.set_ext_name("Hello World"); |
||||||
|
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok()); |
||||||
|
::upb::Arena arena; |
||||||
|
auto bytes = ::protos::Serialize(model, arena); |
||||||
|
EXPECT_EQ(true, bytes.ok()); |
||||||
|
TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value(); |
||||||
|
EXPECT_EQ("Test123", parsed_model.str1()); |
||||||
|
// Should not return an extension since we did not pass ExtensionRegistry.
|
||||||
|
EXPECT_EQ(false, ::protos::GetExtension(parsed_model, theme).ok()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, ParseWithExtensionRegistry) { |
||||||
|
TestModel model; |
||||||
|
model.set_str1("Test123"); |
||||||
|
ThemeExtension extension1; |
||||||
|
extension1.set_ext_name("Hello World"); |
||||||
|
EXPECT_EQ(true, ::protos::SetExtension(model, theme, extension1).ok()); |
||||||
|
::upb::Arena arena; |
||||||
|
auto bytes = ::protos::Serialize(model, arena); |
||||||
|
EXPECT_EQ(true, bytes.ok()); |
||||||
|
::protos::ExtensionRegistry extensions({&theme, &other_ext}, arena); |
||||||
|
TestModel parsed_model = |
||||||
|
::protos::Parse<TestModel>(bytes.value(), extensions).value(); |
||||||
|
EXPECT_EQ("Test123", parsed_model.str1()); |
||||||
|
EXPECT_EQ(true, ::protos::GetExtension(parsed_model, theme).ok()); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(CppGeneratedCode, NameCollisions) { |
||||||
|
TestModel model; |
||||||
|
model.set_template_("test"); |
||||||
|
EXPECT_EQ("test", model.template_()); |
||||||
|
model.set_arena__("test"); |
||||||
|
EXPECT_EQ("test", model.arena__()); |
||||||
|
} |
@ -0,0 +1,149 @@ |
|||||||
|
syntax = "proto2"; |
||||||
|
|
||||||
|
package protos_generator.test; |
||||||
|
|
||||||
|
import "protos_generator/tests/child_model.proto"; |
||||||
|
|
||||||
|
message TestModelContainer { |
||||||
|
repeated TestModel models = 1; |
||||||
|
optional ChildModel3 proto_3_child = 2; |
||||||
|
} |
||||||
|
|
||||||
|
message TestModel { |
||||||
|
optional int32 value = 1; |
||||||
|
repeated int32 value_array = 2; // _UPB_MODE_ARRAY |
||||||
|
repeated int32 value_packed_array = 3 |
||||||
|
[packed = true]; // _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED |
||||||
|
repeated int32 value_deprec = 4 [deprecated = true]; |
||||||
|
optional string str1 = 115; |
||||||
|
optional bool b1 = 9; |
||||||
|
optional bool b2 = 10; |
||||||
|
optional string str2 = 50; |
||||||
|
optional string str3 = 11; |
||||||
|
optional float optional_float = 14; |
||||||
|
optional double optional_double = 15; |
||||||
|
optional int64 optional_int64 = 16; |
||||||
|
optional uint32 optional_uint32 = 17; |
||||||
|
optional uint64 optional_uint64 = 18; |
||||||
|
optional sint32 optional_sint32 = 19; |
||||||
|
optional sint64 optional_sint64 = 20; |
||||||
|
optional fixed32 optional_fixed32 = 21; |
||||||
|
optional fixed64 optional_fixed64 = 22; |
||||||
|
optional sfixed32 optional_sfixed32 = 23; |
||||||
|
optional sfixed64 optional_sfixed64 = 24; |
||||||
|
repeated int64 repeated_int64 = 25; |
||||||
|
repeated uint64 repeated_uint64 = 26; |
||||||
|
repeated fixed64 repeated_fixed64 = 27; |
||||||
|
repeated sfixed64 repeated_sfixed64 = 28; |
||||||
|
repeated bool repeated_bool = 29; |
||||||
|
repeated string repeated_string = 35; |
||||||
|
optional bytes optional_bytes = 36; |
||||||
|
message NestedChild { |
||||||
|
optional string nested_child_name = 211; |
||||||
|
} |
||||||
|
optional NestedChild nested_child_1 = 212; |
||||||
|
optional ChildModel1 child_model_1 = 222; |
||||||
|
repeated ChildModel1 child_model_2 = 223; |
||||||
|
optional ChildModel1 bar = 224; |
||||||
|
oneof child_oneof1 { |
||||||
|
string oneof_member1 = 98; |
||||||
|
bool oneof_member2 = 99; |
||||||
|
} |
||||||
|
optional int32 int_value_with_default = 31 |
||||||
|
[default = 65]; // Not supported yet |
||||||
|
optional string string_value_with_default = 32 |
||||||
|
[default = "hello"]; // Not supported yet |
||||||
|
optional float float_value_with_default = 33 [default = inf]; |
||||||
|
optional float double_value_with_default = 34 [default = -inf]; |
||||||
|
|
||||||
|
map<int32, ChildModel1> child_map = 225; |
||||||
|
optional TestModel recursive_child = 226; |
||||||
|
map<string, ChildModel1> child_str_map = 227; |
||||||
|
map<string, int32> str_to_int_map = 228; |
||||||
|
map<string, string> str_to_str_map = 229; |
||||||
|
|
||||||
|
extend TestAnnotation { |
||||||
|
optional OtherExtension in_message_ext = 15000; |
||||||
|
} |
||||||
|
|
||||||
|
enum Category { |
||||||
|
IMAGES = 5; |
||||||
|
NEWS = 6; |
||||||
|
VIDEO = 7; |
||||||
|
RADIO = 8 [deprecated = true]; |
||||||
|
} |
||||||
|
optional Category category = 37; |
||||||
|
|
||||||
|
// keyword collisions (double, template, ...) |
||||||
|
oneof type { |
||||||
|
string string = 230; |
||||||
|
int64 int64 = 231; |
||||||
|
double double = 232; |
||||||
|
} |
||||||
|
optional string template = 233; |
||||||
|
optional string msg = 234; |
||||||
|
optional string arena = 235; |
||||||
|
|
||||||
|
// Tests publicly imported enum. |
||||||
|
optional TestEnum imported_enum = 238; |
||||||
|
|
||||||
|
// TODO(243705098) accessor name collision with field name |
||||||
|
// optional repeated string phase = 236; |
||||||
|
// optional bool clear_phase = 237; |
||||||
|
|
||||||
|
extensions 10000 to max; |
||||||
|
} |
||||||
|
|
||||||
|
// Old version with fewer fields to test backward/forward compatibility. |
||||||
|
message TestModelContainerV1 { |
||||||
|
repeated TestModelV1 models = 1; |
||||||
|
} |
||||||
|
|
||||||
|
message TestModelV1 { |
||||||
|
optional int32 value = 1; |
||||||
|
repeated int32 value2 = 2; |
||||||
|
repeated int32 value3 = 3 [packed = true]; |
||||||
|
repeated int32 value4 = 4 [deprecated = true]; |
||||||
|
optional bool b1 = 9; |
||||||
|
optional bool b2 = 10; |
||||||
|
optional string str2 = 50; |
||||||
|
} |
||||||
|
|
||||||
|
enum PrimaryColors { |
||||||
|
RED = 1; |
||||||
|
GREEN = 2; |
||||||
|
BLUE = 3; |
||||||
|
} |
||||||
|
|
||||||
|
// TestModel extension. |
||||||
|
message ThemeExtension { |
||||||
|
optional string ext_name = 1; |
||||||
|
optional bool ext_bool = 2; |
||||||
|
} |
||||||
|
|
||||||
|
extend TestModel { |
||||||
|
optional ThemeExtension theme = 12001; |
||||||
|
} |
||||||
|
|
||||||
|
message OtherExtension { |
||||||
|
optional string ext2_name = 1; |
||||||
|
} |
||||||
|
|
||||||
|
extend TestModel { |
||||||
|
optional OtherExtension other_ext = 12002; |
||||||
|
} |
||||||
|
|
||||||
|
message TestAnnotation { |
||||||
|
extensions 10000 to max; |
||||||
|
} |
||||||
|
|
||||||
|
message TestMessageHasEnum { |
||||||
|
optional EnumDeclaredAfterMessage enum_declared_after_message = 1; |
||||||
|
} |
||||||
|
|
||||||
|
enum EnumDeclaredAfterMessage { |
||||||
|
ZERO = 0; |
||||||
|
ONE = 1; |
||||||
|
TWO = 2; |
||||||
|
THREE = 3; |
||||||
|
} |
Loading…
Reference in new issue