Reorganize upb file structure This change moves almost everything in the `upb/` directory up one level, so that for example `upb/upb/generated_code_support.h` becomes just `upb/generated_code_support.h`. The only exceptions I made to this were that I left `upb/cmake` and `upb/BUILD` where they are, mostly because that avoids conflict with other files and the current locations seem reasonable for now. The `python/` directory is a little bit of a challenge because we had to merge the existing directory there with `upb/python/`. I made `upb/python/BUILD` into the BUILD file for the merged directory, and it effectively loads the contents of the other BUILD file via `python/build_targets.bzl`, but I plan to clean this up soon. PiperOrigin-RevId: 568651768
diff --git a/upbc/BUILD b/upbc/BUILD new file mode 100644 index 0000000..399a14e --- /dev/null +++ b/upbc/BUILD
@@ -0,0 +1,336 @@ +# Copyright (c) 2009-2021, Google LLC +# All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +load( + "//bazel:build_defs.bzl", + "UPB_DEFAULT_COPTS", + "UPB_DEFAULT_CPPOPTS", +) +load( + "//bazel:upb_minitable_proto_library.bzl", + "upb_minitable_proto_library", +) +load( + "//bazel:upb_proto_library.bzl", + "upb_proto_library", + "upb_proto_reflection_library", +) +load( + "//upbc:bootstrap_compiler.bzl", + "bootstrap_cc_binary", + "bootstrap_cc_library", + "bootstrap_upb_proto_library", +) + +# begin:google_only +# package(default_applicable_licenses = ["//upb:license"]) +# end:google_only + +licenses(["notice"]) + +proto_library( + name = "code_generator_request", + srcs = ["code_generator_request.proto"], + visibility = ["//upb:friends"], + deps = ["//:compiler_plugin_proto"], +) + +upb_proto_library( + name = "code_generator_request_upb_proto", + visibility = ["//upb:friends"], + deps = [":code_generator_request"], +) + +upb_proto_reflection_library( + name = "code_generator_request_upb_proto_reflection", + visibility = ["//upb:friends"], + deps = [":code_generator_request"], +) + +upb_minitable_proto_library( + name = "code_generator_request_upb_minitable_proto", + visibility = ["//upb:friends"], + deps = [":code_generator_request"], +) + +bootstrap_upb_proto_library( + name = "plugin_upb_proto", + base_dir = "", + # TODO: Export 'net/proto2/proto/descriptor.upb.h' and remove "-layering_check". + features = ["-layering_check"], + google3_src_files = [ + "net/proto2/compiler/proto/profile.proto", + "third_party/protobuf/compiler/plugin.proto", + ], + google3_src_rules = [ + "//net/proto2/proto:descriptor_proto_source", + "//net/proto2/compiler/proto:profile.proto", + "//src/google/protobuf/compiler:plugin_proto_source", + ], + oss_src_files = ["google/protobuf/compiler/plugin.proto"], + oss_src_rules = [ + "//:descriptor_proto_srcs", + "//src/google/protobuf/compiler:plugin_proto_src", + ], + oss_strip_prefix = "third_party/protobuf/github/bootstrap/src", + proto_lib_deps = ["//:compiler_plugin_proto"], + visibility = ["//upb:friends"], + deps = ["//upb:descriptor_upb_proto"], +) + +upb_proto_reflection_library( + name = "plugin_upb_proto_reflection", + visibility = ["//upb:friends"], + deps = ["//:compiler_plugin_proto"], +) + +bootstrap_cc_library( + name = "common", + srcs = [ + "common.cc", + ], + hdrs = [ + "common.h", + ], + bootstrap_deps = [ + "//upb:reflection", + ], + copts = UPB_DEFAULT_CPPOPTS, + visibility = ["//protos_generator:__pkg__"], + deps = [ + "//upb:mini_table", + "//upb:mini_table_internal", + "//upb:port", + "@com_google_absl//absl/strings", + ], +) + +bootstrap_cc_library( + name = "file_layout", + srcs = [ + "file_layout.cc", + ], + hdrs = [ + "file_layout.h", + ], + bootstrap_deps = [ + ":common", + "//upb:reflection", + "//upb:descriptor_upb_proto", + ], + copts = UPB_DEFAULT_CPPOPTS, + visibility = ["//protos_generator:__pkg__"], + deps = [ + "//upb:base", + "//upb:mini_descriptor", + "//upb:mini_table", + "//upb:mini_table_internal", + "//upb:port", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/strings", + ], +) + +cc_library( + name = "keywords", + srcs = [ + "keywords.cc", + ], + hdrs = [ + "keywords.h", + ], + copts = UPB_DEFAULT_CPPOPTS, + visibility = ["//protos_generator:__pkg__"], +) + +bootstrap_cc_library( + name = "plugin", + hdrs = [ + "plugin.h", + ], + bootstrap_deps = [ + ":plugin_upb_proto", + "//upb:descriptor_upb_proto", + "//upb:reflection", + ], + copts = UPB_DEFAULT_CPPOPTS, + visibility = ["//protos_generator:__pkg__"], + deps = [ + "//upb:port", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/log:absl_check", + "@com_google_absl//absl/log:absl_log", + "@com_google_absl//absl/strings", + ], +) + +bootstrap_cc_library( + name = "names", + srcs = [ + "names.cc", + ], + hdrs = [ + "names.h", + ], + bootstrap_deps = [ + "//upb:reflection", + ], + copts = UPB_DEFAULT_CPPOPTS, + visibility = ["//protos_generator:__pkg__"], + deps = [ + "//:protobuf", + "//src/google/protobuf/compiler:code_generator", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/strings", + ], +) + +cc_binary( + name = "libupbc.so", + srcs = ["upbc_so.c"], + copts = UPB_DEFAULT_COPTS + ["-DUPB_BUILD_API"], + linkshared = 1, + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [ + ":upbdev", + "//upb:port", + ], +) + +cc_library( + name = "upbdev", + srcs = [ + "code_generator_request.c", + "code_generator_request.h", + "get_used_fields.c", + "upbdev.c", + ], + hdrs = [ + "get_used_fields.h", + "upbdev.h", + ], + copts = UPB_DEFAULT_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":code_generator_request_upb_proto", + ":code_generator_request_upb_proto_reflection", + ":plugin_upb_proto", + ":plugin_upb_proto_reflection", + "//upb:base", + "//upb:descriptor_upb_proto", + "//upb:json", + "//upb:mem", + "//upb:mini_descriptor", + "//upb:mini_table", + "//upb:port", + "//upb:reflection", + "//upb:reflection_internal", + "//upb:wire", + ], +) + +bootstrap_cc_binary( + name = "protoc-gen-upb", + srcs = ["protoc-gen-upb.cc"], + bootstrap_deps = [ + ":common", + ":file_layout", + ":names", + ":plugin", + ":plugin_upb_proto", + "//upb:descriptor_upb_proto", + "//upb:reflection", + ], + copts = UPB_DEFAULT_CPPOPTS, + visibility = ["//visibility:public"], + deps = [ + "//upb:base", + "//upb:mem", + "//upb:mini_table_internal", + "//upb:port", + "//upb:wire_types", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/log:absl_check", + "@com_google_absl//absl/log:absl_log", + "@com_google_absl//absl/strings", + ], +) + +bootstrap_cc_binary( + name = "protoc-gen-upb_minitable", + srcs = ["protoc-gen-upb_minitable.cc"], + bootstrap_deps = [ + ":common", + ":file_layout", + ":names", + ":plugin", + ":plugin_upb_proto", + "//upb:descriptor_upb_proto", + "//upb:reflection", + ], + copts = UPB_DEFAULT_CPPOPTS, + visibility = ["//visibility:public"], + deps = [ + "//upb:base", + "//upb:mem", + "//upb:mini_table_internal", + "//upb:port", + "//upb:wire_types", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/log:absl_check", + "@com_google_absl//absl/log:absl_log", + "@com_google_absl//absl/strings", + ], +) + +cc_binary( + name = "protoc-gen-upbdefs", + srcs = [ + "protoc-gen-upbdefs.cc", + ], + copts = UPB_DEFAULT_CPPOPTS, + # To work around the following link error from ABSL: + # /usr/bin/x86_64-linux-gnu-ld: bazel-out/k8-opt-exec-2B5CBBC6-ST-c1776f9924ec/bin/external/com_google_absl/absl/time/libtime.a(duration.o): undefined reference to symbol 'floor@@GLIBC_2.2.5' + # /usr/bin/x86_64-linux-gnu-ld: /opt/manylinux/2014/x86_64/lib64/libm.so.6: error adding symbols: DSO missing from command line + # clang-14: error: linker command failed with exit code 1 (use -v to see invocation) + linkopts = ["-lm"], + visibility = ["//visibility:public"], + deps = [ + ":common", + ":file_layout", + ":plugin", + "//upb:descriptor_upb_proto", + "//upb:reflection", + "//upb/util:def_to_proto", + ], +) + +cc_binary( + name = "protoc-gen-upbdev", + srcs = [ + "protoc-gen-upbdev.cc", + "subprocess.cc", + "subprocess.h", + ], + copts = UPB_DEFAULT_CPPOPTS, + target_compatible_with = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [ + ":plugin_upb_proto", + ":upbdev", + "//upb:port", + "@com_google_absl//absl/log:absl_log", + "@com_google_absl//absl/strings", + ], +)
diff --git a/upbc/bootstrap_compiler.bzl b/upbc/bootstrap_compiler.bzl new file mode 100644 index 0000000..fcc1102 --- /dev/null +++ b/upbc/bootstrap_compiler.bzl
@@ -0,0 +1,189 @@ +"""Macros that implement bootstrapping for the upb code generator.""" + +load( + "//bazel:upb_proto_library.bzl", + "upb_proto_library", +) +load( + "//upb/cmake:build_defs.bzl", + "staleness_test", +) + +_stages = ["_stage0", "_stage1", ""] +_protoc = "//:protoc" +_upbc_base = "//upbc:protoc-gen-" + +# begin:google_only +# _is_google3 = True +# _extra_proto_path = "" +# end:google_only + +# begin:github_only +_is_google3 = False +_extra_proto_path = "-I$$(dirname $(location @com_google_protobuf//:descriptor_proto_srcs))/../.. " +# end:github_only + +def _upbc(generator, stage): + return _upbc_base + generator + _stages[stage] + +def bootstrap_cc_library(name, visibility, deps, bootstrap_deps, **kwargs): + for stage in _stages: + stage_visibility = visibility if stage == "" else ["//upbc:__pkg__"] + native.cc_library( + name = name + stage, + deps = deps + [dep + stage for dep in bootstrap_deps], + visibility = stage_visibility, + **kwargs + ) + +def bootstrap_cc_binary(name, deps, bootstrap_deps, **kwargs): + for stage in _stages: + native.cc_binary( + name = name + stage, + deps = deps + [dep + stage for dep in bootstrap_deps], + **kwargs + ) + +def _generated_srcs_for_suffix(prefix, srcs, suffix): + return [prefix + "/" + src[:-len(".proto")] + suffix for src in srcs] + +def _generated_srcs_for_generator(prefix, srcs, generator): + ret = _generated_srcs_for_suffix(prefix, srcs, ".{}.h".format(generator)) + + if not (generator == "upb" and prefix.endswith("stage1")): + ret += _generated_srcs_for_suffix(prefix, srcs, ".{}.c".format(generator)) + return ret + +def _generated_srcs(prefix, srcs): + return _generated_srcs_for_generator(prefix, srcs, "upb") + +def _stage0_proto_staleness_test(name, base_dir, src_files, src_rules, strip_prefix): + native.genrule( + name = name + "_generate_bootstrap", + srcs = src_rules, + outs = _generated_srcs("bootstrap_generated_sources/" + base_dir + "stage0", src_files), + tools = [_protoc, _upbc("upb", 0)], + cmd = + "$(location " + _protoc + ") " + + "-I$(GENDIR)/" + strip_prefix + " " + _extra_proto_path + + "--plugin=protoc-gen-upb=$(location " + _upbc("upb", 0) + ") " + + "--upb_out=bootstrap_upb:$(@D)/bootstrap_generated_sources/" + base_dir + "stage0 " + + " ".join(src_files), + ) + + staleness_test( + name = name + "_staleness_test", + outs = _generated_srcs(base_dir + "stage0", src_files), + generated_pattern = "bootstrap_generated_sources/%s", + target_files = native.glob([base_dir + "stage0/**"]), + # To avoid skew problems for descriptor.proto/pluging.proto between + # GitHub repos. It's not critical that the checked-in protos are up to + # date for every change, they just needs to be complete enough to have + # everything needed by the code generator itself. + tags = ["manual"], + ) + +def _generate_stage1_proto(name, base_dir, src_files, src_rules, generator, kwargs): + native.genrule( + name = "gen_{}_{}_stage1".format(name, generator), + srcs = src_rules, + outs = _generated_srcs_for_generator(base_dir + "stage1", src_files, generator), + cmd = "$(location " + _protoc + ") " + + "--plugin=protoc-gen-" + generator + + "=$(location " + _upbc(generator, 0) + ") " + _extra_proto_path + + "--" + generator + "_out=$(RULEDIR)/" + base_dir + "stage1 " + + " ".join(src_files), + visibility = ["//upbc:__pkg__"], + tools = [ + _protoc, + _upbc(generator, 0), + ], + **kwargs + ) + +def bootstrap_upb_proto_library( + name, + base_dir, + google3_src_files, + google3_src_rules, + oss_src_files, + oss_src_rules, + oss_strip_prefix, + proto_lib_deps, + visibility, + deps = [], + **kwargs): + """A version of upb_proto_library() that is augmented to allow for bootstrapping the compiler. + + Args: + name: Name of this rule. This name will resolve to a upb_proto_library(). + base_dir: The directory that all generated files should be placed under. + google3_src_files: Google3 filenames of .proto files that should be built by this rule. + The names should be relative to the depot base. + google3_src_rules: Target names of the Blaze rules that will provide these filenames. + oss_src_files: OSS filenames of .proto files that should be built by this rule. + oss_src_rules: Target names of the Bazel rules that will provide these filenames. + oss_strip_prefix: Prefix that should be stripped from OSS file names. + proto_lib_deps: proto_library() rules that we will use to build the protos when we are + not bootstrapping. + visibility: Visibility list for the final upb_proto_library() rule. Bootstrapping rules + will always be hidden, and will not honor the visibility parameter passed here. + deps: other bootstrap_upb_proto_library() rules that this one depends on. + **kwargs: Other arguments that will be passed through to cc_library(), genrule(), and + upb_proto_library(). + """ + _stage0_proto_staleness_test(name, base_dir, oss_src_files, oss_src_rules, oss_strip_prefix) + + # stage0 uses checked-in protos, and has no MiniTable. + native.cc_library( + name = name + "_stage0", + srcs = _generated_srcs_for_suffix(base_dir + "stage0", oss_src_files, ".upb.c"), + hdrs = _generated_srcs_for_suffix(base_dir + "stage0", oss_src_files, ".upb.h"), + includes = [base_dir + "stage0"], + visibility = ["//upbc:__pkg__"], + # This macro signals to the runtime that it must use OSS APIs for descriptor.proto/plugin.proto. + defines = ["UPB_BOOTSTRAP_STAGE0"], + deps = [ + "//upb:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", + "//upb:mini_table", + ] + [dep + "_stage0" for dep in deps], + **kwargs + ) + + src_files = google3_src_files if _is_google3 else oss_src_files + src_rules = google3_src_rules if _is_google3 else oss_src_rules + + # Generate stage1 protos (C API and MiniTables) using stage0 compiler. + _generate_stage1_proto(name, base_dir, src_files, src_rules, "upb", kwargs) + _generate_stage1_proto(name, base_dir, src_files, src_rules, "upb_minitable", kwargs) + + native.cc_library( + name = name + "_minitable_stage1", + srcs = _generated_srcs_for_suffix(base_dir + "stage1", src_files, ".upb_minitable.c"), + hdrs = _generated_srcs_for_suffix(base_dir + "stage1", src_files, ".upb_minitable.h"), + includes = [base_dir + "stage1"], + visibility = ["//upbc:__pkg__"], + deps = [ + "//upb:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", + ] + [dep + "_stage1" for dep in deps], + **kwargs + ) + native.cc_library( + name = name + "_stage1", + hdrs = _generated_srcs_for_suffix(base_dir + "stage1", src_files, ".upb.h"), + includes = [base_dir + "stage1"], + visibility = ["//upbc:__pkg__"], + deps = [ + "//upb:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", + ":" + name + "_minitable_stage1", + ] + [dep + "_stage1" for dep in deps], + **kwargs + ) + + # The final protos are generated via normal upb_proto_library(). + upb_proto_library( + name = name, + deps = proto_lib_deps, + visibility = visibility, + **kwargs + )
diff --git a/upbc/code_generator_request.c b/upbc/code_generator_request.c new file mode 100644 index 0000000..4ab5fcc --- /dev/null +++ b/upbc/code_generator_request.c
@@ -0,0 +1,262 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 "upbc/code_generator_request.h" + +#include <inttypes.h> + +#include "google/protobuf/compiler/plugin.upb.h" +#include "upb/mini_descriptor/decode.h" +#include "upb/reflection/def.h" + +// Must be last. +#include "upb/port/def.inc" + +/******************************************************************************/ + +// Kitchen sink storage for all of our state as we build the mini descriptors. + +typedef struct { + upb_Arena* arena; + upb_Status* status; + upb_DefPool* symtab; + + upbc_CodeGeneratorRequest* out; + + jmp_buf jmp; +} upbc_State; + +static void upbc_State_Fini(upbc_State* s) { + if (s->symtab) upb_DefPool_Free(s->symtab); +} + +UPB_NORETURN static void upbc_Error(upbc_State* s, const char* fn, + const char* msg) { + upb_Status_SetErrorFormat(s->status, "%s(): %s", fn, msg); + upbc_State_Fini(s); + UPB_LONGJMP(s->jmp, -1); +} + +static void upbc_State_Init(upbc_State* s) { + s->symtab = upb_DefPool_New(); + if (!s->symtab) upbc_Error(s, __func__, "could not allocate def pool"); + + s->out = upbc_CodeGeneratorRequest_new(s->arena); + if (!s->out) upbc_Error(s, __func__, "could not allocate request"); +} + +static upb_StringView upbc_State_StrDup(upbc_State* s, const char* str) { + upb_StringView from = upb_StringView_FromString(str); + char* to = upb_Arena_Malloc(s->arena, from.size); + if (!to) upbc_Error(s, __func__, "Out of memory"); + memcpy(to, from.data, from.size); + return upb_StringView_FromDataAndSize(to, from.size); +} + +static void upbc_State_AddMiniDescriptor(upbc_State* s, const char* name, + upb_StringView encoding) { + const upb_StringView key = upb_StringView_FromString(name); + upbc_CodeGeneratorRequest_UpbInfo* info = + upbc_CodeGeneratorRequest_UpbInfo_new(s->arena); + if (!info) upbc_Error(s, __func__, "Out of memory"); + upbc_CodeGeneratorRequest_UpbInfo_set_mini_descriptor(info, encoding); + bool ok = upbc_CodeGeneratorRequest_upb_info_set(s->out, key, info, s->arena); + if (!ok) upbc_Error(s, __func__, "could not set mini descriptor in map"); +} + +/******************************************************************************/ + +// Forward declaration. +static void upbc_Scrape_Message(upbc_State*, const upb_MessageDef*); + +static void upbc_Scrape_Enum(upbc_State* s, const upb_EnumDef* e) { + upb_StringView desc; + bool ok = upb_EnumDef_MiniDescriptorEncode(e, s->arena, &desc); + if (!ok) upbc_Error(s, __func__, "could not encode enum"); + + upbc_State_AddMiniDescriptor(s, upb_EnumDef_FullName(e), desc); +} + +static void upbc_Scrape_Extension(upbc_State* s, const upb_FieldDef* f) { + upb_StringView desc; + bool ok = upb_FieldDef_MiniDescriptorEncode(f, s->arena, &desc); + if (!ok) upbc_Error(s, __func__, "could not encode extension"); + + upbc_State_AddMiniDescriptor(s, upb_FieldDef_FullName(f), desc); +} + +static void upbc_Scrape_FileEnums(upbc_State* s, const upb_FileDef* f) { + const size_t len = upb_FileDef_TopLevelEnumCount(f); + + for (size_t i = 0; i < len; i++) { + upbc_Scrape_Enum(s, upb_FileDef_TopLevelEnum(f, i)); + } +} + +static void upbc_Scrape_FileExtensions(upbc_State* s, const upb_FileDef* f) { + const size_t len = upb_FileDef_TopLevelExtensionCount(f); + + for (size_t i = 0; i < len; i++) { + upbc_Scrape_Extension(s, upb_FileDef_TopLevelExtension(f, i)); + } +} + +static void upbc_Scrape_FileMessages(upbc_State* s, const upb_FileDef* f) { + const size_t len = upb_FileDef_TopLevelMessageCount(f); + + for (size_t i = 0; i < len; i++) { + upbc_Scrape_Message(s, upb_FileDef_TopLevelMessage(f, i)); + } +} + +static void upbc_Scrape_File(upbc_State* s, const upb_FileDef* f) { + upbc_Scrape_FileEnums(s, f); + upbc_Scrape_FileExtensions(s, f); + upbc_Scrape_FileMessages(s, f); +} + +static void upbc_Scrape_Files(upbc_State* s) { + const google_protobuf_compiler_CodeGeneratorRequest* request = + upbc_CodeGeneratorRequest_request(s->out); + + size_t len = 0; + const google_protobuf_FileDescriptorProto* const* files = + google_protobuf_compiler_CodeGeneratorRequest_proto_file(request, &len); + + for (size_t i = 0; i < len; i++) { + const upb_FileDef* f = upb_DefPool_AddFile(s->symtab, files[i], s->status); + if (!f) upbc_Error(s, __func__, "could not add file to def pool"); + + upbc_Scrape_File(s, f); + } +} + +static void upbc_Scrape_NestedEnums(upbc_State* s, const upb_MessageDef* m) { + const size_t len = upb_MessageDef_NestedEnumCount(m); + + for (size_t i = 0; i < len; i++) { + upbc_Scrape_Enum(s, upb_MessageDef_NestedEnum(m, i)); + } +} + +static void upbc_Scrape_NestedExtensions(upbc_State* s, + const upb_MessageDef* m) { + const size_t len = upb_MessageDef_NestedExtensionCount(m); + + for (size_t i = 0; i < len; i++) { + upbc_Scrape_Extension(s, upb_MessageDef_NestedExtension(m, i)); + } +} + +static void upbc_Scrape_NestedMessages(upbc_State* s, const upb_MessageDef* m) { + const size_t len = upb_MessageDef_NestedMessageCount(m); + + for (size_t i = 0; i < len; i++) { + upbc_Scrape_Message(s, upb_MessageDef_NestedMessage(m, i)); + } +} + +static void upbc_Scrape_MessageSubs(upbc_State* s, + upbc_CodeGeneratorRequest_UpbInfo* info, + const upb_MessageDef* m) { + const upb_MiniTableField** fields = + malloc(upb_MessageDef_FieldCount(m) * sizeof(*fields)); + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + uint32_t counts = upb_MiniTable_GetSubList(mt, fields); + uint32_t msg_count = counts >> 16; + uint32_t enum_count = counts & 0xffff; + + for (uint32_t i = 0; i < msg_count; i++) { + const upb_FieldDef* f = + upb_MessageDef_FindFieldByNumber(m, fields[i]->number); + if (!f) upbc_Error(s, __func__, "Missing f"); + const upb_MessageDef* sub = upb_FieldDef_MessageSubDef(f); + if (!sub) upbc_Error(s, __func__, "Missing sub"); + upb_StringView name = upbc_State_StrDup(s, upb_MessageDef_FullName(sub)); + upbc_CodeGeneratorRequest_UpbInfo_add_sub_message(info, name, s->arena); + } + + for (uint32_t i = 0; i < enum_count; i++) { + const upb_FieldDef* f = + upb_MessageDef_FindFieldByNumber(m, fields[msg_count + i]->number); + if (!f) upbc_Error(s, __func__, "Missing f (2)"); + const upb_EnumDef* sub = upb_FieldDef_EnumSubDef(f); + if (!sub) upbc_Error(s, __func__, "Missing sub (2)"); + upb_StringView name = upbc_State_StrDup(s, upb_EnumDef_FullName(sub)); + upbc_CodeGeneratorRequest_UpbInfo_add_sub_enum(info, name, s->arena); + } + + free(fields); +} + +static void upbc_Scrape_Message(upbc_State* s, const upb_MessageDef* m) { + upb_StringView desc; + bool ok = upb_MessageDef_MiniDescriptorEncode(m, s->arena, &desc); + if (!ok) upbc_Error(s, __func__, "could not encode message"); + + upbc_CodeGeneratorRequest_UpbInfo* info = + upbc_CodeGeneratorRequest_UpbInfo_new(s->arena); + if (!info) upbc_Error(s, __func__, "Out of memory"); + upbc_CodeGeneratorRequest_UpbInfo_set_mini_descriptor(info, desc); + + upbc_Scrape_MessageSubs(s, info, m); + + const upb_StringView key = upbc_State_StrDup(s, upb_MessageDef_FullName(m)); + ok = upbc_CodeGeneratorRequest_upb_info_set(s->out, key, info, s->arena); + if (!ok) upbc_Error(s, __func__, "could not set mini descriptor in map"); + + upbc_Scrape_NestedEnums(s, m); + upbc_Scrape_NestedExtensions(s, m); + upbc_Scrape_NestedMessages(s, m); +} + +static upbc_CodeGeneratorRequest* upbc_State_MakeCodeGeneratorRequest( + upbc_State* const s, google_protobuf_compiler_CodeGeneratorRequest* const request) { + if (UPB_SETJMP(s->jmp)) return NULL; + upbc_State_Init(s); + + upbc_CodeGeneratorRequest_set_request(s->out, request); + upbc_Scrape_Files(s); + upbc_State_Fini(s); + return s->out; +} + +upbc_CodeGeneratorRequest* upbc_MakeCodeGeneratorRequest( + google_protobuf_compiler_CodeGeneratorRequest* request, upb_Arena* arena, + upb_Status* status) { + upbc_State s = { + .arena = arena, + .status = status, + .symtab = NULL, + .out = NULL, + }; + + return upbc_State_MakeCodeGeneratorRequest(&s, request); +}
diff --git a/upbc/code_generator_request.h b/upbc/code_generator_request.h new file mode 100644 index 0000000..3218c08 --- /dev/null +++ b/upbc/code_generator_request.h
@@ -0,0 +1,55 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 UPBC_CODE_GENERATOR_REQUEST_H_ +#define UPBC_CODE_GENERATOR_REQUEST_H_ + +#include "upb/mem/arena.h" +#include "upb/reflection/def.h" +#include "upbc/code_generator_request.upb.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +upbc_CodeGeneratorRequest* upbc_MakeCodeGeneratorRequest( + struct google_protobuf_compiler_CodeGeneratorRequest* request, upb_Arena* a, + upb_Status* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif /* UPBC_CODE_GENERATOR_REQUEST_H_ */
diff --git a/upbc/code_generator_request.proto b/upbc/code_generator_request.proto new file mode 100644 index 0000000..600faee --- /dev/null +++ b/upbc/code_generator_request.proto
@@ -0,0 +1,56 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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. + +syntax = "proto2"; + +package upbc; + +import "google/protobuf/compiler/plugin.proto"; + +message CodeGeneratorRequest { + message UpbInfo { + optional string mini_descriptor = 1; + + // An ordered list of fully qualified sub-message names whose upb_MiniTable + // should be passed to upb_MiniTable_Link(). + repeated string sub_message = 3; + + // An ordered list of fully qualified sub-enum names whose upb_MiniTableEnum + // should be passed to upb_MiniTable_Link(). + repeated string sub_enum = 4; + } + + // The pb sent by protoc to its plugins. + optional google.protobuf.compiler.CodeGeneratorRequest request = 1; + + // upb-specific info for the messages/enums/extensions in the request, keyed + // by the fully qualified names. + map<string, UpbInfo> upb_info = 2; +}
diff --git a/upbc/common.cc b/upbc/common.cc new file mode 100644 index 0000000..b5bad20 --- /dev/null +++ b/upbc/common.cc
@@ -0,0 +1,188 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 "upbc/common.h" + +#include <assert.h> +#include <stdint.h> +#include <stdlib.h> + +#include <string> + +#include "absl/strings/ascii.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "upb/mini_table/field.h" +#include "upb/mini_table/internal/field.h" +#include "upb/reflection/def.hpp" + +// Must be last +#include "upb/port/def.inc" + +namespace upbc { + +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(absl::string_view name, Output& output) { + output( + "/* This file was generated by upbc (the upb compiler) from the input\n" + " * file:\n" + " *\n" + " * $0\n" + " *\n" + " * Do not edit -- your changes will be discarded when the file is\n" + " * regenerated. */\n\n", + name); +} + +std::string MessageName(upb::MessageDefPtr descriptor) { + return ToCIdent(descriptor.full_name()); +} + +std::string FileLayoutName(upb::FileDefPtr file) { + return ToCIdent(file.name()) + "_upb_file_layout"; +} + +std::string CApiHeaderFilename(upb::FileDefPtr file) { + return StripExtension(file.name()) + ".upb.h"; +} + +std::string MiniTableHeaderFilename(upb::FileDefPtr file) { + return StripExtension(file.name()) + ".upb_minitable.h"; +} + +std::string MessageInit(absl::string_view full_name) { + return ToCIdent(full_name) + "_msg_init"; +} + +std::string EnumInit(upb::EnumDefPtr descriptor) { + return ToCIdent(descriptor.full_name()) + "_enum_init"; +} + +std::string FieldInitializer(upb::FieldDefPtr field, + const upb_MiniTableField* field64, + const upb_MiniTableField* field32) { + return absl::Substitute( + "{$0, $1, $2, $3, $4, $5}", field64->number, + ArchDependentSize(field32->offset, field64->offset), + ArchDependentSize(field32->presence, field64->presence), + field64->UPB_PRIVATE(submsg_index) == kUpb_NoSub + ? "kUpb_NoSub" + : absl::StrCat(field64->UPB_PRIVATE(submsg_index)).c_str(), + field64->UPB_PRIVATE(descriptortype), GetModeInit(field32, field64)); +} + +std::string ArchDependentSize(int64_t size32, int64_t size64) { + if (size32 == size64) return absl::StrCat(size32); + return absl::Substitute("UPB_SIZE($0, $1)", size32, size64); +} + +// Returns the field mode as a string initializer. +// +// We could just emit this as a number (and we may yet go in that direction) but +// for now emitting symbolic constants gives this better readability and +// debuggability. +std::string GetModeInit(const upb_MiniTableField* field32, + const upb_MiniTableField* field64) { + std::string ret; + uint8_t mode32 = field32->mode; + switch (mode32 & kUpb_FieldMode_Mask) { + case kUpb_FieldMode_Map: + ret = "(int)kUpb_FieldMode_Map"; + break; + case kUpb_FieldMode_Array: + ret = "(int)kUpb_FieldMode_Array"; + break; + case kUpb_FieldMode_Scalar: + ret = "(int)kUpb_FieldMode_Scalar"; + break; + default: + break; + } + + if (mode32 & kUpb_LabelFlags_IsPacked) { + absl::StrAppend(&ret, " | (int)kUpb_LabelFlags_IsPacked"); + } + + if (mode32 & kUpb_LabelFlags_IsExtension) { + absl::StrAppend(&ret, " | (int)kUpb_LabelFlags_IsExtension"); + } + + if (mode32 & kUpb_LabelFlags_IsAlternate) { + absl::StrAppend(&ret, " | (int)kUpb_LabelFlags_IsAlternate"); + } + + absl::StrAppend(&ret, " | ((int)", GetFieldRep(field32, field64), + " << kUpb_FieldRep_Shift)"); + return ret; +} + +std::string GetFieldRep(const upb_MiniTableField* field32, + const upb_MiniTableField* field64) { + switch (_upb_MiniTableField_GetRep(field32)) { + case kUpb_FieldRep_1Byte: + return "kUpb_FieldRep_1Byte"; + break; + case kUpb_FieldRep_4Byte: { + if (_upb_MiniTableField_GetRep(field64) == kUpb_FieldRep_4Byte) { + return "kUpb_FieldRep_4Byte"; + } else { + assert(_upb_MiniTableField_GetRep(field64) == kUpb_FieldRep_8Byte); + return "UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)"; + } + break; + } + case kUpb_FieldRep_StringView: + return "kUpb_FieldRep_StringView"; + break; + case kUpb_FieldRep_8Byte: + return "kUpb_FieldRep_8Byte"; + break; + } + UPB_UNREACHABLE(); +} + +} // namespace upbc
diff --git a/upbc/common.h b/upbc/common.h new file mode 100644 index 0000000..e607714 --- /dev/null +++ b/upbc/common.h
@@ -0,0 +1,102 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 UPBC_COMMON_H +#define UPBC_COMMON_H + +#include <vector> + +#include "absl/strings/str_replace.h" +#include "absl/strings/substitute.h" +#include "upb/reflection/def.hpp" + +namespace upbc { + +class Output { + public: + template <class... Arg> + void operator()(absl::string_view format, const Arg&... arg) { + Write(absl::Substitute(format, arg...)); + } + + absl::string_view output() const { return output_; } + + 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 != 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; + } + } + absl::StrAppend(&output_, data); + } + + std::string output_; +}; + +std::string StripExtension(absl::string_view fname); +std::string ToCIdent(absl::string_view str); +std::string ToPreproc(absl::string_view str); +void EmitFileWarning(absl::string_view name, Output& output); +std::string MessageName(upb::MessageDefPtr descriptor); +std::string FileLayoutName(upb::FileDefPtr file); +std::string MiniTableHeaderFilename(upb::FileDefPtr file); +std::string CApiHeaderFilename(upb::FileDefPtr file); + +std::string MessageInit(absl::string_view full_name); +std::string EnumInit(upb::EnumDefPtr descriptor); + +std::string FieldInitializer(upb::FieldDefPtr field, + const upb_MiniTableField* field64, + const upb_MiniTableField* field32); +std::string ArchDependentSize(int64_t size32, int64_t size64); +std::string GetModeInit(const upb_MiniTableField* field32, + const upb_MiniTableField* field64); +std::string GetFieldRep(const upb_MiniTableField* field32, + const upb_MiniTableField* field64); + +} // namespace upbc + +#endif // UPBC_COMMON_H
diff --git a/upbc/file_layout.cc b/upbc/file_layout.cc new file mode 100644 index 0000000..fab6120 --- /dev/null +++ b/upbc/file_layout.cc
@@ -0,0 +1,144 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 "upbc/file_layout.h" + +#include <string> +#include <unordered_set> + +#include "upb/mini_table/internal/extension.h" +#include "upbc/common.h" + +namespace upbc { + +const char* kEnumsInit = "enums_layout"; +const char* kExtensionsInit = "extensions_layout"; +const char* kMessagesInit = "messages_layout"; + +void AddEnums(upb::MessageDefPtr message, std::vector<upb::EnumDefPtr>* enums) { + enums->reserve(enums->size() + message.enum_type_count()); + for (int i = 0; i < message.enum_type_count(); i++) { + enums->push_back(message.enum_type(i)); + } + for (int i = 0; i < message.nested_message_count(); i++) { + AddEnums(message.nested_message(i), enums); + } +} + +std::vector<upb::EnumDefPtr> SortedEnums(upb::FileDefPtr file) { + std::vector<upb::EnumDefPtr> enums; + enums.reserve(file.toplevel_enum_count()); + for (int i = 0; i < file.toplevel_enum_count(); i++) { + enums.push_back(file.toplevel_enum(i)); + } + for (int i = 0; i < file.toplevel_message_count(); i++) { + AddEnums(file.toplevel_message(i), &enums); + } + std::sort(enums.begin(), enums.end(), + [](upb::EnumDefPtr a, upb::EnumDefPtr b) { + return strcmp(a.full_name(), b.full_name()) < 0; + }); + return enums; +} + +std::vector<uint32_t> SortedUniqueEnumNumbers(upb::EnumDefPtr e) { + std::vector<uint32_t> values; + values.reserve(e.value_count()); + for (int i = 0; i < e.value_count(); i++) { + values.push_back(static_cast<uint32_t>(e.value(i).number())); + } + std::sort(values.begin(), values.end()); + auto last = std::unique(values.begin(), values.end()); + values.erase(last, values.end()); + return values; +} + +void AddMessages(upb::MessageDefPtr message, + std::vector<upb::MessageDefPtr>* messages) { + messages->push_back(message); + for (int i = 0; i < message.nested_message_count(); i++) { + AddMessages(message.nested_message(i), messages); + } +} + +// Ordering must match upb/def.c! +// +// The ordering is significant because each upb_MessageDef* will point at the +// corresponding upb_MiniTable and we just iterate through the list without +// any search or lookup. +std::vector<upb::MessageDefPtr> SortedMessages(upb::FileDefPtr file) { + std::vector<upb::MessageDefPtr> messages; + for (int i = 0; i < file.toplevel_message_count(); i++) { + AddMessages(file.toplevel_message(i), &messages); + } + return messages; +} + +void AddExtensionsFromMessage(upb::MessageDefPtr message, + std::vector<upb::FieldDefPtr>* exts) { + for (int i = 0; i < message.nested_extension_count(); i++) { + exts->push_back(message.nested_extension(i)); + } + for (int i = 0; i < message.nested_message_count(); i++) { + AddExtensionsFromMessage(message.nested_message(i), exts); + } +} + +// Ordering must match upb/def.c! +// +// The ordering is significant because each upb_FieldDef* will point at the +// corresponding upb_MiniTableExtension and we just iterate through the list +// without any search or lookup. +std::vector<upb::FieldDefPtr> SortedExtensions(upb::FileDefPtr file) { + std::vector<upb::FieldDefPtr> ret; + ret.reserve(file.toplevel_extension_count()); + for (int i = 0; i < file.toplevel_extension_count(); i++) { + ret.push_back(file.toplevel_extension(i)); + } + for (int i = 0; i < file.toplevel_message_count(); i++) { + AddExtensionsFromMessage(file.toplevel_message(i), &ret); + } + return ret; +} + +std::vector<upb::FieldDefPtr> FieldNumberOrder(upb::MessageDefPtr message) { + std::vector<upb::FieldDefPtr> fields; + fields.reserve(message.field_count()); + for (int i = 0; i < message.field_count(); i++) { + fields.push_back(message.field(i)); + } + std::sort(fields.begin(), fields.end(), + [](upb::FieldDefPtr a, upb::FieldDefPtr b) { + return a.number() < b.number(); + }); + return fields; +} + +} // namespace upbc
diff --git a/upbc/file_layout.h b/upbc/file_layout.h new file mode 100644 index 0000000..9df43aa --- /dev/null +++ b/upbc/file_layout.h
@@ -0,0 +1,129 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 UPBC_FILE_LAYOUT_H +#define UPBC_FILE_LAYOUT_H + +#include <string> + +// begin:google_only +// #ifndef UPB_BOOTSTRAP_STAGE0 +// #include "net/proto2/proto/descriptor.upb.h" +// #else +// #include "google/protobuf/descriptor.upb.h" +// #endif +// end:google_only + +// begin:github_only +#include "google/protobuf/descriptor.upb.h" +// end:github_only + +#include "absl/container/flat_hash_map.h" +#include "upb/base/status.hpp" +#include "upb/mini_descriptor/decode.h" +#include "upb/reflection/def.h" +#include "upb/reflection/def.hpp" + +// Must be last +#include "upb/port/def.inc" + +namespace upbc { + +std::vector<upb::EnumDefPtr> SortedEnums(upb::FileDefPtr file); + +// Ordering must match upb/def.c! +// +// The ordering is significant because each upb_MessageDef* will point at the +// corresponding upb_MiniTable and we just iterate through the list without +// any search or lookup. +std::vector<upb::MessageDefPtr> SortedMessages(upb::FileDefPtr file); + +// Ordering must match upb/def.c! +// +// The ordering is significant because each upb_FieldDef* will point at the +// corresponding upb_MiniTableExtension and we just iterate through the list +// without any search or lookup. +std::vector<upb::FieldDefPtr> SortedExtensions(upb::FileDefPtr file); + +std::vector<upb::FieldDefPtr> FieldNumberOrder(upb::MessageDefPtr message); + +// DefPoolPair is a pair of DefPools: one for 32-bit and one for 64-bit. +class DefPoolPair { + public: + DefPoolPair() { + pool32_._SetPlatform(kUpb_MiniTablePlatform_32Bit); + pool64_._SetPlatform(kUpb_MiniTablePlatform_64Bit); + } + + upb::FileDefPtr AddFile(const UPB_DESC(FileDescriptorProto) * file_proto, + upb::Status* status) { + upb::FileDefPtr file32 = pool32_.AddFile(file_proto, status); + upb::FileDefPtr file64 = pool64_.AddFile(file_proto, status); + if (!file32) return file32; + return file64; + } + + const upb_MiniTable* GetMiniTable32(upb::MessageDefPtr m) const { + return pool32_.FindMessageByName(m.full_name()).mini_table(); + } + + const upb_MiniTable* GetMiniTable64(upb::MessageDefPtr m) const { + return pool64_.FindMessageByName(m.full_name()).mini_table(); + } + + const upb_MiniTableField* GetField32(upb::FieldDefPtr f) const { + return GetFieldFromPool(&pool32_, f); + } + + const upb_MiniTableField* GetField64(upb::FieldDefPtr f) const { + return GetFieldFromPool(&pool64_, f); + } + + private: + static const upb_MiniTableField* GetFieldFromPool(const upb::DefPool* pool, + upb::FieldDefPtr f) { + if (f.is_extension()) { + return pool->FindExtensionByName(f.full_name()).mini_table(); + } else { + return pool->FindMessageByName(f.containing_type().full_name()) + .FindFieldByNumber(f.number()) + .mini_table(); + } + } + + upb::DefPool pool32_; + upb::DefPool pool64_; +}; + +} // namespace upbc + +#include "upb/port/undef.inc" + +#endif // UPBC_FILE_LAYOUT_H
diff --git a/upbc/get_used_fields.c b/upbc/get_used_fields.c new file mode 100644 index 0000000..796e501 --- /dev/null +++ b/upbc/get_used_fields.c
@@ -0,0 +1,143 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 "upbc/get_used_fields.h" + +#include "google/protobuf/descriptor.upb.h" +#include "google/protobuf/compiler/plugin.upb.h" +#include "upb/reflection/def_pool.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/message.h" +#include "upb/reflection/message_def.h" +#include "upb/wire/decode.h" + +// Must be last. +#include "upb/port/def.inc" + +#define upbdev_Err(...) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + exit(1); \ + } + +typedef struct { + char* buf; + size_t size; + size_t capacity; + upb_Arena* arena; +} upbdev_StringBuf; + +void upbdev_StringBuf_Add(upbdev_StringBuf* buf, const char* sym) { + size_t len = strlen(sym); + size_t need = buf->size + len + (buf->size != 0); + if (need > buf->capacity) { + size_t new_cap = UPB_MAX(buf->capacity, 32); + while (need > new_cap) new_cap *= 2; + buf->buf = upb_Arena_Realloc(buf->arena, buf->buf, buf->capacity, new_cap); + buf->capacity = new_cap; + } + if (buf->size != 0) { + buf->buf[buf->size++] = '\n'; // Separator + } + memcpy(buf->buf + buf->size, sym, len); + buf->size = need; +} + +void upbdev_VisitMessage(upbdev_StringBuf* buf, const upb_Message* msg, + const upb_MessageDef* m) { + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + while (upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + // This could be a duplicate, but we don't worry about it; we'll dedupe + // one level up. + upbdev_StringBuf_Add(buf, upb_FieldDef_FullName(f)); + + if (upb_FieldDef_CType(f) != kUpb_CType_Message) continue; + const upb_MessageDef* sub = upb_FieldDef_MessageSubDef(f); + + if (upb_FieldDef_IsMap(f)) { + const upb_Map* map = val.map_val; + size_t iter = kUpb_Map_Begin; + upb_MessageValue map_key, map_val; + while (upb_Map_Next(map, &map_key, &map_val, &iter)) { + upbdev_VisitMessage(buf, map_val.msg_val, sub); + } + } else if (upb_FieldDef_IsRepeated(f)) { + const upb_Array* arr = val.array_val; + size_t n = upb_Array_Size(arr); + for (size_t i = 0; i < n; i++) { + upb_MessageValue val = upb_Array_Get(arr, i); + upbdev_VisitMessage(buf, val.msg_val, sub); + } + } else { + upbdev_VisitMessage(buf, val.msg_val, sub); + } + } +} + +upb_StringView upbdev_GetUsedFields(const char* request, size_t request_size, + const char* payload, size_t payload_size, + const char* message_name, + upb_Arena* arena) { + upb_Arena* tmp_arena = upb_Arena_New(); + google_protobuf_compiler_CodeGeneratorRequest* request_proto = + google_protobuf_compiler_CodeGeneratorRequest_parse(request, request_size, + tmp_arena); + if (!request_proto) upbdev_Err("Couldn't parse request proto\n"); + + size_t len; + const google_protobuf_FileDescriptorProto* const* files = + google_protobuf_compiler_CodeGeneratorRequest_proto_file(request_proto, &len); + + upb_DefPool* pool = upb_DefPool_New(); + for (size_t i = 0; i < len; i++) { + const upb_FileDef* f = upb_DefPool_AddFile(pool, files[i], NULL); + if (!f) upbdev_Err("could not add file to def pool\n"); + } + + const upb_MessageDef* m = upb_DefPool_FindMessageByName(pool, message_name); + if (!m) upbdev_Err("Couldn't find message name\n"); + + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(mt, tmp_arena); + upb_DecodeStatus st = + upb_Decode(payload, payload_size, msg, mt, NULL, 0, tmp_arena); + if (st != kUpb_DecodeStatus_Ok) upbdev_Err("Error parsing payload: %d\n", st); + + upbdev_StringBuf buf = { + .buf = NULL, + .size = 0, + .capacity = 0, + .arena = arena, + }; + upbdev_VisitMessage(&buf, msg, m); + return upb_StringView_FromDataAndSize(buf.buf, buf.size); +}
diff --git a/upbc/get_used_fields.h b/upbc/get_used_fields.h new file mode 100644 index 0000000..ccf3208 --- /dev/null +++ b/upbc/get_used_fields.h
@@ -0,0 +1,57 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 UPBC_GET_USED_FIELDS +#define UPBC_GET_USED_FIELDS + +#include "upb/base/status.h" +#include "upb/base/string_view.h" +#include "upb/mem/arena.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +// Consume |buf|, deserialize it to a Code_Generator_Request proto, then +// upbc_Code_Generator_Request, and return it as a JSON-encoded string. +UPB_API upb_StringView upbdev_GetUsedFields( + const char* request, size_t request_size, const char* payload, + size_t payload_size, const char* message_name, upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif // UPBC_GET_USED_FIELDS
diff --git a/upbc/keywords.cc b/upbc/keywords.cc new file mode 100644 index 0000000..3f51705 --- /dev/null +++ b/upbc/keywords.cc
@@ -0,0 +1,152 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 "upbc/keywords.h" + +#include <string> +#include <unordered_set> + +namespace upbc { + +static const char* const kKeywordList[] = { + // + "NULL", + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "class", + "compl", + "const", + "constexpr", + "const_cast", + "continue", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + "char8_t", + "char16_t", + "char32_t", + "concept", + "consteval", + "constinit", + "co_await", + "co_return", + "co_yield", + "requires", +}; + +static std::unordered_set<std::string>* MakeKeywordsMap() { + auto* result = new std::unordered_set<std::string>(); + for (const auto keyword : kKeywordList) { + result->emplace(keyword); + } + return result; +} + +static std::unordered_set<std::string>& kKeywords = *MakeKeywordsMap(); + +std::string ResolveKeywordConflict(const std::string& name) { + if (kKeywords.count(name) > 0) { + return name + "_"; + } + return name; +} + +} // namespace upbc
diff --git a/upbc/keywords.h b/upbc/keywords.h new file mode 100644 index 0000000..6638f99 --- /dev/null +++ b/upbc/keywords.h
@@ -0,0 +1,43 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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_KEYWORDS_H +#define UPB_PROTOS_GENERATOR_KEYWORDS_H + +#include <string> + +namespace upbc { + +// Resolves proto field name conflict with C++ reserved keywords. +std::string ResolveKeywordConflict(const std::string& name); + +} // namespace upbc + +#endif // UPB_PROTOS_GENERATOR_KEYWORDS_H
diff --git a/upbc/names.cc b/upbc/names.cc new file mode 100644 index 0000000..63521b8 --- /dev/null +++ b/upbc/names.cc
@@ -0,0 +1,132 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 "upbc/names.h" + +#include <string> + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/descriptor.h" +#include "upb/reflection/def.hpp" + +namespace upbc { + +namespace protobuf = ::google::protobuf; + +// Prefixes used by C code generator for field access. +static constexpr absl::string_view kClearMethodPrefix = "clear_"; +static constexpr absl::string_view kSetMethodPrefix = "set_"; +static constexpr absl::string_view kHasMethodPrefix = "has_"; +static constexpr absl::string_view kDeleteMethodPrefix = "delete_"; +static constexpr absl::string_view kAddToRepeatedMethodPrefix = "add_"; +static constexpr absl::string_view kResizeArrayMethodPrefix = "resize_"; + +ABSL_CONST_INIT const absl::string_view kRepeatedFieldArrayGetterPostfix = + "upb_array"; +ABSL_CONST_INIT const absl::string_view + kRepeatedFieldMutableArrayGetterPostfix = "mutable_upb_array"; + +// 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[] = { + kClearMethodPrefix, kDeleteMethodPrefix, kAddToRepeatedMethodPrefix, + kResizeArrayMethodPrefix, kSetMethodPrefix, kHasMethodPrefix}; + +std::string ResolveFieldName(const protobuf::FieldDescriptor* field, + const NameToFieldDescriptorMap& field_names) { + absl::string_view field_name = 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() || + (candidate->cpp_type() == + protobuf::FieldDescriptor::CPPTYPE_STRING && + prefix == kClearMethodPrefix) || + prefix == kSetMethodPrefix || prefix == kHasMethodPrefix) { + return absl::StrCat(field_name, "_"); + } + } + } + } + return std::string(field_name); +} + +// Returns field map by name to use for conflict checks. +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; +} + +NameToFieldDefMap CreateFieldNameMap(upb::MessageDefPtr message) { + NameToFieldDefMap field_names; + field_names.reserve(message.field_count()); + for (const auto& field : message.fields()) { + field_names.emplace(field.name(), field); + } + return field_names; +} + +std::string ResolveFieldName(upb::FieldDefPtr field, + const NameToFieldDefMap& field_names) { + absl::string_view field_name(field.name()); + for (absl::string_view 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.IsSequence() || candidate.IsMap() || + (candidate.ctype() == kUpb_CType_String && + prefix == kClearMethodPrefix) || + prefix == kSetMethodPrefix || prefix == kHasMethodPrefix) { + return absl::StrCat(field_name, "_"); + } + } + } + } + return std::string(field_name); +} + +} // namespace upbc
diff --git a/upbc/names.h b/upbc/names.h new file mode 100644 index 0000000..87b0a15 --- /dev/null +++ b/upbc/names.h
@@ -0,0 +1,73 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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_NAMES_H +#define UPB_PROTOS_GENERATOR_NAMES_H + +#include <string> + +#include "absl/base/attributes.h" +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/descriptor.h" +#include "upb/reflection/def.hpp" + +namespace upbc { + +using NameToFieldDescriptorMap = + absl::flat_hash_map<absl::string_view, const google::protobuf::FieldDescriptor*>; + +// Returns field name by resolving naming conflicts across +// proto field names (such as clear_ prefixes). +std::string ResolveFieldName(const google::protobuf::FieldDescriptor* field, + const NameToFieldDescriptorMap& field_names); + +// Returns field map by name to use for conflict checks. +NameToFieldDescriptorMap CreateFieldNameMap(const google::protobuf::Descriptor* message); + +using NameToFieldDefMap = + absl::flat_hash_map<absl::string_view, upb::FieldDefPtr>; + +// Returns field name by resolving naming conflicts across +// proto field names (such as clear_ prefixes). +std::string ResolveFieldName(upb::FieldDefPtr field, + const NameToFieldDefMap& field_names); + +// Returns field map by name to use for conflict checks. +NameToFieldDefMap CreateFieldNameMap(upb::MessageDefPtr message); + +// Private array getter name postfix for repeated fields. +ABSL_CONST_INIT extern const absl::string_view kRepeatedFieldArrayGetterPostfix; +ABSL_CONST_INIT extern const absl::string_view + kRepeatedFieldMutableArrayGetterPostfix; + +} // namespace upbc + +#endif // UPB_PROTOS_GENERATOR_NAMES_H
diff --git a/upbc/plugin.h b/upbc/plugin.h new file mode 100644 index 0000000..465bda0 --- /dev/null +++ b/upbc/plugin.h
@@ -0,0 +1,212 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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_UPBC_PLUGIN_H_ +#define UPB_UPBC_PLUGIN_H_ + +#include <stdio.h> + +#include <string> +#include <vector> +#ifdef _WIN32 +#include <fcntl.h> +#include <io.h> +#endif + +// begin:google_only +// #ifndef UPB_BOOTSTRAP_STAGE0 +// #include "net/proto2/proto/descriptor.upb.h" +// #include "third_party/protobuf/compiler/plugin.upb.h" +// #else +// #include "google/protobuf/compiler/plugin.upb.h" +// #include "google/protobuf/descriptor.upb.h" +// #endif +// end:google_only + +// begin:github_only +#include "google/protobuf/compiler/plugin.upb.h" +#include "google/protobuf/descriptor.upb.h" +// end:github_only + +#include "absl/container/flat_hash_set.h" +#include "absl/log/absl_log.h" +#include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" +#include "upb/reflection/def.hpp" + +// Must be last. +#include "upb/port/def.inc" + +namespace upbc { + +inline std::vector<std::pair<std::string, std::string>> ParseGeneratorParameter( + const absl::string_view text) { + std::vector<std::pair<std::string, std::string>> ret; + for (absl::string_view sp : absl::StrSplit(text, ',', absl::SkipEmpty())) { + std::string::size_type equals_pos = sp.find_first_of('='); + std::pair<std::string, std::string> value; + if (equals_pos == std::string::npos) { + value.first = std::string(sp); + } else { + value.first = std::string(sp.substr(0, equals_pos)); + value.second = std::string(sp.substr(equals_pos + 1)); + } + ret.push_back(std::move(value)); + } + return ret; +} + +class Plugin { + public: + Plugin() { ReadRequest(); } + ~Plugin() { WriteResponse(); } + + absl::string_view parameter() const { + return ToStringView( + UPB_DESC(compiler_CodeGeneratorRequest_parameter)(request_)); + } + + template <class T> + void GenerateFilesRaw(T&& func) { + absl::flat_hash_set<absl::string_view> files_to_generate; + size_t size; + const upb_StringView* file_to_generate = UPB_DESC( + compiler_CodeGeneratorRequest_file_to_generate)(request_, &size); + for (size_t i = 0; i < size; i++) { + files_to_generate.insert( + {file_to_generate[i].data, file_to_generate[i].size}); + } + + const UPB_DESC(FileDescriptorProto)* const* files = + UPB_DESC(compiler_CodeGeneratorRequest_proto_file)(request_, &size); + for (size_t i = 0; i < size; i++) { + upb::Status status; + absl::string_view name = + ToStringView(UPB_DESC(FileDescriptorProto_name)(files[i])); + func(files[i], files_to_generate.contains(name)); + } + } + + template <class T> + void GenerateFiles(T&& func) { + GenerateFilesRaw( + [this, &func](const UPB_DESC(FileDescriptorProto) * file_proto, + bool generate) { + upb::Status status; + upb::FileDefPtr file = pool_.AddFile(file_proto, &status); + if (!file) { + absl::string_view name = + ToStringView(UPB_DESC(FileDescriptorProto_name)(file_proto)); + ABSL_LOG(FATAL) << "Couldn't add file " << name + << " to DefPool: " << status.error_message(); + } + if (generate) func(file); + }); + } + + void SetError(absl::string_view error) { + char* data = + static_cast<char*>(upb_Arena_Malloc(arena_.ptr(), error.size())); + memcpy(data, error.data(), error.size()); + UPB_DESC(compiler_CodeGeneratorResponse_set_error) + (response_, upb_StringView_FromDataAndSize(data, error.size())); + } + + void AddOutputFile(absl::string_view filename, absl::string_view content) { + UPB_DESC(compiler_CodeGeneratorResponse_File)* file = UPB_DESC( + compiler_CodeGeneratorResponse_add_file)(response_, arena_.ptr()); + UPB_DESC(compiler_CodeGeneratorResponse_File_set_name) + (file, StringDup(filename)); + UPB_DESC(compiler_CodeGeneratorResponse_File_set_content) + (file, StringDup(content)); + } + + private: + upb::Arena arena_; + upb::DefPool pool_; + UPB_DESC(compiler_CodeGeneratorRequest) * request_; + UPB_DESC(compiler_CodeGeneratorResponse) * response_; + + static absl::string_view ToStringView(upb_StringView sv) { + return absl::string_view(sv.data, sv.size); + } + + upb_StringView StringDup(absl::string_view s) { + char* data = + reinterpret_cast<char*>(upb_Arena_Malloc(arena_.ptr(), s.size())); + memcpy(data, s.data(), s.size()); + return upb_StringView_FromDataAndSize(data, s.size()); + } + + std::string ReadAllStdinBinary() { + std::string data; +#ifdef _WIN32 + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); +#endif + char buf[4096]; + while (size_t len = fread(buf, 1, sizeof(buf), stdin)) { + data.append(buf, len); + } + return data; + } + + void ReadRequest() { + std::string data = ReadAllStdinBinary(); + request_ = UPB_DESC(compiler_CodeGeneratorRequest_parse)( + data.data(), data.size(), arena_.ptr()); + if (!request_) { + ABSL_LOG(FATAL) << "Failed to parse CodeGeneratorRequest"; + } + response_ = UPB_DESC(compiler_CodeGeneratorResponse_new)(arena_.ptr()); + UPB_DESC(compiler_CodeGeneratorResponse_set_supported_features) + (response_, + UPB_DESC(compiler_CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)); + } + + void WriteResponse() { + size_t size; + char* serialized = UPB_DESC(compiler_CodeGeneratorResponse_serialize)( + response_, arena_.ptr(), &size); + if (!serialized) { + ABSL_LOG(FATAL) << "Failed to serialize CodeGeneratorResponse"; + } + + if (fwrite(serialized, 1, size, stdout) != size) { + ABSL_LOG(FATAL) << "Failed to write response to stdout"; + } + } +}; + +} // namespace upbc + +#include "upb/port/undef.inc" + +#endif // UPB_UPBC_PLUGIN_H_
diff --git a/upbc/protoc-gen-upb.cc b/upbc/protoc-gen-upb.cc new file mode 100644 index 0000000..0fa716a --- /dev/null +++ b/upbc/protoc-gen-upb.cc
@@ -0,0 +1,1154 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 <algorithm> +#include <cmath> +#include <cstddef> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <limits> +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/log/absl_check.h" +#include "absl/log/absl_log.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "upb/base/descriptor_constants.h" +#include "upb/base/string_view.h" +#include "upb/reflection/def.hpp" +#include "upb/wire/types.h" +#include "upbc/common.h" +#include "upbc/file_layout.h" +#include "upbc/names.h" +#include "upbc/plugin.h" + +// Must be last. +#include "upb/port/def.inc" + +namespace upbc { +namespace { + +struct Options { + bool bootstrap = false; +}; + +std::string SourceFilename(upb::FileDefPtr file) { + return StripExtension(file.name()) + ".upb.c"; +} + +std::string MessageInitName(upb::MessageDefPtr descriptor) { + return absl::StrCat(MessageName(descriptor), "_msg_init"); +} + +std::string MessageMiniTableRef(upb::MessageDefPtr descriptor, + const Options& options) { + if (options.bootstrap) { + return absl::StrCat(MessageInitName(descriptor), "()"); + } else { + return absl::StrCat("&", MessageInitName(descriptor)); + } +} + +std::string EnumInitName(upb::EnumDefPtr descriptor) { + return ToCIdent(descriptor.full_name()) + "_enum_init"; +} + +std::string EnumMiniTableRef(upb::EnumDefPtr descriptor, + const Options& options) { + if (options.bootstrap) { + return absl::StrCat(EnumInitName(descriptor), "()"); + } else { + return absl::StrCat("&", EnumInitName(descriptor)); + } +} + +std::string ExtensionIdentBase(upb::FieldDefPtr 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 ExtensionLayout(upb::FieldDefPtr ext) { + return absl::StrCat(ExtensionIdentBase(ext), "_", ext.name(), "_ext"); +} + +std::string EnumValueSymbol(upb::EnumValDefPtr value) { + return ToCIdent(value.full_name()); +} + +std::string CTypeInternal(upb::FieldDefPtr field, bool is_const) { + std::string maybe_const = is_const ? "const " : ""; + switch (field.ctype()) { + case kUpb_CType_Message: { + std::string maybe_struct = + field.file() != field.message_type().file() ? "struct " : ""; + return maybe_const + maybe_struct + MessageName(field.message_type()) + + "*"; + } + case kUpb_CType_Bool: + return "bool"; + case kUpb_CType_Float: + return "float"; + case kUpb_CType_Int32: + case kUpb_CType_Enum: + return "int32_t"; + case kUpb_CType_UInt32: + return "uint32_t"; + case kUpb_CType_Double: + return "double"; + case kUpb_CType_Int64: + return "int64_t"; + case kUpb_CType_UInt64: + return "uint64_t"; + case kUpb_CType_String: + case kUpb_CType_Bytes: + return "upb_StringView"; + default: + abort(); + } +} + +std::string FloatToCLiteral(float value) { + if (value == std::numeric_limits<float>::infinity()) { + return "kUpb_FltInfinity"; + } else if (value == -std::numeric_limits<float>::infinity()) { + return "-kUpb_FltInfinity"; + } else if (std::isnan(value)) { + return "kUpb_NaN"; + } else { + return absl::StrCat(value); + } +} + +std::string DoubleToCLiteral(double value) { + if (value == std::numeric_limits<double>::infinity()) { + return "kUpb_Infinity"; + } else if (value == -std::numeric_limits<double>::infinity()) { + return "-kUpb_Infinity"; + } else if (std::isnan(value)) { + return "kUpb_NaN"; + } else { + return absl::StrCat(value); + } +} + +// Escape trigraphs by escaping question marks to \? +std::string EscapeTrigraphs(absl::string_view to_escape) { + return absl::StrReplaceAll(to_escape, {{"?", "\\?"}}); +} + +std::string FieldDefault(upb::FieldDefPtr field) { + switch (field.ctype()) { + case kUpb_CType_Message: + return "NULL"; + case kUpb_CType_Bytes: + case kUpb_CType_String: { + upb_StringView str = field.default_value().str_val; + return absl::Substitute("upb_StringView_FromString(\"$0\")", + EscapeTrigraphs(absl::CEscape( + absl::string_view(str.data, str.size)))); + } + case kUpb_CType_Int32: + return absl::Substitute("(int32_t)$0", field.default_value().int32_val); + case kUpb_CType_Int64: + if (field.default_value().int64_val == INT64_MIN) { + // Special-case to avoid: + // integer literal is too large to be represented in a signed integer + // type, interpreting as unsigned + // [-Werror,-Wimplicitly-unsigned-literal] + // int64_t default_val = (int64_t)-9223372036854775808ll; + // + // More info here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661 + return "INT64_MIN"; + } else { + return absl::Substitute("(int64_t)$0ll", + field.default_value().int64_val); + } + case kUpb_CType_UInt32: + return absl::Substitute("(uint32_t)$0u", + field.default_value().uint32_val); + case kUpb_CType_UInt64: + return absl::Substitute("(uint64_t)$0ull", + field.default_value().uint64_val); + case kUpb_CType_Float: + return FloatToCLiteral(field.default_value().float_val); + case kUpb_CType_Double: + return DoubleToCLiteral(field.default_value().double_val); + case kUpb_CType_Bool: + return field.default_value().bool_val ? "true" : "false"; + case kUpb_CType_Enum: + // Use a number instead of a symbolic name so that we don't require + // this enum's header to be included. + return absl::StrCat(field.default_value().int32_val); + } + ABSL_ASSERT(false); + return "XXX"; +} + +std::string CType(upb::FieldDefPtr field) { + return CTypeInternal(field, false); +} + +std::string CTypeConst(upb::FieldDefPtr field) { + return CTypeInternal(field, true); +} + +std::string MapKeyCType(upb::FieldDefPtr map_field) { + return CType(map_field.message_type().map_key()); +} + +std::string MapValueCType(upb::FieldDefPtr map_field) { + return CType(map_field.message_type().map_value()); +} + +std::string MapKeySize(upb::FieldDefPtr map_field, absl::string_view expr) { + return map_field.message_type().map_key().ctype() == kUpb_CType_String + ? "0" + : absl::StrCat("sizeof(", expr, ")"); +} + +std::string MapValueSize(upb::FieldDefPtr map_field, absl::string_view expr) { + return map_field.message_type().map_value().ctype() == kUpb_CType_String + ? "0" + : absl::StrCat("sizeof(", expr, ")"); +} + +std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field, + const Options& options); + +void DumpEnumValues(upb::EnumDefPtr desc, Output& output) { + std::vector<upb::EnumValDefPtr> values; + values.reserve(desc.value_count()); + for (int i = 0; i < desc.value_count(); i++) { + values.push_back(desc.value(i)); + } + std::sort(values.begin(), values.end(), + [](upb::EnumValDefPtr a, upb::EnumValDefPtr b) { + return a.number() < b.number(); + }); + + for (size_t i = 0; i < values.size(); i++) { + auto value = values[i]; + output(" $0 = $1", EnumValueSymbol(value), value.number()); + if (i != values.size() - 1) { + output(","); + } + output("\n"); + } +} + +std::string GetFieldRep(const DefPoolPair& pools, upb::FieldDefPtr field) { + return upbc::GetFieldRep(pools.GetField32(field), pools.GetField64(field)); +} + +void GenerateExtensionInHeader(const DefPoolPair& pools, upb::FieldDefPtr ext, + Output& output) { + output( + R"cc( + UPB_INLINE bool $0_has_$1(const struct $2* msg) { + return _upb_Message_HasExtensionField(msg, &$3); + } + )cc", + ExtensionIdentBase(ext), ext.name(), MessageName(ext.containing_type()), + ExtensionLayout(ext)); + + output( + R"cc( + UPB_INLINE void $0_clear_$1(struct $2* msg) { + _upb_Message_ClearExtensionField(msg, &$3); + } + )cc", + ExtensionIdentBase(ext), ext.name(), MessageName(ext.containing_type()), + ExtensionLayout(ext)); + + if (ext.IsSequence()) { + // TODO: We need generated accessors for repeated extensions. + } else { + output( + R"cc( + UPB_INLINE $0 $1_$2(const struct $3* msg) { + const upb_MiniTableExtension* ext = &$4; + UPB_ASSUME(!upb_IsRepeatedOrMap(&ext->field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(&ext->field) == $5); + $0 default_val = $6; + $0 ret; + _upb_Message_GetExtensionField(msg, ext, &default_val, &ret); + return ret; + } + )cc", + CTypeConst(ext), ExtensionIdentBase(ext), ext.name(), + MessageName(ext.containing_type()), ExtensionLayout(ext), + GetFieldRep(pools, ext), FieldDefault(ext)); + output( + R"cc( + UPB_INLINE void $1_set_$2(struct $3* msg, $0 val, upb_Arena* arena) { + const upb_MiniTableExtension* ext = &$4; + UPB_ASSUME(!upb_IsRepeatedOrMap(&ext->field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(&ext->field) == $5); + bool ok = _upb_Message_SetExtensionField(msg, ext, &val, arena); + UPB_ASSERT(ok); + } + )cc", + CTypeConst(ext), ExtensionIdentBase(ext), ext.name(), + MessageName(ext.containing_type()), ExtensionLayout(ext), + GetFieldRep(pools, ext)); + } +} + +void GenerateMessageFunctionsInHeader(upb::MessageDefPtr message, + const Options& options, Output& output) { + // TODO: The generated code here does not check the return values + // from upb_Encode(). How can we even fix this without breaking other things? + output( + R"cc( + UPB_INLINE $0* $0_new(upb_Arena* arena) { + return ($0*)_upb_Message_New($1, arena); + } + UPB_INLINE $0* $0_parse(const char* buf, size_t size, upb_Arena* arena) { + $0* ret = $0_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, $1, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; + } + UPB_INLINE $0* $0_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + $0* ret = $0_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, $1, extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; + } + UPB_INLINE char* $0_serialize(const $0* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, $1, 0, arena, &ptr, len); + return ptr; + } + UPB_INLINE char* $0_serialize_ex(const $0* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, $1, options, arena, &ptr, len); + return ptr; + } + )cc", + MessageName(message), MessageMiniTableRef(message, options)); +} + +void GenerateOneofInHeader(upb::OneofDefPtr oneof, const DefPoolPair& pools, + absl::string_view msg_name, const Options& options, + Output& output) { + std::string fullname = ToCIdent(oneof.full_name()); + output("typedef enum {\n"); + for (int j = 0; j < oneof.field_count(); j++) { + upb::FieldDefPtr field = oneof.field(j); + output(" $0_$1 = $2,\n", fullname, field.name(), field.number()); + } + output( + " $0_NOT_SET = 0\n" + "} $0_oneofcases;\n", + fullname); + output( + R"cc( + UPB_INLINE $0_oneofcases $1_$2_case(const $1* msg) { + const upb_MiniTableField field = $3; + return ($0_oneofcases)upb_Message_WhichOneofFieldNumber(msg, &field); + } + )cc", + fullname, msg_name, oneof.name(), + FieldInitializer(pools, oneof.field(0), options)); +} + +void GenerateHazzer(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + std::string resolved_name = ResolveFieldName(field, field_names); + if (field.has_presence()) { + output( + R"cc( + UPB_INLINE bool $0_has_$1(const $0* msg) { + const upb_MiniTableField field = $2; + return _upb_Message_HasNonExtensionField(msg, &field); + } + )cc", + msg_name, resolved_name, FieldInitializer(pools, field, options)); + } else if (field.IsMap()) { + // Do nothing. + } else if (field.IsSequence()) { + // TODO: remove. + output( + R"cc( + UPB_INLINE bool $0_has_$1(const $0* msg) { + size_t size; + $0_$1(msg, &size); + return size != 0; + } + )cc", + msg_name, resolved_name); + } +} + +void GenerateClear(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, const Options& options, + Output& output) { + if (field == field.containing_type().map_key() || + field == field.containing_type().map_value()) { + // Cannot be cleared. + return; + } + std::string resolved_name = ResolveFieldName(field, field_names); + output( + R"cc( + UPB_INLINE void $0_clear_$1($0* msg) { + const upb_MiniTableField field = $2; + _upb_Message_ClearNonExtensionField(msg, &field); + } + )cc", + msg_name, resolved_name, FieldInitializer(pools, field, options)); +} + +void GenerateMapGetters(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + std::string resolved_name = ResolveFieldName(field, field_names); + output( + R"cc( + UPB_INLINE size_t $0_$1_size(const $0* msg) { + const upb_MiniTableField field = $2; + const upb_Map* map = upb_Message_GetMap(msg, &field); + return map ? _upb_Map_Size(map) : 0; + } + )cc", + msg_name, resolved_name, FieldInitializer(pools, field, options)); + output( + R"cc( + UPB_INLINE bool $0_$1_get(const $0* msg, $2 key, $3* val) { + const upb_MiniTableField field = $4; + const upb_Map* map = upb_Message_GetMap(msg, &field); + if (!map) return false; + return _upb_Map_Get(map, &key, $5, val, $6); + } + )cc", + msg_name, resolved_name, MapKeyCType(field), MapValueCType(field), + FieldInitializer(pools, field, options), MapKeySize(field, "key"), + MapValueSize(field, "*val")); + output( + R"cc( + UPB_INLINE $0 $1_$2_next(const $1* msg, size_t* iter) { + const upb_MiniTableField field = $3; + const upb_Map* map = upb_Message_GetMap(msg, &field); + if (!map) return NULL; + return ($0)_upb_map_next(map, iter); + } + )cc", + CTypeConst(field), msg_name, resolved_name, + FieldInitializer(pools, field, options)); +} + +void GenerateMapEntryGetters(upb::FieldDefPtr field, absl::string_view msg_name, + Output& output) { + output( + R"cc( + UPB_INLINE $0 $1_$2(const $1* msg) { + $3 ret; + _upb_msg_map_$2(msg, &ret, $4); + return ret; + } + )cc", + CTypeConst(field), msg_name, field.name(), CType(field), + field.ctype() == kUpb_CType_String ? "0" : "sizeof(ret)"); +} + +void GenerateRepeatedGetters(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + // Generate getter returning first item and size. + // + // Example: + // UPB_INLINE const struct Bar* const* name(const Foo* msg, size_t* size) + output( + R"cc( + UPB_INLINE $0 const* $1_$2(const $1* msg, size_t* size) { + const upb_MiniTableField field = $3; + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return ($0 const*)_upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } + } + )cc", + CTypeConst(field), // $0 + msg_name, // $1 + ResolveFieldName(field, field_names), // $2 + FieldInitializer(pools, field, options) // #3 + ); + // Generate private getter returning array or NULL for immutable and upb_Array + // for mutable. + // + // Example: + // UPB_INLINE const upb_Array* _name_upbarray(size_t* size) + // UPB_INLINE upb_Array* _name_mutable_upbarray(size_t* size) + output( + R"cc( + UPB_INLINE const upb_Array* _$1_$2_$4(const $1* msg, size_t* size) { + const upb_MiniTableField field = $3; + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; + } + UPB_INLINE upb_Array* _$1_$2_$5(const $1* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = $3; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + (upb_Message*)msg, &field, arena); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; + } + )cc", + CTypeConst(field), // $0 + msg_name, // $1 + ResolveFieldName(field, field_names), // $2 + FieldInitializer(pools, field, options), // $3 + kRepeatedFieldArrayGetterPostfix, // $4 + kRepeatedFieldMutableArrayGetterPostfix // $5 + ); +} + +void GenerateScalarGetters(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& Options, Output& output) { + std::string field_name = ResolveFieldName(field, field_names); + output( + R"cc( + UPB_INLINE $0 $1_$2(const $1* msg) { + $0 default_val = $3; + $0 ret; + const upb_MiniTableField field = $4; + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; + } + )cc", + CTypeConst(field), msg_name, field_name, FieldDefault(field), + FieldInitializer(pools, field, Options)); +} + +void GenerateGetters(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + if (field.IsMap()) { + GenerateMapGetters(field, pools, msg_name, field_names, options, output); + } else if (UPB_DESC(MessageOptions_map_entry)( + field.containing_type().options())) { + GenerateMapEntryGetters(field, msg_name, output); + } else if (field.IsSequence()) { + GenerateRepeatedGetters(field, pools, msg_name, field_names, options, + output); + } else { + GenerateScalarGetters(field, pools, msg_name, field_names, options, output); + } +} + +void GenerateMapSetters(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + std::string resolved_name = ResolveFieldName(field, field_names); + output( + R"cc( + UPB_INLINE void $0_$1_clear($0* msg) { + const upb_MiniTableField field = $2; + upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field); + if (!map) return; + _upb_Map_Clear(map); + } + )cc", + msg_name, resolved_name, FieldInitializer(pools, field, options)); + output( + R"cc( + UPB_INLINE bool $0_$1_set($0* msg, $2 key, $3 val, upb_Arena* a) { + const upb_MiniTableField field = $4; + upb_Map* map = _upb_Message_GetOrCreateMutableMap(msg, &field, $5, $6, a); + return _upb_Map_Insert(map, &key, $5, &val, $6, a) != + kUpb_MapInsertStatus_OutOfMemory; + } + )cc", + msg_name, resolved_name, MapKeyCType(field), MapValueCType(field), + FieldInitializer(pools, field, options), MapKeySize(field, "key"), + MapValueSize(field, "val")); + output( + R"cc( + UPB_INLINE bool $0_$1_delete($0* msg, $2 key) { + const upb_MiniTableField field = $3; + upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field); + if (!map) return false; + return _upb_Map_Delete(map, &key, $4, NULL); + } + )cc", + msg_name, resolved_name, MapKeyCType(field), + FieldInitializer(pools, field, options), MapKeySize(field, "key")); + output( + R"cc( + UPB_INLINE $0 $1_$2_nextmutable($1* msg, size_t* iter) { + const upb_MiniTableField field = $3; + upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field); + if (!map) return NULL; + return ($0)_upb_map_next(map, iter); + } + )cc", + CType(field), msg_name, resolved_name, + FieldInitializer(pools, field, options)); +} + +void GenerateRepeatedSetters(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + std::string resolved_name = ResolveFieldName(field, field_names); + output( + R"cc( + UPB_INLINE $0* $1_mutable_$2($1* msg, size_t* size) { + upb_MiniTableField field = $3; + upb_Array* arr = upb_Message_GetMutableArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return ($0*)_upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } + } + )cc", + CType(field), msg_name, resolved_name, + FieldInitializer(pools, field, options)); + output( + R"cc( + UPB_INLINE $0* $1_resize_$2($1* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = $3; + return ($0*)upb_Message_ResizeArrayUninitialized(msg, &field, size, arena); + } + )cc", + CType(field), msg_name, resolved_name, + FieldInitializer(pools, field, options)); + if (field.ctype() == kUpb_CType_Message) { + output( + R"cc( + UPB_INLINE struct $0* $1_add_$2($1* msg, upb_Arena* arena) { + upb_MiniTableField field = $4; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena); + if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) { + return NULL; + } + struct $0* sub = (struct $0*)_upb_Message_New($3, arena); + if (!arr || !sub) return NULL; + _upb_Array_Set(arr, arr->size - 1, &sub, sizeof(sub)); + return sub; + } + )cc", + MessageName(field.message_type()), msg_name, resolved_name, + MessageMiniTableRef(field.message_type(), options), + FieldInitializer(pools, field, options)); + } else { + output( + R"cc( + UPB_INLINE bool $1_add_$2($1* msg, $0 val, upb_Arena* arena) { + upb_MiniTableField field = $3; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena); + if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) { + return false; + } + _upb_Array_Set(arr, arr->size - 1, &val, sizeof(val)); + return true; + } + )cc", + CType(field), msg_name, resolved_name, + FieldInitializer(pools, field, options)); + } +} + +void GenerateNonRepeatedSetters(upb::FieldDefPtr field, + const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + if (field == field.containing_type().map_key()) { + // Key cannot be mutated. + return; + } + + std::string field_name = ResolveFieldName(field, field_names); + + if (field == field.containing_type().map_value()) { + output(R"cc( + UPB_INLINE void $0_set_$1($0 *msg, $2 value) { + _upb_msg_map_set_value(msg, &value, $3); + } + )cc", + msg_name, field_name, CType(field), + field.ctype() == kUpb_CType_String ? "0" + : "sizeof(" + CType(field) + ")"); + } else { + output(R"cc( + UPB_INLINE void $0_set_$1($0 *msg, $2 value) { + const upb_MiniTableField field = $3; + _upb_Message_SetNonExtensionField(msg, &field, &value); + } + )cc", + msg_name, field_name, CType(field), + FieldInitializer(pools, field, options)); + } + + // Message fields also have a Msg_mutable_foo() accessor that will create + // the sub-message if it doesn't already exist. + if (field.ctype() == kUpb_CType_Message && + !UPB_DESC(MessageOptions_map_entry)(field.containing_type().options())) { + output( + R"cc( + UPB_INLINE struct $0* $1_mutable_$2($1* msg, upb_Arena* arena) { + struct $0* sub = (struct $0*)$1_$2(msg); + if (sub == NULL) { + sub = (struct $0*)_upb_Message_New($3, arena); + if (sub) $1_set_$2(msg, sub); + } + return sub; + } + )cc", + MessageName(field.message_type()), msg_name, field_name, + MessageMiniTableRef(field.message_type(), options)); + } +} + +void GenerateSetters(upb::FieldDefPtr field, const DefPoolPair& pools, + absl::string_view msg_name, + const NameToFieldDefMap& field_names, + const Options& options, Output& output) { + if (field.IsMap()) { + GenerateMapSetters(field, pools, msg_name, field_names, options, output); + } else if (field.IsSequence()) { + GenerateRepeatedSetters(field, pools, msg_name, field_names, options, + output); + } else { + GenerateNonRepeatedSetters(field, pools, msg_name, field_names, options, + output); + } +} + +void GenerateMessageInHeader(upb::MessageDefPtr message, + const DefPoolPair& pools, const Options& options, + Output& output) { + output("/* $0 */\n\n", message.full_name()); + std::string msg_name = ToCIdent(message.full_name()); + if (!UPB_DESC(MessageOptions_map_entry)(message.options())) { + GenerateMessageFunctionsInHeader(message, options, output); + } + + for (int i = 0; i < message.real_oneof_count(); i++) { + GenerateOneofInHeader(message.oneof(i), pools, msg_name, options, output); + } + + auto field_names = CreateFieldNameMap(message); + for (auto field : FieldNumberOrder(message)) { + GenerateClear(field, pools, msg_name, field_names, options, output); + GenerateGetters(field, pools, msg_name, field_names, options, output); + GenerateHazzer(field, pools, msg_name, field_names, options, output); + } + + output("\n"); + + for (auto field : FieldNumberOrder(message)) { + GenerateSetters(field, pools, msg_name, field_names, options, output); + } + + output("\n"); +} + +void ForwardDeclareMiniTableInit(upb::MessageDefPtr message, + const Options& options, Output& output) { + if (options.bootstrap) { + output("extern const upb_MiniTable* $0();\n", MessageInitName(message)); + } else { + output("extern const upb_MiniTable $0;\n", MessageInitName(message)); + } +} + +std::vector<upb::MessageDefPtr> SortedForwardMessages( + const std::vector<upb::MessageDefPtr>& this_file_messages, + const std::vector<upb::FieldDefPtr>& this_file_exts) { + std::map<std::string, upb::MessageDefPtr> forward_messages; + for (auto message : this_file_messages) { + for (int i = 0; i < message.field_count(); i++) { + upb::FieldDefPtr field = message.field(i); + if (field.ctype() == kUpb_CType_Message && + field.file() != field.message_type().file()) { + forward_messages[field.message_type().full_name()] = + field.message_type(); + } + } + } + for (auto ext : this_file_exts) { + if (ext.file() != ext.containing_type().file()) { + forward_messages[ext.containing_type().full_name()] = + ext.containing_type(); + } + } + std::vector<upb::MessageDefPtr> ret; + ret.reserve(forward_messages.size()); + for (const auto& pair : forward_messages) { + ret.push_back(pair.second); + } + return ret; +} + +void WriteHeader(const DefPoolPair& pools, upb::FileDefPtr file, + const Options& options, Output& output) { + const std::vector<upb::MessageDefPtr> this_file_messages = + SortedMessages(file); + const std::vector<upb::FieldDefPtr> this_file_exts = SortedExtensions(file); + std::vector<upb::EnumDefPtr> this_file_enums = SortedEnums(file); + std::vector<upb::MessageDefPtr> forward_messages = + SortedForwardMessages(this_file_messages, this_file_exts); + + EmitFileWarning(file.name(), output); + output( + "#ifndef $0_UPB_H_\n" + "#define $0_UPB_H_\n\n" + "#include \"upb/generated_code_support.h\"\n\n", + ToPreproc(file.name())); + + for (int i = 0; i < file.public_dependency_count(); i++) { + if (i == 0) { + output("/* Public Imports. */\n"); + } + output("#include \"$0\"\n", CApiHeaderFilename(file.public_dependency(i))); + } + if (file.public_dependency_count() > 0) { + output("\n"); + } + + if (!options.bootstrap) { + output("#include \"$0\"\n\n", MiniTableHeaderFilename(file)); + for (int i = 0; i < file.dependency_count(); i++) { + output("#include \"$0\"\n", MiniTableHeaderFilename(file.dependency(i))); + } + if (file.dependency_count() > 0) { + output("\n"); + } + } + + output( + "// Must be last.\n" + "#include \"upb/port/def.inc\"\n" + "\n" + "#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif\n" + "\n"); + + if (options.bootstrap) { + for (auto message : this_file_messages) { + output("extern const upb_MiniTable* $0();\n", MessageInitName(message)); + } + for (auto message : forward_messages) { + output("extern const upb_MiniTable* $0();\n", MessageInitName(message)); + } + for (auto enumdesc : this_file_enums) { + output("extern const upb_MiniTableEnum* $0();\n", EnumInit(enumdesc)); + } + output("\n"); + } + + // Forward-declare types defined in this file. + for (auto message : this_file_messages) { + output("typedef struct $0 $0;\n", ToCIdent(message.full_name())); + } + + // Forward-declare types not in this file, but used as submessages. + // Order by full name for consistent ordering. + for (auto msg : forward_messages) { + output("struct $0;\n", MessageName(msg)); + } + + if (!this_file_messages.empty()) { + output("\n"); + } + + for (auto enumdesc : this_file_enums) { + output("typedef enum {\n"); + DumpEnumValues(enumdesc, output); + output("} $0;\n\n", ToCIdent(enumdesc.full_name())); + } + + output("\n"); + + output("\n"); + for (auto message : this_file_messages) { + GenerateMessageInHeader(message, pools, options, output); + } + + for (auto ext : this_file_exts) { + GenerateExtensionInHeader(pools, ext, output); + } + + if (absl::string_view(file.name()) == "google/protobuf/descriptor.proto" || + absl::string_view(file.name()) == "net/proto2/proto/descriptor.proto") { + // This is gratuitously inefficient with how many times it rebuilds + // MessageLayout objects for the same message. But we only do this for one + // proto (descriptor.proto) so we don't worry about it. + upb::MessageDefPtr max32_message; + upb::MessageDefPtr max64_message; + size_t max32 = 0; + size_t max64 = 0; + for (const auto message : this_file_messages) { + if (absl::EndsWith(message.name(), "Options")) { + size_t size32 = pools.GetMiniTable32(message)->size; + size_t size64 = pools.GetMiniTable64(message)->size; + if (size32 > max32) { + max32 = size32; + max32_message = message; + } + if (size64 > max64) { + max64 = size64; + max64_message = message; + } + } + } + + output("/* Max size 32 is $0 */\n", max32_message.full_name()); + output("/* Max size 64 is $0 */\n", max64_message.full_name()); + output("#define _UPB_MAXOPT_SIZE UPB_SIZE($0, $1)\n\n", max32, max64); + } + + output( + "#ifdef __cplusplus\n" + "} /* extern \"C\" */\n" + "#endif\n" + "\n" + "#include \"upb/port/undef.inc\"\n" + "\n" + "#endif /* $0_UPB_H_ */\n", + ToPreproc(file.name())); +} + +std::string FieldInitializer(upb::FieldDefPtr field, + const upb_MiniTableField* field64, + const upb_MiniTableField* field32, + const Options& options) { + if (options.bootstrap) { + ABSL_CHECK(!field.is_extension()); + return absl::Substitute( + "*upb_MiniTable_FindFieldByNumber($0, $1)", + MessageMiniTableRef(field.containing_type(), options), field.number()); + } else { + return upbc::FieldInitializer(field, field64, field32); + } +} + +std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field, + const Options& options) { + return FieldInitializer(field, pools.GetField64(field), + pools.GetField32(field), options); +} + +void WriteMessageMiniDescriptorInitializer(upb::MessageDefPtr msg, + const Options& options, + Output& output) { + Output resolve_calls; + for (int i = 0; i < msg.field_count(); i++) { + upb::FieldDefPtr field = msg.field(i); + if (!field.message_type() && !field.enum_subdef()) continue; + if (field.message_type()) { + resolve_calls( + "upb_MiniTable_SetSubMessage(mini_table, " + "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, " + "$0), $1);\n ", + field.number(), MessageMiniTableRef(field.message_type(), options)); + } else if (field.enum_subdef() && field.enum_subdef().is_closed()) { + resolve_calls( + "upb_MiniTable_SetSubEnum(mini_table, " + "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, " + "$0), $1);\n ", + field.number(), EnumMiniTableRef(field.enum_subdef(), options)); + } + } + + output( + R"cc( + const upb_MiniTable* $0() { + static upb_MiniTable* mini_table = NULL; + static const char* mini_descriptor = "$1"; + if (mini_table) return mini_table; + mini_table = + upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor), + upb_BootstrapArena(), NULL); + $2return mini_table; + } + )cc", + MessageInitName(msg), msg.MiniDescriptorEncode(), resolve_calls.output()); + output("\n"); +} + +void WriteEnumMiniDescriptorInitializer(upb::EnumDefPtr enum_def, + const Options& options, + Output& output) { + output( + R"cc( + const upb_MiniTableEnum* $0() { + static const upb_MiniTableEnum* mini_table = NULL; + static const char* mini_descriptor = "$1"; + if (mini_table) return mini_table; + mini_table = + upb_MiniTableEnum_Build(mini_descriptor, strlen(mini_descriptor), + upb_BootstrapArena(), NULL); + return mini_table; + } + )cc", + EnumInitName(enum_def), enum_def.MiniDescriptorEncode()); + output("\n"); +} + +void WriteMiniDescriptorSource(const DefPoolPair& pools, upb::FileDefPtr file, + const Options& options, Output& output) { + output( + "#include <stddef.h>\n" + "#include \"upb/generated_code_support.h\"\n" + "#include \"$0\"\n\n", + CApiHeaderFilename(file)); + + for (int i = 0; i < file.dependency_count(); i++) { + output("#include \"$0\"\n", CApiHeaderFilename(file.dependency(i))); + } + + output( + R"cc( + static upb_Arena* upb_BootstrapArena() { + static upb_Arena* arena = NULL; + if (!arena) arena = upb_Arena_New(); + return arena; + } + )cc"); + + output("\n"); + + for (const auto msg : SortedMessages(file)) { + WriteMessageMiniDescriptorInitializer(msg, options, output); + } + + for (const auto msg : SortedEnums(file)) { + WriteEnumMiniDescriptorInitializer(msg, options, output); + } +} + +void GenerateFile(const DefPoolPair& pools, upb::FileDefPtr file, + const Options& options, Plugin* plugin) { + Output h_output; + WriteHeader(pools, file, options, h_output); + plugin->AddOutputFile(CApiHeaderFilename(file), h_output.output()); + + if (options.bootstrap) { + Output c_output; + WriteMiniDescriptorSource(pools, file, options, c_output); + plugin->AddOutputFile(SourceFilename(file), c_output.output()); + } else { + // TODO: remove once we can figure out how to make both Blaze + // and Bazel happy with header-only libraries. + + // begin:github_only + plugin->AddOutputFile(SourceFilename(file), "\n"); + // end:github_only + } +} + +bool ParseOptions(Plugin* plugin, Options* options) { + for (const auto& pair : ParseGeneratorParameter(plugin->parameter())) { + if (pair.first == "bootstrap_upb") { + options->bootstrap = true; + } else { + plugin->SetError(absl::Substitute("Unknown parameter: $0", pair.first)); + return false; + } + } + + return true; +} + +absl::string_view ToStringView(upb_StringView str) { + return absl::string_view(str.data, str.size); +} + +} // namespace + +} // namespace upbc + +int main(int argc, char** argv) { + upbc::DefPoolPair pools; + upbc::Plugin plugin; + upbc::Options options; + if (!ParseOptions(&plugin, &options)) return 0; + plugin.GenerateFilesRaw([&](const UPB_DESC(FileDescriptorProto) * file_proto, + bool generate) { + upb::Status status; + upb::FileDefPtr file = pools.AddFile(file_proto, &status); + if (!file) { + absl::string_view name = + upbc::ToStringView(UPB_DESC(FileDescriptorProto_name)(file_proto)); + ABSL_LOG(FATAL) << "Couldn't add file " << name + << " to DefPool: " << status.error_message(); + } + if (generate) GenerateFile(pools, file, options, &plugin); + }); + return 0; +}
diff --git a/upbc/protoc-gen-upb_minitable.cc b/upbc/protoc-gen-upb_minitable.cc new file mode 100644 index 0000000..745dc84 --- /dev/null +++ b/upbc/protoc-gen-upb_minitable.cc
@@ -0,0 +1,709 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "absl/log/absl_check.h" +#include "absl/log/absl_log.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "upb/base/descriptor_constants.h" +#include "upb/base/string_view.h" +#include "upb/reflection/def.hpp" +#include "upb/wire/types.h" +#include "upbc/common.h" +#include "upbc/file_layout.h" +#include "upbc/names.h" +#include "upbc/plugin.h" + +// Must be last. +#include "upb/port/def.inc" + +namespace upbc { +namespace { + +// Returns fields in order of "hotness", eg. how frequently they appear in +// serialized payloads. Ideally this will use a profile. When we don't have +// that, we assume that fields with smaller numbers are used more frequently. +inline std::vector<upb::FieldDefPtr> FieldHotnessOrder( + upb::MessageDefPtr message) { + std::vector<upb::FieldDefPtr> fields; + size_t field_count = message.field_count(); + fields.reserve(field_count); + for (size_t i = 0; i < field_count; i++) { + fields.push_back(message.field(i)); + } + std::sort(fields.begin(), fields.end(), + [](upb::FieldDefPtr a, upb::FieldDefPtr b) { + return std::make_pair(!a.is_required(), a.number()) < + std::make_pair(!b.is_required(), b.number()); + }); + return fields; +} + +std::string SourceFilename(upb::FileDefPtr file) { + return StripExtension(file.name()) + ".upb_minitable.c"; +} + +std::string MessageInitName(upb::MessageDefPtr descriptor) { + return absl::StrCat(MessageName(descriptor), "_msg_init"); +} + +std::string ExtensionIdentBase(upb::FieldDefPtr 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 ExtensionLayout(upb::FieldDefPtr ext) { + return absl::StrCat(ExtensionIdentBase(ext), "_", ext.name(), "_ext"); +} + +const char* kEnumsInit = "enums_layout"; +const char* kExtensionsInit = "extensions_layout"; +const char* kMessagesInit = "messages_layout"; + +void WriteHeader(const DefPoolPair& pools, upb::FileDefPtr file, + Output& output) { + EmitFileWarning(file.name(), output); + output( + "#ifndef $0_UPB_MINITABLE_H_\n" + "#define $0_UPB_MINITABLE_H_\n\n" + "#include \"upb/generated_code_support.h\"\n", + ToPreproc(file.name())); + + for (int i = 0; i < file.public_dependency_count(); i++) { + if (i == 0) { + output("/* Public Imports. */\n"); + } + output("#include \"$0\"\n", + MiniTableHeaderFilename(file.public_dependency(i))); + if (i == file.public_dependency_count() - 1) { + output("\n"); + } + } + + output( + "\n" + "// Must be last.\n" + "#include \"upb/port/def.inc\"\n" + "\n" + "#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif\n" + "\n"); + + const std::vector<upb::MessageDefPtr> this_file_messages = + SortedMessages(file); + const std::vector<upb::FieldDefPtr> this_file_exts = SortedExtensions(file); + + for (auto message : this_file_messages) { + output("extern const upb_MiniTable $0;\n", MessageInitName(message)); + } + for (auto ext : this_file_exts) { + output("extern const upb_MiniTableExtension $0;\n", ExtensionLayout(ext)); + } + + output("\n"); + + std::vector<upb::EnumDefPtr> this_file_enums = SortedEnums(file); + + if (file.syntax() == kUpb_Syntax_Proto2) { + for (const auto enumdesc : this_file_enums) { + output("extern const upb_MiniTableEnum $0;\n", EnumInit(enumdesc)); + } + } + + output("extern const upb_MiniTableFile $0;\n\n", FileLayoutName(file)); + + output( + "#ifdef __cplusplus\n" + "} /* extern \"C\" */\n" + "#endif\n" + "\n" + "#include \"upb/port/undef.inc\"\n" + "\n" + "#endif /* $0_UPB_MINITABLE_H_ */\n", + ToPreproc(file.name())); +} + +typedef std::pair<std::string, uint64_t> TableEntry; + +uint32_t GetWireTypeForField(upb::FieldDefPtr field) { + if (field.packed()) return kUpb_WireType_Delimited; + switch (field.type()) { + case kUpb_FieldType_Double: + case kUpb_FieldType_Fixed64: + case kUpb_FieldType_SFixed64: + return kUpb_WireType_64Bit; + case kUpb_FieldType_Float: + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + return kUpb_WireType_32Bit; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + case kUpb_FieldType_Int32: + case kUpb_FieldType_Bool: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + case kUpb_FieldType_SInt32: + case kUpb_FieldType_SInt64: + return kUpb_WireType_Varint; + case kUpb_FieldType_Group: + return kUpb_WireType_StartGroup; + case kUpb_FieldType_Message: + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: + return kUpb_WireType_Delimited; + } + UPB_UNREACHABLE(); +} + +uint32_t MakeTag(uint32_t field_number, uint32_t wire_type) { + return field_number << 3 | wire_type; +} + +size_t WriteVarint32ToArray(uint64_t val, char* buf) { + size_t i = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } while (val); + return i; +} + +uint64_t GetEncodedTag(upb::FieldDefPtr field) { + uint32_t wire_type = GetWireTypeForField(field); + uint32_t unencoded_tag = MakeTag(field.number(), wire_type); + char tag_bytes[10] = {0}; + WriteVarint32ToArray(unencoded_tag, tag_bytes); + uint64_t encoded_tag = 0; + memcpy(&encoded_tag, tag_bytes, sizeof(encoded_tag)); + // TODO: byte-swap for big endian. + return encoded_tag; +} + +int GetTableSlot(upb::FieldDefPtr field) { + uint64_t tag = GetEncodedTag(field); + if (tag > 0x7fff) { + // Tag must fit within a two-byte varint. + return -1; + } + return (tag & 0xf8) >> 3; +} + +bool TryFillTableEntry(const DefPoolPair& pools, upb::FieldDefPtr field, + TableEntry& ent) { + const upb_MiniTable* mt = pools.GetMiniTable64(field.containing_type()); + const upb_MiniTableField* mt_f = + upb_MiniTable_FindFieldByNumber(mt, field.number()); + std::string type = ""; + std::string cardinality = ""; + switch (upb_MiniTableField_Type(mt_f)) { + case kUpb_FieldType_Bool: + type = "b1"; + break; + case kUpb_FieldType_Enum: + if (upb_MiniTableField_IsClosedEnum(mt_f)) { + // We don't have the means to test proto2 enum fields for valid values. + return false; + } + [[fallthrough]]; + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + type = "v4"; + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + type = "v8"; + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + case kUpb_FieldType_Float: + type = "f4"; + break; + case kUpb_FieldType_Fixed64: + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Double: + type = "f8"; + break; + case kUpb_FieldType_SInt32: + type = "z4"; + break; + case kUpb_FieldType_SInt64: + type = "z8"; + break; + case kUpb_FieldType_String: + type = "s"; + break; + case kUpb_FieldType_Bytes: + type = "b"; + break; + case kUpb_FieldType_Message: + type = "m"; + break; + default: + return false; // Not supported yet. + } + + switch (upb_FieldMode_Get(mt_f)) { + case kUpb_FieldMode_Map: + return false; // Not supported yet (ever?). + case kUpb_FieldMode_Array: + if (mt_f->mode & kUpb_LabelFlags_IsPacked) { + cardinality = "p"; + } else { + cardinality = "r"; + } + break; + case kUpb_FieldMode_Scalar: + if (mt_f->presence < 0) { + cardinality = "o"; + } else { + cardinality = "s"; + } + break; + } + + uint64_t expected_tag = GetEncodedTag(field); + + // Data is: + // + // 48 32 16 0 + // |--------|--------|--------|--------|--------|--------|--------|--------| + // | offset (16) |case offset (16) |presence| submsg | exp. tag (16) | + // |--------|--------|--------|--------|--------|--------|--------|--------| + // + // - |presence| is either hasbit index or field number for oneofs. + + uint64_t data = static_cast<uint64_t>(mt_f->offset) << 48 | expected_tag; + + if (field.IsSequence()) { + // No hasbit/oneof-related fields. + } + if (field.real_containing_oneof()) { + uint64_t case_offset = ~mt_f->presence; + if (case_offset > 0xffff || field.number() > 0xff) return false; + data |= field.number() << 24; + data |= case_offset << 32; + } else { + uint64_t hasbit_index = 63; // No hasbit (set a high, unused bit). + if (mt_f->presence) { + hasbit_index = mt_f->presence; + if (hasbit_index > 31) return false; + } + data |= hasbit_index << 24; + } + + if (field.ctype() == kUpb_CType_Message) { + uint64_t idx = mt_f->UPB_PRIVATE(submsg_index); + if (idx > 255) return false; + data |= idx << 16; + + std::string size_ceil = "max"; + size_t size = SIZE_MAX; + if (field.message_type().file() == field.file()) { + // We can only be guaranteed the size of the sub-message if it is in the + // same file as us. We could relax this to increase the speed of + // cross-file sub-message parsing if we are comfortable requiring that + // users compile all messages at the same time. + const upb_MiniTable* sub_mt = pools.GetMiniTable64(field.message_type()); + size = sub_mt->size + 8; + } + std::vector<size_t> breaks = {64, 128, 192, 256}; + for (auto brk : breaks) { + if (size <= brk) { + size_ceil = std::to_string(brk); + break; + } + } + ent.first = absl::Substitute("upb_p$0$1_$2bt_max$3b", cardinality, type, + expected_tag > 0xff ? "2" : "1", size_ceil); + + } else { + ent.first = absl::Substitute("upb_p$0$1_$2bt", cardinality, type, + expected_tag > 0xff ? "2" : "1"); + } + ent.second = data; + return true; +} + +std::vector<TableEntry> FastDecodeTable(upb::MessageDefPtr message, + const DefPoolPair& pools) { + std::vector<TableEntry> table; + for (const auto field : FieldHotnessOrder(message)) { + TableEntry ent; + int slot = GetTableSlot(field); + // std::cerr << "table slot: " << field->number() << ": " << slot << "\n"; + if (slot < 0) { + // Tag can't fit in the table. + continue; + } + if (!TryFillTableEntry(pools, field, ent)) { + // Unsupported field type or offset, hasbit index, etc. doesn't fit. + continue; + } + while ((size_t)slot >= table.size()) { + size_t size = std::max(static_cast<size_t>(1), table.size() * 2); + table.resize(size, TableEntry{"_upb_FastDecoder_DecodeGeneric", 0}); + } + if (table[slot].first != "_upb_FastDecoder_DecodeGeneric") { + // A hotter field already filled this slot. + continue; + } + table[slot] = ent; + } + return table; +} + +std::string ArchDependentSize(int64_t size32, int64_t size64) { + if (size32 == size64) return absl::StrCat(size32); + return absl::Substitute("UPB_SIZE($0, $1)", size32, size64); +} + +std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field) { + return upbc::FieldInitializer(field, pools.GetField64(field), + pools.GetField32(field)); +} + +// Writes a single field into a .upb.c source file. +void WriteMessageField(upb::FieldDefPtr field, + const upb_MiniTableField* field64, + const upb_MiniTableField* field32, Output& output) { + output(" $0,\n", upbc::FieldInitializer(field, field64, field32)); +} + +std::string GetSub(upb::FieldDefPtr field) { + if (auto message_def = field.message_type()) { + return absl::Substitute("{.submsg = &$0}", MessageInitName(message_def)); + } + + if (auto enum_def = field.enum_subdef()) { + if (enum_def.is_closed()) { + return absl::Substitute("{.subenum = &$0}", EnumInit(enum_def)); + } + } + + return std::string("{.submsg = NULL}"); +} + +// Writes a single message into a .upb.c source file. +void WriteMessage(upb::MessageDefPtr message, const DefPoolPair& pools, + Output& output) { + std::string msg_name = ToCIdent(message.full_name()); + std::string fields_array_ref = "NULL"; + std::string submsgs_array_ref = "NULL"; + std::string subenums_array_ref = "NULL"; + const upb_MiniTable* mt_32 = pools.GetMiniTable32(message); + const upb_MiniTable* mt_64 = pools.GetMiniTable64(message); + std::map<int, std::string> subs; + + for (int i = 0; i < mt_64->field_count; i++) { + const upb_MiniTableField* f = &mt_64->fields[i]; + uint32_t index = f->UPB_PRIVATE(submsg_index); + if (index != kUpb_NoSub) { + auto pair = + subs.emplace(index, GetSub(message.FindFieldByNumber(f->number))); + ABSL_CHECK(pair.second); + } + } + + if (!subs.empty()) { + std::string submsgs_array_name = msg_name + "_submsgs"; + submsgs_array_ref = "&" + submsgs_array_name + "[0]"; + output("static const upb_MiniTableSub $0[$1] = {\n", submsgs_array_name, + subs.size()); + + int i = 0; + for (const auto& pair : subs) { + ABSL_CHECK(pair.first == i++); + output(" $0,\n", pair.second); + } + + output("};\n\n"); + } + + if (mt_64->field_count > 0) { + std::string fields_array_name = msg_name + "__fields"; + fields_array_ref = "&" + fields_array_name + "[0]"; + output("static const upb_MiniTableField $0[$1] = {\n", fields_array_name, + mt_64->field_count); + for (int i = 0; i < mt_64->field_count; i++) { + WriteMessageField(message.FindFieldByNumber(mt_64->fields[i].number), + &mt_64->fields[i], &mt_32->fields[i], output); + } + output("};\n\n"); + } + + std::vector<TableEntry> table; + uint8_t table_mask = -1; + + table = FastDecodeTable(message, pools); + + if (table.size() > 1) { + assert((table.size() & (table.size() - 1)) == 0); + table_mask = (table.size() - 1) << 3; + } + + std::string msgext = "kUpb_ExtMode_NonExtendable"; + + if (message.extension_range_count()) { + if (UPB_DESC(MessageOptions_message_set_wire_format)(message.options())) { + msgext = "kUpb_ExtMode_IsMessageSet"; + } else { + msgext = "kUpb_ExtMode_Extendable"; + } + } + + output("const upb_MiniTable $0 = {\n", MessageInitName(message)); + output(" $0,\n", submsgs_array_ref); + output(" $0,\n", fields_array_ref); + output(" $0, $1, $2, $3, UPB_FASTTABLE_MASK($4), $5,\n", + ArchDependentSize(mt_32->size, mt_64->size), mt_64->field_count, + msgext, mt_64->dense_below, table_mask, mt_64->required_count); + if (!table.empty()) { + output(" UPB_FASTTABLE_INIT({\n"); + for (const auto& ent : table) { + output(" {0x$1, &$0},\n", ent.first, + absl::StrCat(absl::Hex(ent.second, absl::kZeroPad16))); + } + output(" })\n"); + } + output("};\n\n"); +} + +void WriteEnum(upb::EnumDefPtr e, Output& output) { + std::string values_init = "{\n"; + const upb_MiniTableEnum* mt = e.mini_table(); + uint32_t value_count = (mt->mask_limit / 32) + mt->value_count; + for (uint32_t i = 0; i < value_count; i++) { + absl::StrAppend(&values_init, " 0x", absl::Hex(mt->data[i]), + ",\n"); + } + values_init += " }"; + + output( + R"cc( + const upb_MiniTableEnum $0 = { + $1, + $2, + $3, + }; + )cc", + EnumInit(e), mt->mask_limit, mt->value_count, values_init); + output("\n"); +} + +int WriteEnums(const DefPoolPair& pools, upb::FileDefPtr file, Output& output) { + if (file.syntax() != kUpb_Syntax_Proto2) return 0; + + std::vector<upb::EnumDefPtr> this_file_enums = SortedEnums(file); + + for (const auto e : this_file_enums) { + WriteEnum(e, output); + } + + if (!this_file_enums.empty()) { + output("static const upb_MiniTableEnum *$0[$1] = {\n", kEnumsInit, + this_file_enums.size()); + for (const auto e : this_file_enums) { + output(" &$0,\n", EnumInit(e)); + } + output("};\n"); + output("\n"); + } + + return this_file_enums.size(); +} + +int WriteMessages(const DefPoolPair& pools, upb::FileDefPtr file, + Output& output) { + std::vector<upb::MessageDefPtr> file_messages = SortedMessages(file); + + if (file_messages.empty()) return 0; + + for (auto message : file_messages) { + WriteMessage(message, pools, output); + } + + output("static const upb_MiniTable *$0[$1] = {\n", kMessagesInit, + file_messages.size()); + for (auto message : file_messages) { + output(" &$0,\n", MessageInitName(message)); + } + output("};\n"); + output("\n"); + return file_messages.size(); +} + +void WriteExtension(upb::FieldDefPtr ext, const DefPoolPair& pools, + Output& output) { + output("$0,\n", FieldInitializer(pools, ext)); + output(" &$0,\n", MessageInitName(ext.containing_type())); + output(" $0,\n", GetSub(ext)); +} + +int WriteExtensions(const DefPoolPair& pools, upb::FileDefPtr file, + Output& output) { + auto exts = SortedExtensions(file); + + if (exts.empty()) return 0; + + // Order by full name for consistent ordering. + std::map<std::string, upb::MessageDefPtr> forward_messages; + + for (auto ext : exts) { + forward_messages[ext.containing_type().full_name()] = ext.containing_type(); + if (ext.message_type()) { + forward_messages[ext.message_type().full_name()] = ext.message_type(); + } + } + + for (auto ext : exts) { + output("const upb_MiniTableExtension $0 = {\n ", ExtensionLayout(ext)); + WriteExtension(ext, pools, output); + output("\n};\n"); + } + + output( + "\n" + "static const upb_MiniTableExtension *$0[$1] = {\n", + kExtensionsInit, exts.size()); + + for (auto ext : exts) { + output(" &$0,\n", ExtensionLayout(ext)); + } + + output( + "};\n" + "\n"); + return exts.size(); +} + +void WriteMiniTableSource(const DefPoolPair& pools, upb::FileDefPtr file, + Output& output) { + EmitFileWarning(file.name(), output); + + output( + "#include <stddef.h>\n" + "#include \"upb/generated_code_support.h\"\n" + "#include \"$0\"\n", + MiniTableHeaderFilename(file)); + + for (int i = 0; i < file.dependency_count(); i++) { + output("#include \"$0\"\n", MiniTableHeaderFilename(file.dependency(i))); + } + + output( + "\n" + "// Must be last.\n" + "#include \"upb/port/def.inc\"\n" + "\n"); + + int msg_count = WriteMessages(pools, file, output); + int ext_count = WriteExtensions(pools, file, output); + int enum_count = WriteEnums(pools, file, output); + + output("const upb_MiniTableFile $0 = {\n", FileLayoutName(file)); + output(" $0,\n", msg_count ? kMessagesInit : "NULL"); + output(" $0,\n", enum_count ? kEnumsInit : "NULL"); + output(" $0,\n", ext_count ? kExtensionsInit : "NULL"); + output(" $0,\n", msg_count); + output(" $0,\n", enum_count); + output(" $0,\n", ext_count); + output("};\n\n"); + + output("#include \"upb/port/undef.inc\"\n"); + output("\n"); +} + +void GenerateFile(const DefPoolPair& pools, upb::FileDefPtr file, + Plugin* plugin) { + Output h_output; + WriteHeader(pools, file, h_output); + plugin->AddOutputFile(MiniTableHeaderFilename(file), h_output.output()); + + Output c_output; + WriteMiniTableSource(pools, file, c_output); + plugin->AddOutputFile(SourceFilename(file), c_output.output()); +} + +bool ParseOptions(Plugin* plugin) { + for (const auto& pair : ParseGeneratorParameter(plugin->parameter())) { + plugin->SetError(absl::Substitute("Unknown parameter: $0", pair.first)); + return false; + } + + return true; +} + +absl::string_view ToStringView(upb_StringView str) { + return absl::string_view(str.data, str.size); +} + +} // namespace + +} // namespace upbc + +int main(int argc, char** argv) { + upbc::DefPoolPair pools; + upbc::Plugin plugin; + if (!upbc::ParseOptions(&plugin)) return 0; + plugin.GenerateFilesRaw([&](const UPB_DESC(FileDescriptorProto) * file_proto, + bool generate) { + upb::Status status; + upb::FileDefPtr file = pools.AddFile(file_proto, &status); + if (!file) { + absl::string_view name = + upbc::ToStringView(UPB_DESC(FileDescriptorProto_name)(file_proto)); + ABSL_LOG(FATAL) << "Couldn't add file " << name + << " to DefPool: " << status.error_message(); + } + if (generate) upbc::GenerateFile(pools, file, &plugin); + }); + return 0; +}
diff --git a/upbc/protoc-gen-upbdefs.cc b/upbc/protoc-gen-upbdefs.cc new file mode 100644 index 0000000..d2870b0 --- /dev/null +++ b/upbc/protoc-gen-upbdefs.cc
@@ -0,0 +1,175 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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/descriptor.upb.h" +#include "upb/reflection/def.hpp" +#include "upb/util/def_to_proto.h" +#include "upbc/common.h" +#include "upbc/file_layout.h" +#include "upbc/plugin.h" + +namespace upbc { +namespace { + +std::string DefInitSymbol(upb::FileDefPtr file) { + return ToCIdent(file.name()) + "_upbdefinit"; +} + +static std::string DefHeaderFilename(upb::FileDefPtr file) { + return StripExtension(file.name()) + ".upbdefs.h"; +} + +static std::string DefSourceFilename(upb::FileDefPtr file) { + return StripExtension(file.name()) + ".upbdefs.c"; +} + +void GenerateMessageDefAccessor(upb::MessageDefPtr d, Output& output) { + output("UPB_INLINE const upb_MessageDef *$0_getmsgdef(upb_DefPool *s) {\n", + ToCIdent(d.full_name())); + output(" _upb_DefPool_LoadDefInit(s, &$0);\n", DefInitSymbol(d.file())); + output(" return upb_DefPool_FindMessageByName(s, \"$0\");\n", d.full_name()); + output("}\n"); + output("\n"); +} + +void WriteDefHeader(upb::FileDefPtr file, Output& output) { + EmitFileWarning(file.name(), output); + + output( + "#ifndef $0_UPBDEFS_H_\n" + "#define $0_UPBDEFS_H_\n\n" + "#include \"upb/reflection/def.h\"\n" + "#include \"upb/reflection/internal/def_pool.h\"\n" + "#include \"upb/port/def.inc\"\n" + "#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif\n\n", + ToPreproc(file.name())); + + output("#include \"upb/reflection/def.h\"\n"); + output("\n"); + output("#include \"upb/port/def.inc\"\n"); + output("\n"); + + output("extern _upb_DefPool_Init $0;\n", DefInitSymbol(file)); + output("\n"); + + for (auto msg : SortedMessages(file)) { + GenerateMessageDefAccessor(msg, output); + } + + output( + "#ifdef __cplusplus\n" + "} /* extern \"C\" */\n" + "#endif\n" + "\n" + "#include \"upb/port/undef.inc\"\n" + "\n" + "#endif /* $0_UPBDEFS_H_ */\n", + ToPreproc(file.name())); +} + +void WriteDefSource(upb::FileDefPtr file, Output& output) { + EmitFileWarning(file.name(), output); + + output("#include \"upb/reflection/def.h\"\n"); + output("#include \"$0\"\n", DefHeaderFilename(file)); + output("#include \"$0\"\n", MiniTableHeaderFilename(file)); + output("\n"); + + for (int i = 0; i < file.dependency_count(); i++) { + output("extern _upb_DefPool_Init $0;\n", DefInitSymbol(file.dependency(i))); + } + + upb::Arena arena; + google_protobuf_FileDescriptorProto* file_proto = + upb_FileDef_ToProto(file.ptr(), arena.ptr()); + size_t serialized_size; + const char* serialized = google_protobuf_FileDescriptorProto_serialize( + file_proto, arena.ptr(), &serialized_size); + absl::string_view file_data(serialized, serialized_size); + + output("static const char descriptor[$0] = {", serialized_size); + + // C90 only guarantees that strings can be up to 509 characters, and some + // implementations have limits here (for example, MSVC only allows 64k: + // https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1091. + // So we always emit an array instead of a string. + for (size_t i = 0; i < serialized_size;) { + for (size_t j = 0; j < 25 && i < serialized_size; ++i, ++j) { + output("'$0', ", absl::CEscape(file_data.substr(i, 1))); + } + output("\n"); + } + output("};\n\n"); + + output("static _upb_DefPool_Init *deps[$0] = {\n", + file.dependency_count() + 1); + for (int i = 0; i < file.dependency_count(); i++) { + output(" &$0,\n", DefInitSymbol(file.dependency(i))); + } + output(" NULL\n"); + output("};\n"); + output("\n"); + + output("_upb_DefPool_Init $0 = {\n", DefInitSymbol(file)); + output(" deps,\n"); + output(" &$0,\n", FileLayoutName(file)); + output(" \"$0\",\n", file.name()); + output(" UPB_STRINGVIEW_INIT(descriptor, $0)\n", file_data.size()); + output("};\n"); +} + +void GenerateFile(upb::FileDefPtr file, Plugin* plugin) { + Output h_def_output; + WriteDefHeader(file, h_def_output); + plugin->AddOutputFile(DefHeaderFilename(file), h_def_output.output()); + + Output c_def_output; + WriteDefSource(file, c_def_output); + plugin->AddOutputFile(DefSourceFilename(file), c_def_output.output()); +} + +} // namespace +} // namespace upbc + +int main(int argc, char** argv) { + upbc::Plugin plugin; + if (!plugin.parameter().empty()) { + plugin.SetError( + absl::StrCat("Expected no parameters, got: ", plugin.parameter())); + return 0; + } + plugin.GenerateFiles( + [&](upb::FileDefPtr file) { upbc::GenerateFile(file, &plugin); }); + return 0; +}
diff --git a/upbc/protoc-gen-upbdev.cc b/upbc/protoc-gen-upbdev.cc new file mode 100644 index 0000000..3093169 --- /dev/null +++ b/upbc/protoc-gen-upbdev.cc
@@ -0,0 +1,91 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 <iostream> +#include <string> + +#include "google/protobuf/compiler/plugin.upb.h" +#include "upbc/subprocess.h" +#include "upbc/upbdev.h" + +static constexpr char kDefaultPlugin[] = "protoc_dart_plugin"; + +int main() { + upb_Arena* a = upb_Arena_New(); + upb_Status status; + upb_Status_Clear(&status); + + // Read (binary) stdin into a string. + const std::string input = {std::istreambuf_iterator<char>(std::cin), + std::istreambuf_iterator<char>()}; + + // Parse the request. + auto inner_request = google_protobuf_compiler_CodeGeneratorRequest_parse( + input.c_str(), input.size(), a); + + // Check the request for a plugin name. + std::string plugin = kDefaultPlugin; + if (google_protobuf_compiler_CodeGeneratorRequest_has_parameter(inner_request)) { + auto param = google_protobuf_compiler_CodeGeneratorRequest_parameter(inner_request); + plugin = std::string(param.data, param.size); + } + + // Wrap the request inside a upbc_CodeGeneratorRequest and JSON-encode it. + const upb_StringView sv = + upbdev_ProcessInput(input.data(), input.size(), a, &status); + if (!upb_Status_IsOk(&status)) { + std::cerr << status.msg << std::endl; + return -1; + } + + // Launch the subprocess. + upbc::Subprocess subprocess; + subprocess.Start(plugin, upbc::Subprocess::SEARCH_PATH); + + // Exchange JSON strings with the subprocess. + const std::string json_request = std::string(sv.data, sv.size); + std::string json_response, error; + const bool ok = subprocess.Communicate(json_request, &json_response, &error); + if (!ok) { + // Dump the JSON request to stderr if we can't launch the next plugin. + std::cerr << json_request << std::endl; + return -1; + } + + // Decode, serialize, and write the JSON response. + upbdev_ProcessOutput(json_response.data(), json_response.size(), a, &status); + if (!upb_Status_IsOk(&status)) { + std::cerr << status.msg << std::endl; + return -1; + } + + upb_Arena_Free(a); + return 0; +}
diff --git a/upbc/stage0/google/protobuf/compiler/plugin.upb.c b/upbc/stage0/google/protobuf/compiler/plugin.upb.c new file mode 100644 index 0000000..3a67715 --- /dev/null +++ b/upbc/stage0/google/protobuf/compiler/plugin.upb.c
@@ -0,0 +1,66 @@ +#include <stddef.h> +#include "upb/generated_code_support.h" +#include "google/protobuf/compiler/plugin.upb.h" + +#include "google/protobuf/descriptor.upb.h" +static upb_Arena* upb_BootstrapArena() { + static upb_Arena* arena = NULL; + if (!arena) arena = upb_Arena_New(); + return arena; +} + +const upb_MiniTable* google_protobuf_compiler_Version_msg_init() { + static upb_MiniTable* mini_table = NULL; + static const char* mini_descriptor = "$(((1"; + if (mini_table) return mini_table; + mini_table = + upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor), + upb_BootstrapArena(), NULL); + return mini_table; +} + +const upb_MiniTable* google_protobuf_compiler_CodeGeneratorRequest_msg_init() { + static upb_MiniTable* mini_table = NULL; + static const char* mini_descriptor = "$E13kGaG"; + if (mini_table) return mini_table; + mini_table = + upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor), + upb_BootstrapArena(), NULL); + upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, 15), google_protobuf_FileDescriptorProto_msg_init()); + upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, 17), google_protobuf_FileDescriptorProto_msg_init()); + upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, 3), google_protobuf_compiler_Version_msg_init()); + return mini_table; +} + +const upb_MiniTable* google_protobuf_compiler_CodeGeneratorResponse_msg_init() { + static upb_MiniTable* mini_table = NULL; + static const char* mini_descriptor = "$1,lG"; + if (mini_table) return mini_table; + mini_table = + upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor), + upb_BootstrapArena(), NULL); + upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, 15), google_protobuf_compiler_CodeGeneratorResponse_File_msg_init()); + return mini_table; +} + +const upb_MiniTable* google_protobuf_compiler_CodeGeneratorResponse_File_msg_init() { + static upb_MiniTable* mini_table = NULL; + static const char* mini_descriptor = "$11l13"; + if (mini_table) return mini_table; + mini_table = + upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor), + upb_BootstrapArena(), NULL); + upb_MiniTable_SetSubMessage(mini_table, (upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, 16), google_protobuf_GeneratedCodeInfo_msg_init()); + return mini_table; +} + +const upb_MiniTableEnum* google_protobuf_compiler_CodeGeneratorResponse_Feature_enum_init() { + static const upb_MiniTableEnum* mini_table = NULL; + static const char* mini_descriptor = "!)"; + if (mini_table) return mini_table; + mini_table = + upb_MiniTableEnum_Build(mini_descriptor, strlen(mini_descriptor), + upb_BootstrapArena(), NULL); + return mini_table; +} +
diff --git a/upbc/stage0/google/protobuf/compiler/plugin.upb.h b/upbc/stage0/google/protobuf/compiler/plugin.upb.h new file mode 100644 index 0000000..4227e51 --- /dev/null +++ b/upbc/stage0/google/protobuf/compiler/plugin.upb.h
@@ -0,0 +1,692 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/compiler/plugin.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_PROTO_UPB_H_ + +#include "upb/generated_code_support.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const upb_MiniTable* google_protobuf_compiler_Version_msg_init(); +extern const upb_MiniTable* google_protobuf_compiler_CodeGeneratorRequest_msg_init(); +extern const upb_MiniTable* google_protobuf_compiler_CodeGeneratorResponse_msg_init(); +extern const upb_MiniTable* google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(); +extern const upb_MiniTable* google_protobuf_FileDescriptorProto_msg_init(); +extern const upb_MiniTable* google_protobuf_GeneratedCodeInfo_msg_init(); +extern const upb_MiniTableEnum* google_protobuf_compiler_CodeGeneratorResponse_Feature_enum_init(); + +typedef struct google_protobuf_compiler_Version google_protobuf_compiler_Version; +typedef struct google_protobuf_compiler_CodeGeneratorRequest google_protobuf_compiler_CodeGeneratorRequest; +typedef struct google_protobuf_compiler_CodeGeneratorResponse google_protobuf_compiler_CodeGeneratorResponse; +typedef struct google_protobuf_compiler_CodeGeneratorResponse_File google_protobuf_compiler_CodeGeneratorResponse_File; +struct google_protobuf_FileDescriptorProto; +struct google_protobuf_GeneratedCodeInfo; + +typedef enum { + google_protobuf_compiler_CodeGeneratorResponse_FEATURE_NONE = 0, + google_protobuf_compiler_CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL = 1, + google_protobuf_compiler_CodeGeneratorResponse_FEATURE_SUPPORTS_EDITIONS = 2 +} google_protobuf_compiler_CodeGeneratorResponse_Feature; + + + +/* google.protobuf.compiler.Version */ + +UPB_INLINE google_protobuf_compiler_Version* google_protobuf_compiler_Version_new(upb_Arena* arena) { + return (google_protobuf_compiler_Version*)_upb_Message_New(google_protobuf_compiler_Version_msg_init(), arena); +} +UPB_INLINE google_protobuf_compiler_Version* google_protobuf_compiler_Version_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_compiler_Version* ret = google_protobuf_compiler_Version_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_Version_msg_init(), NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_compiler_Version* google_protobuf_compiler_Version_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_compiler_Version* ret = google_protobuf_compiler_Version_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_Version_msg_init(), extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_compiler_Version_serialize(const google_protobuf_compiler_Version* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_Version_msg_init(), 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_compiler_Version_serialize_ex(const google_protobuf_compiler_Version* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_Version_msg_init(), options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_compiler_Version_clear_major(google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 1); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE int32_t google_protobuf_compiler_Version_major(const google_protobuf_compiler_Version* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 1); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_Version_has_major(const google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 1); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_Version_clear_minor(google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 2); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE int32_t google_protobuf_compiler_Version_minor(const google_protobuf_compiler_Version* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 2); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_Version_has_minor(const google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 2); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_Version_clear_patch(google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 3); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE int32_t google_protobuf_compiler_Version_patch(const google_protobuf_compiler_Version* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 3); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_Version_has_patch(const google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 3); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_Version_clear_suffix(google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 4); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE upb_StringView google_protobuf_compiler_Version_suffix(const google_protobuf_compiler_Version* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 4); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_Version_has_suffix(const google_protobuf_compiler_Version* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 4); + return _upb_Message_HasNonExtensionField(msg, &field); +} + +UPB_INLINE void google_protobuf_compiler_Version_set_major(google_protobuf_compiler_Version *msg, int32_t value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 1); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_Version_set_minor(google_protobuf_compiler_Version *msg, int32_t value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 2); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_Version_set_patch(google_protobuf_compiler_Version *msg, int32_t value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 3); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_Version_set_suffix(google_protobuf_compiler_Version *msg, upb_StringView value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_Version_msg_init(), 4); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} + +/* google.protobuf.compiler.CodeGeneratorRequest */ + +UPB_INLINE google_protobuf_compiler_CodeGeneratorRequest* google_protobuf_compiler_CodeGeneratorRequest_new(upb_Arena* arena) { + return (google_protobuf_compiler_CodeGeneratorRequest*)_upb_Message_New(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), arena); +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorRequest* google_protobuf_compiler_CodeGeneratorRequest_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_compiler_CodeGeneratorRequest* ret = google_protobuf_compiler_CodeGeneratorRequest_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_CodeGeneratorRequest_msg_init(), NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorRequest* google_protobuf_compiler_CodeGeneratorRequest_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_compiler_CodeGeneratorRequest* ret = google_protobuf_compiler_CodeGeneratorRequest_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_CodeGeneratorRequest_msg_init(), extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_compiler_CodeGeneratorRequest_serialize(const google_protobuf_compiler_CodeGeneratorRequest* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_compiler_CodeGeneratorRequest_serialize_ex(const google_protobuf_compiler_CodeGeneratorRequest* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_CodeGeneratorRequest_msg_init(), options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorRequest_clear_file_to_generate(google_protobuf_compiler_CodeGeneratorRequest* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 1); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE upb_StringView const* google_protobuf_compiler_CodeGeneratorRequest_file_to_generate(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 1); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (upb_StringView const*)_upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_compiler_CodeGeneratorRequest_file_to_generate_upb_array(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 1); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_compiler_CodeGeneratorRequest_file_to_generate_mutable_upb_array(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 1); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + (upb_Message*)msg, &field, arena); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorRequest_has_file_to_generate(const google_protobuf_compiler_CodeGeneratorRequest* msg) { + size_t size; + google_protobuf_compiler_CodeGeneratorRequest_file_to_generate(msg, &size); + return size != 0; +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorRequest_clear_parameter(google_protobuf_compiler_CodeGeneratorRequest* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 2); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE upb_StringView google_protobuf_compiler_CodeGeneratorRequest_parameter(const google_protobuf_compiler_CodeGeneratorRequest* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 2); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorRequest_has_parameter(const google_protobuf_compiler_CodeGeneratorRequest* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 2); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorRequest_clear_compiler_version(google_protobuf_compiler_CodeGeneratorRequest* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 3); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE const google_protobuf_compiler_Version* google_protobuf_compiler_CodeGeneratorRequest_compiler_version(const google_protobuf_compiler_CodeGeneratorRequest* msg) { + const google_protobuf_compiler_Version* default_val = NULL; + const google_protobuf_compiler_Version* ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 3); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorRequest_has_compiler_version(const google_protobuf_compiler_CodeGeneratorRequest* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 3); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorRequest_clear_proto_file(google_protobuf_compiler_CodeGeneratorRequest* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 15); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE const struct google_protobuf_FileDescriptorProto* const* google_protobuf_compiler_CodeGeneratorRequest_proto_file(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 15); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (const struct google_protobuf_FileDescriptorProto* const*)_upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_compiler_CodeGeneratorRequest_proto_file_upb_array(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 15); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_compiler_CodeGeneratorRequest_proto_file_mutable_upb_array(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 15); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + (upb_Message*)msg, &field, arena); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorRequest_has_proto_file(const google_protobuf_compiler_CodeGeneratorRequest* msg) { + size_t size; + google_protobuf_compiler_CodeGeneratorRequest_proto_file(msg, &size); + return size != 0; +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorRequest_clear_source_file_descriptors(google_protobuf_compiler_CodeGeneratorRequest* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 17); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE const struct google_protobuf_FileDescriptorProto* const* google_protobuf_compiler_CodeGeneratorRequest_source_file_descriptors(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 17); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (const struct google_protobuf_FileDescriptorProto* const*)_upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_compiler_CodeGeneratorRequest_source_file_descriptors_upb_array(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 17); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_compiler_CodeGeneratorRequest_source_file_descriptors_mutable_upb_array(const google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 17); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + (upb_Message*)msg, &field, arena); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorRequest_has_source_file_descriptors(const google_protobuf_compiler_CodeGeneratorRequest* msg) { + size_t size; + google_protobuf_compiler_CodeGeneratorRequest_source_file_descriptors(msg, &size); + return size != 0; +} + +UPB_INLINE upb_StringView* google_protobuf_compiler_CodeGeneratorRequest_mutable_file_to_generate(google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 1); + upb_Array* arr = upb_Message_GetMutableArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (upb_StringView*)_upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE upb_StringView* google_protobuf_compiler_CodeGeneratorRequest_resize_file_to_generate(google_protobuf_compiler_CodeGeneratorRequest* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 1); + return (upb_StringView*)upb_Message_ResizeArrayUninitialized(msg, &field, size, arena); +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorRequest_add_file_to_generate(google_protobuf_compiler_CodeGeneratorRequest* msg, upb_StringView val, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 1); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena); + if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) { + return false; + } + _upb_Array_Set(arr, arr->size - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorRequest_set_parameter(google_protobuf_compiler_CodeGeneratorRequest *msg, upb_StringView value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 2); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorRequest_set_compiler_version(google_protobuf_compiler_CodeGeneratorRequest *msg, google_protobuf_compiler_Version* value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 3); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE struct google_protobuf_compiler_Version* google_protobuf_compiler_CodeGeneratorRequest_mutable_compiler_version(google_protobuf_compiler_CodeGeneratorRequest* msg, upb_Arena* arena) { + struct google_protobuf_compiler_Version* sub = (struct google_protobuf_compiler_Version*)google_protobuf_compiler_CodeGeneratorRequest_compiler_version(msg); + if (sub == NULL) { + sub = (struct google_protobuf_compiler_Version*)_upb_Message_New(google_protobuf_compiler_Version_msg_init(), arena); + if (sub) google_protobuf_compiler_CodeGeneratorRequest_set_compiler_version(msg, sub); + } + return sub; +} +UPB_INLINE struct google_protobuf_FileDescriptorProto** google_protobuf_compiler_CodeGeneratorRequest_mutable_proto_file(google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 15); + upb_Array* arr = upb_Message_GetMutableArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (struct google_protobuf_FileDescriptorProto**)_upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE struct google_protobuf_FileDescriptorProto** google_protobuf_compiler_CodeGeneratorRequest_resize_proto_file(google_protobuf_compiler_CodeGeneratorRequest* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 15); + return (struct google_protobuf_FileDescriptorProto**)upb_Message_ResizeArrayUninitialized(msg, &field, size, arena); +} +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_compiler_CodeGeneratorRequest_add_proto_file(google_protobuf_compiler_CodeGeneratorRequest* msg, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 15); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena); + if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) { + return NULL; + } + struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(google_protobuf_FileDescriptorProto_msg_init(), arena); + if (!arr || !sub) return NULL; + _upb_Array_Set(arr, arr->size - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE struct google_protobuf_FileDescriptorProto** google_protobuf_compiler_CodeGeneratorRequest_mutable_source_file_descriptors(google_protobuf_compiler_CodeGeneratorRequest* msg, size_t* size) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 17); + upb_Array* arr = upb_Message_GetMutableArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (struct google_protobuf_FileDescriptorProto**)_upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE struct google_protobuf_FileDescriptorProto** google_protobuf_compiler_CodeGeneratorRequest_resize_source_file_descriptors(google_protobuf_compiler_CodeGeneratorRequest* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 17); + return (struct google_protobuf_FileDescriptorProto**)upb_Message_ResizeArrayUninitialized(msg, &field, size, arena); +} +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_compiler_CodeGeneratorRequest_add_source_file_descriptors(google_protobuf_compiler_CodeGeneratorRequest* msg, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorRequest_msg_init(), 17); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena); + if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) { + return NULL; + } + struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(google_protobuf_FileDescriptorProto_msg_init(), arena); + if (!arr || !sub) return NULL; + _upb_Array_Set(arr, arr->size - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.compiler.CodeGeneratorResponse */ + +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse* google_protobuf_compiler_CodeGeneratorResponse_new(upb_Arena* arena) { + return (google_protobuf_compiler_CodeGeneratorResponse*)_upb_Message_New(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), arena); +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse* google_protobuf_compiler_CodeGeneratorResponse_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_compiler_CodeGeneratorResponse* ret = google_protobuf_compiler_CodeGeneratorResponse_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_CodeGeneratorResponse_msg_init(), NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse* google_protobuf_compiler_CodeGeneratorResponse_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_compiler_CodeGeneratorResponse* ret = google_protobuf_compiler_CodeGeneratorResponse_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_CodeGeneratorResponse_msg_init(), extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_compiler_CodeGeneratorResponse_serialize(const google_protobuf_compiler_CodeGeneratorResponse* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_compiler_CodeGeneratorResponse_serialize_ex(const google_protobuf_compiler_CodeGeneratorResponse* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_CodeGeneratorResponse_msg_init(), options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_clear_error(google_protobuf_compiler_CodeGeneratorResponse* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 1); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE upb_StringView google_protobuf_compiler_CodeGeneratorResponse_error(const google_protobuf_compiler_CodeGeneratorResponse* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 1); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorResponse_has_error(const google_protobuf_compiler_CodeGeneratorResponse* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 1); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_clear_supported_features(google_protobuf_compiler_CodeGeneratorResponse* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 2); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE uint64_t google_protobuf_compiler_CodeGeneratorResponse_supported_features(const google_protobuf_compiler_CodeGeneratorResponse* msg) { + uint64_t default_val = (uint64_t)0ull; + uint64_t ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 2); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorResponse_has_supported_features(const google_protobuf_compiler_CodeGeneratorResponse* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 2); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_clear_file(google_protobuf_compiler_CodeGeneratorResponse* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 15); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE const google_protobuf_compiler_CodeGeneratorResponse_File* const* google_protobuf_compiler_CodeGeneratorResponse_file(const google_protobuf_compiler_CodeGeneratorResponse* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 15); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (const google_protobuf_compiler_CodeGeneratorResponse_File* const*)_upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_compiler_CodeGeneratorResponse_file_upb_array(const google_protobuf_compiler_CodeGeneratorResponse* msg, size_t* size) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 15); + const upb_Array* arr = upb_Message_GetArray(msg, &field); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_compiler_CodeGeneratorResponse_file_mutable_upb_array(const google_protobuf_compiler_CodeGeneratorResponse* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 15); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + (upb_Message*)msg, &field, arena); + if (size) { + *size = arr ? arr->size : 0; + } + return arr; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorResponse_has_file(const google_protobuf_compiler_CodeGeneratorResponse* msg) { + size_t size; + google_protobuf_compiler_CodeGeneratorResponse_file(msg, &size); + return size != 0; +} + +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_set_error(google_protobuf_compiler_CodeGeneratorResponse *msg, upb_StringView value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 1); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_set_supported_features(google_protobuf_compiler_CodeGeneratorResponse *msg, uint64_t value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 2); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse_File** google_protobuf_compiler_CodeGeneratorResponse_mutable_file(google_protobuf_compiler_CodeGeneratorResponse* msg, size_t* size) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 15); + upb_Array* arr = upb_Message_GetMutableArray(msg, &field); + if (arr) { + if (size) *size = arr->size; + return (google_protobuf_compiler_CodeGeneratorResponse_File**)_upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse_File** google_protobuf_compiler_CodeGeneratorResponse_resize_file(google_protobuf_compiler_CodeGeneratorResponse* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 15); + return (google_protobuf_compiler_CodeGeneratorResponse_File**)upb_Message_ResizeArrayUninitialized(msg, &field, size, arena); +} +UPB_INLINE struct google_protobuf_compiler_CodeGeneratorResponse_File* google_protobuf_compiler_CodeGeneratorResponse_add_file(google_protobuf_compiler_CodeGeneratorResponse* msg, upb_Arena* arena) { + upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_msg_init(), 15); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena); + if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) { + return NULL; + } + struct google_protobuf_compiler_CodeGeneratorResponse_File* sub = (struct google_protobuf_compiler_CodeGeneratorResponse_File*)_upb_Message_New(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), arena); + if (!arr || !sub) return NULL; + _upb_Array_Set(arr, arr->size - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.compiler.CodeGeneratorResponse.File */ + +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse_File* google_protobuf_compiler_CodeGeneratorResponse_File_new(upb_Arena* arena) { + return (google_protobuf_compiler_CodeGeneratorResponse_File*)_upb_Message_New(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), arena); +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse_File* google_protobuf_compiler_CodeGeneratorResponse_File_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_compiler_CodeGeneratorResponse_File* ret = google_protobuf_compiler_CodeGeneratorResponse_File_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_compiler_CodeGeneratorResponse_File* google_protobuf_compiler_CodeGeneratorResponse_File_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_compiler_CodeGeneratorResponse_File* ret = google_protobuf_compiler_CodeGeneratorResponse_File_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_compiler_CodeGeneratorResponse_File_serialize(const google_protobuf_compiler_CodeGeneratorResponse_File* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_compiler_CodeGeneratorResponse_File_serialize_ex(const google_protobuf_compiler_CodeGeneratorResponse_File* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_clear_name(google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 1); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE upb_StringView google_protobuf_compiler_CodeGeneratorResponse_File_name(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 1); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorResponse_File_has_name(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 1); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_clear_insertion_point(google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 2); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE upb_StringView google_protobuf_compiler_CodeGeneratorResponse_File_insertion_point(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 2); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorResponse_File_has_insertion_point(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 2); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_clear_content(google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 15); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE upb_StringView google_protobuf_compiler_CodeGeneratorResponse_File_content(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 15); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorResponse_File_has_content(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 15); + return _upb_Message_HasNonExtensionField(msg, &field); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_clear_generated_code_info(google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 16); + _upb_Message_ClearNonExtensionField(msg, &field); +} +UPB_INLINE const struct google_protobuf_GeneratedCodeInfo* google_protobuf_compiler_CodeGeneratorResponse_File_generated_code_info(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const struct google_protobuf_GeneratedCodeInfo* default_val = NULL; + const struct google_protobuf_GeneratedCodeInfo* ret; + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 16); + _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_compiler_CodeGeneratorResponse_File_has_generated_code_info(const google_protobuf_compiler_CodeGeneratorResponse_File* msg) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 16); + return _upb_Message_HasNonExtensionField(msg, &field); +} + +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_set_name(google_protobuf_compiler_CodeGeneratorResponse_File *msg, upb_StringView value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 1); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_set_insertion_point(google_protobuf_compiler_CodeGeneratorResponse_File *msg, upb_StringView value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 2); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_set_content(google_protobuf_compiler_CodeGeneratorResponse_File *msg, upb_StringView value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 15); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE void google_protobuf_compiler_CodeGeneratorResponse_File_set_generated_code_info(google_protobuf_compiler_CodeGeneratorResponse_File *msg, struct google_protobuf_GeneratedCodeInfo* value) { + const upb_MiniTableField field = *upb_MiniTable_FindFieldByNumber(google_protobuf_compiler_CodeGeneratorResponse_File_msg_init(), 16); + _upb_Message_SetNonExtensionField(msg, &field, &value); +} +UPB_INLINE struct google_protobuf_GeneratedCodeInfo* google_protobuf_compiler_CodeGeneratorResponse_File_mutable_generated_code_info(google_protobuf_compiler_CodeGeneratorResponse_File* msg, upb_Arena* arena) { + struct google_protobuf_GeneratedCodeInfo* sub = (struct google_protobuf_GeneratedCodeInfo*)google_protobuf_compiler_CodeGeneratorResponse_File_generated_code_info(msg); + if (sub == NULL) { + sub = (struct google_protobuf_GeneratedCodeInfo*)_upb_Message_New(google_protobuf_GeneratedCodeInfo_msg_init(), arena); + if (sub) google_protobuf_compiler_CodeGeneratorResponse_File_set_generated_code_info(msg, sub); + } + return sub; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif /* GOOGLE_PROTOBUF_COMPILER_PLUGIN_PROTO_UPB_H_ */
diff --git a/upbc/subprocess.cc b/upbc/subprocess.cc new file mode 100644 index 0000000..e0c2604 --- /dev/null +++ b/upbc/subprocess.cc
@@ -0,0 +1,465 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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. + +// Shamelessly copied from the protobuf compiler's subprocess.cc +// except this version passes strings instead of Messages. + +#include "upbc/subprocess.h" + +#include <algorithm> +#include <cstring> +#include <iostream> + +#ifndef _MSVC_LANG +#include <errno.h> +#include <signal.h> +#include <sys/select.h> +#include <sys/wait.h> +#endif + +#include "absl/log/absl_log.h" +#include "absl/strings/substitute.h" + +// Must be last. +#include "upb/port/def.inc" + +namespace upbc { + +namespace { +char* portable_strdup(const char* s) { + char* ns = (char*)malloc(strlen(s) + 1); + if (ns != nullptr) { + strcpy(ns, s); + } + return ns; +} +} // namespace + +#ifdef _WIN32 + +static void CloseHandleOrDie(HANDLE handle) { + if (!CloseHandle(handle)) { + ABSL_LOG(FATAL) << "CloseHandle: " + << Subprocess::Win32ErrorMessage(GetLastError()); + } +} + +Subprocess::Subprocess() + : process_start_error_(ERROR_SUCCESS), + child_handle_(nullptr), + child_stdin_(nullptr), + child_stdout_(nullptr) {} + +Subprocess::~Subprocess() { + if (child_stdin_ != nullptr) { + CloseHandleOrDie(child_stdin_); + } + if (child_stdout_ != nullptr) { + CloseHandleOrDie(child_stdout_); + } +} + +void Subprocess::Start(const std::string& program, SearchMode search_mode) { + // Create the pipes. + HANDLE stdin_pipe_read; + HANDLE stdin_pipe_write; + HANDLE stdout_pipe_read; + HANDLE stdout_pipe_write; + + if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, nullptr, 0)) { + ABSL_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); + } + if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, nullptr, 0)) { + ABSL_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); + } + + // Make child side of the pipes inheritable. + if (!SetHandleInformation(stdin_pipe_read, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT)) { + ABSL_LOG(FATAL) << "SetHandleInformation: " + << Win32ErrorMessage(GetLastError()); + } + if (!SetHandleInformation(stdout_pipe_write, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT)) { + ABSL_LOG(FATAL) << "SetHandleInformation: " + << Win32ErrorMessage(GetLastError()); + } + + // Setup STARTUPINFO to redirect handles. + STARTUPINFOA startup_info; + ZeroMemory(&startup_info, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = stdin_pipe_read; + startup_info.hStdOutput = stdout_pipe_write; + startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + if (startup_info.hStdError == INVALID_HANDLE_VALUE) { + ABSL_LOG(FATAL) << "GetStdHandle: " << Win32ErrorMessage(GetLastError()); + } + + // Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'. + // Using a malloc'ed string because CreateProcess() can mutate its second + // parameter. + char* command_line = + portable_strdup(("cmd.exe /c \"" + program + "\"").c_str()); + + // Create the process. + PROCESS_INFORMATION process_info; + + if (CreateProcessA((search_mode == SEARCH_PATH) ? nullptr : program.c_str(), + (search_mode == SEARCH_PATH) ? command_line : nullptr, + nullptr, // process security attributes + nullptr, // thread security attributes + TRUE, // inherit handles? + 0, // obscure creation flags + nullptr, // environment (inherit from parent) + nullptr, // current directory (inherit from parent) + &startup_info, &process_info)) { + child_handle_ = process_info.hProcess; + CloseHandleOrDie(process_info.hThread); + child_stdin_ = stdin_pipe_write; + child_stdout_ = stdout_pipe_read; + } else { + process_start_error_ = GetLastError(); + CloseHandleOrDie(stdin_pipe_write); + CloseHandleOrDie(stdout_pipe_read); + } + + CloseHandleOrDie(stdin_pipe_read); + CloseHandleOrDie(stdout_pipe_write); + free(command_line); +} + +bool Subprocess::Communicate(const std::string& input_data, + std::string* output_data, std::string* error) { + if (process_start_error_ != ERROR_SUCCESS) { + *error = Win32ErrorMessage(process_start_error_); + return false; + } + + GOOGLE_CHECK(child_handle_ != nullptr) << "Must call Start() first."; + + int input_pos = 0; + + while (child_stdout_ != nullptr) { + HANDLE handles[2]; + int handle_count = 0; + + if (child_stdin_ != nullptr) { + handles[handle_count++] = child_stdin_; + } + if (child_stdout_ != nullptr) { + handles[handle_count++] = child_stdout_; + } + + DWORD wait_result = + WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE); + + HANDLE signaled_handle = nullptr; + if (wait_result >= WAIT_OBJECT_0 && + wait_result < WAIT_OBJECT_0 + handle_count) { + signaled_handle = handles[wait_result - WAIT_OBJECT_0]; + } else if (wait_result == WAIT_FAILED) { + ABSL_LOG(FATAL) << "WaitForMultipleObjects: " + << Win32ErrorMessage(GetLastError()); + } else { + ABSL_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: " + << wait_result; + } + + if (signaled_handle == child_stdin_) { + DWORD n; + if (!WriteFile(child_stdin_, input_data.data() + input_pos, + input_data.size() - input_pos, &n, nullptr)) { + // Child closed pipe. Presumably it will report an error later. + // Pretend we're done for now. + input_pos = input_data.size(); + } else { + input_pos += n; + } + + if (input_pos == input_data.size()) { + // We're done writing. Close. + CloseHandleOrDie(child_stdin_); + child_stdin_ = nullptr; + } + } else if (signaled_handle == child_stdout_) { + char buffer[4096]; + DWORD n; + + if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, nullptr)) { + // We're done reading. Close. + CloseHandleOrDie(child_stdout_); + child_stdout_ = nullptr; + } else { + output_data->append(buffer, n); + } + } + } + + if (child_stdin_ != nullptr) { + // Child did not finish reading input before it closed the output. + // Presumably it exited with an error. + CloseHandleOrDie(child_stdin_); + child_stdin_ = nullptr; + } + + DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE); + + if (wait_result == WAIT_FAILED) { + ABSL_LOG(FATAL) << "WaitForSingleObject: " + << Win32ErrorMessage(GetLastError()); + } else if (wait_result != WAIT_OBJECT_0) { + ABSL_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: " + << wait_result; + } + + DWORD exit_code; + if (!GetExitCodeProcess(child_handle_, &exit_code)) { + ABSL_LOG(FATAL) << "GetExitCodeProcess: " + << Win32ErrorMessage(GetLastError()); + } + + CloseHandleOrDie(child_handle_); + child_handle_ = nullptr; + + if (exit_code != 0) { + *error = absl::Substitute("Plugin failed with status code $0.", exit_code); + return false; + } + + return true; +} + +std::string Subprocess::Win32ErrorMessage(DWORD error_code) { + char* message; + + // WTF? + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR)&message, // NOT A BUG! + 0, nullptr); + + std::string result = message; + LocalFree(message); + return result; +} + +// =================================================================== + +#else // _WIN32 + +Subprocess::Subprocess() + : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {} + +Subprocess::~Subprocess() { + if (child_stdin_ != -1) { + close(child_stdin_); + } + if (child_stdout_ != -1) { + close(child_stdout_); + } +} + +void Subprocess::Start(const std::string& program, SearchMode search_mode) { + // Note that we assume that there are no other threads, thus we don't have to + // do crazy stuff like using socket pairs or avoiding libc locks. + + // [0] is read end, [1] is write end. + int stdin_pipe[2]; + int stdout_pipe[2]; + + int p0 = pipe(stdin_pipe); + int p1 = pipe(stdout_pipe); + UPB_ASSERT(p0 != -1); + UPB_ASSERT(p1 != -1); + + char* argv[2] = {portable_strdup(program.c_str()), nullptr}; + + child_pid_ = fork(); + if (child_pid_ == -1) { + std::cerr << "fork: " << strerror(errno); + } else if (child_pid_ == 0) { + // We are the child. + dup2(stdin_pipe[0], STDIN_FILENO); + dup2(stdout_pipe[1], STDOUT_FILENO); + + close(stdin_pipe[0]); + close(stdin_pipe[1]); + close(stdout_pipe[0]); + close(stdout_pipe[1]); + + switch (search_mode) { + case SEARCH_PATH: + execvp(argv[0], argv); + break; + case EXACT_NAME: + execv(argv[0], argv); + break; + } + + // Write directly to STDERR_FILENO to avoid stdio code paths that may do + // stuff that is unsafe here. + int ignored; + ignored = write(STDERR_FILENO, argv[0], strlen(argv[0])); + const char* message = + ": program not found or is not executable\n" + "Please specify a program using absolute path or make sure " + "the program is available in your PATH system variable\n"; + ignored = write(STDERR_FILENO, message, strlen(message)); + (void)ignored; + + // Must use _exit() rather than exit() to avoid flushing output buffers + // that will also be flushed by the parent. + _exit(1); + } else { + free(argv[0]); + + close(stdin_pipe[0]); + close(stdout_pipe[1]); + + child_stdin_ = stdin_pipe[1]; + child_stdout_ = stdout_pipe[0]; + } +} + +bool Subprocess::Communicate(const std::string& input_data, + std::string* output_data, std::string* error) { + if (child_stdin_ == -1) { + std::cerr << "Must call Start() first." << std::endl; + UPB_ASSERT(child_stdin_ != -1); + } + + // The "sighandler_t" typedef is GNU-specific, so define our own. + typedef void SignalHandler(int); + + // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us. + SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN); + + int input_pos = 0; + int max_fd = std::max(child_stdin_, child_stdout_); + + while (child_stdout_ != -1) { + fd_set read_fds; + fd_set write_fds; + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + if (child_stdout_ != -1) { + FD_SET(child_stdout_, &read_fds); + } + if (child_stdin_ != -1) { + FD_SET(child_stdin_, &write_fds); + } + + if (select(max_fd + 1, &read_fds, &write_fds, nullptr, nullptr) < 0) { + if (errno == EINTR) { + // Interrupted by signal. Try again. + continue; + } else { + std::cerr << "select: " << strerror(errno) << std::endl; + UPB_ASSERT(0); + } + } + + if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) { + int n = write(child_stdin_, input_data.data() + input_pos, + input_data.size() - input_pos); + if (n < 0) { + // Child closed pipe. Presumably it will report an error later. + // Pretend we're done for now. + input_pos = input_data.size(); + } else { + input_pos += n; + } + + if (input_pos == (int)input_data.size()) { + // We're done writing. Close. + close(child_stdin_); + child_stdin_ = -1; + } + } + + if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) { + char buffer[4096]; + int n = read(child_stdout_, buffer, sizeof(buffer)); + + if (n > 0) { + output_data->append(buffer, (size_t)n); + } else { + // We're done reading. Close. + close(child_stdout_); + child_stdout_ = -1; + } + } + } + + if (child_stdin_ != -1) { + // Child did not finish reading input before it closed the output. + // Presumably it exited with an error. + close(child_stdin_); + child_stdin_ = -1; + } + + int status; + while (waitpid(child_pid_, &status, 0) == -1) { + if (errno != EINTR) { + std::cerr << "waitpid: " << strerror(errno) << std::endl; + UPB_ASSERT(0); + } + } + + // Restore SIGPIPE handling. + signal(SIGPIPE, old_pipe_handler); + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) { + int error_code = WEXITSTATUS(status); + *error = + absl::Substitute("Plugin failed with status code $0.", error_code); + return false; + } + } else if (WIFSIGNALED(status)) { + int signal = WTERMSIG(status); + *error = absl::Substitute("Plugin killed by signal $0.", signal); + return false; + } else { + *error = "Neither WEXITSTATUS nor WTERMSIG is true?"; + return false; + } + + return true; +} + +#endif // !_WIN32 + +} // namespace upbc
diff --git a/upbc/subprocess.h b/upbc/subprocess.h new file mode 100644 index 0000000..b30b5bf --- /dev/null +++ b/upbc/subprocess.h
@@ -0,0 +1,102 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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. + +// Shamelessly copied from the protobuf compiler's subprocess.h +// except this version passes strings instead of Messages. + +#ifndef THIRD_PARTY_UPB_UPBC_H_ +#define THIRD_PARTY_UPB_UPBC_H_ + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // right... +#endif +#include <windows.h> +#else // _WIN32 +#include <sys/types.h> +#include <unistd.h> +#endif // !_WIN32 +#include <string> + +namespace upbc { + +// Utility class for launching sub-processes. +class Subprocess { + public: + Subprocess(); + ~Subprocess(); + + enum SearchMode { + SEARCH_PATH, // Use PATH environment variable. + EXACT_NAME // Program is an exact file name; don't use the PATH. + }; + + // Start the subprocess. Currently we don't provide a way to specify + // arguments as protoc plugins don't have any. + void Start(const std::string& program, SearchMode search_mode); + + // Pipe the input message to the subprocess's stdin, then close the pipe. + // Meanwhile, read from the subprocess's stdout and copy into *output. + // All this is done carefully to avoid deadlocks. + // Returns true if successful. On any sort of error, returns false and sets + // *error to a description of the problem. + bool Communicate(const std::string& input_data, std::string* output_data, + std::string* error); + +#ifdef _WIN32 + // Given an error code, returns a human-readable error message. This is + // defined here so that CommandLineInterface can share it. + static std::string Win32ErrorMessage(DWORD error_code); +#endif + + private: +#ifdef _WIN32 + DWORD process_start_error_; + HANDLE child_handle_; + + // The file handles for our end of the child's pipes. We close each and + // set it to NULL when no longer needed. + HANDLE child_stdin_; + HANDLE child_stdout_; + +#else // _WIN32 + pid_t child_pid_; + + // The file descriptors for our end of the child's pipes. We close each and + // set it to -1 when no longer needed. + int child_stdin_; + int child_stdout_; + +#endif // !_WIN32 +}; + +} // namespace upbc + +#endif // THIRD_PARTY_UPB_UPBC_H_
diff --git a/upbc/upbc_so.c b/upbc/upbc_so.c new file mode 100644 index 0000000..1cfc04b --- /dev/null +++ b/upbc/upbc_so.c
@@ -0,0 +1,34 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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. + +// These headers form a spanning tree for the upbc defs needed by FFI layers. + +#include "upbc/get_used_fields.h" +#include "upbc/upbdev.h"
diff --git a/upbc/upbdev.c b/upbc/upbdev.c new file mode 100644 index 0000000..ffccd07 --- /dev/null +++ b/upbc/upbdev.c
@@ -0,0 +1,136 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 "upbc/upbdev.h" + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#else // _WIN32 +#include <unistd.h> +#endif // !_WIN32 + +#include "google/protobuf/compiler/plugin.upb.h" +#include "google/protobuf/compiler/plugin.upbdefs.h" +#include "upb/base/status.h" +#include "upb/json/decode.h" +#include "upb/json/encode.h" +#include "upb/mem/arena.h" +#include "upbc/code_generator_request.h" +#include "upbc/code_generator_request.upb.h" +#include "upbc/code_generator_request.upbdefs.h" + +static google_protobuf_compiler_CodeGeneratorResponse* upbc_JsonDecode( + const char* data, size_t size, upb_Arena* arena, upb_Status* status) { + google_protobuf_compiler_CodeGeneratorResponse* response = + google_protobuf_compiler_CodeGeneratorResponse_new(arena); + + upb_DefPool* s = upb_DefPool_New(); + const upb_MessageDef* m = google_protobuf_compiler_CodeGeneratorResponse_getmsgdef(s); + + (void)upb_JsonDecode(data, size, response, m, s, 0, arena, status); + if (!upb_Status_IsOk(status)) return NULL; + + upb_DefPool_Free(s); + + return response; +} + +static upb_StringView upbc_JsonEncode(const upbc_CodeGeneratorRequest* request, + upb_Arena* arena, upb_Status* status) { + upb_StringView out = {.data = NULL, .size = 0}; + + upb_DefPool* s = upb_DefPool_New(); + const upb_MessageDef* m = upbc_CodeGeneratorRequest_getmsgdef(s); + const int options = upb_JsonEncode_FormatEnumsAsIntegers; + + out.size = upb_JsonEncode(request, m, s, options, NULL, 0, status); + if (!upb_Status_IsOk(status)) goto done; + + char* data = (char*)upb_Arena_Malloc(arena, out.size + 1); + + (void)upb_JsonEncode(request, m, s, options, data, out.size + 1, status); + if (!upb_Status_IsOk(status)) goto done; + + out.data = (const char*)data; + +done: + upb_DefPool_Free(s); + return out; +} + +upb_StringView upbdev_ProcessInput(const char* buf, size_t size, + upb_Arena* arena, upb_Status* status) { + upb_StringView out = {.data = NULL, .size = 0}; + + google_protobuf_compiler_CodeGeneratorRequest* inner_request = + google_protobuf_compiler_CodeGeneratorRequest_parse(buf, size, arena); + + const upbc_CodeGeneratorRequest* outer_request = + upbc_MakeCodeGeneratorRequest(inner_request, arena, status); + if (!upb_Status_IsOk(status)) return out; + + return upbc_JsonEncode(outer_request, arena, status); +} + +upb_StringView upbdev_ProcessOutput(const char* buf, size_t size, + upb_Arena* arena, upb_Status* status) { + upb_StringView out = {.data = NULL, .size = 0}; + + const google_protobuf_compiler_CodeGeneratorResponse* response = + upbc_JsonDecode(buf, size, arena, status); + if (!upb_Status_IsOk(status)) return out; + + out.data = google_protobuf_compiler_CodeGeneratorResponse_serialize(response, arena, + &out.size); + return out; +} + +void upbdev_ProcessStdout(const char* buf, size_t size, upb_Arena* arena, + upb_Status* status) { + const upb_StringView sv = upbdev_ProcessOutput(buf, size, arena, status); + if (!upb_Status_IsOk(status)) return; + + const char* ptr = sv.data; + size_t len = sv.size; + while (len) { + int n = write(1, ptr, len); + if (n > 0) { + ptr += n; + len -= n; + } + } +} + +upb_Arena* upbdev_Arena_New() { return upb_Arena_New(); } + +void upbdev_Status_Clear(upb_Status* status) { upb_Status_Clear(status); }
diff --git a/upbc/upbdev.h b/upbc/upbdev.h new file mode 100644 index 0000000..047a1be --- /dev/null +++ b/upbc/upbdev.h
@@ -0,0 +1,71 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS 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 UPBC_UPBDEV_H_ +#define UPBC_UPBDEV_H_ + +#include "upb/base/status.h" +#include "upb/base/string_view.h" +#include "upb/mem/arena.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +// Consume |buf|, deserialize it to a Code_Generator_Request proto, construct a +// upbc_Code_Generator_Request, and return it as a JSON-encoded string. +UPB_API upb_StringView upbdev_ProcessInput(const char* buf, size_t size, + upb_Arena* arena, + upb_Status* status); + +// Decode |buf| from JSON, serialize to wire format, and return it. +UPB_API upb_StringView upbdev_ProcessOutput(const char* buf, size_t size, + upb_Arena* arena, + upb_Status* status); + +// Decode |buf| from JSON, serialize to wire format, and write it to stdout. +UPB_API void upbdev_ProcessStdout(const char* buf, size_t size, + upb_Arena* arena, upb_Status* status); + +// The following wrappers allow the protoc plugins to call the above functions +// without pulling in the entire pb_runtime library. +UPB_API upb_Arena* upbdev_Arena_New(void); +UPB_API void upbdev_Status_Clear(upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif // UPBC_UPBDEV_H_