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