| // Protocol Buffers - Google's data interchange format |
| // Copyright 2023 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 |
| |
| #include <cstddef> |
| #include <string> |
| |
| #include "google/protobuf/descriptor.upb.h" |
| #include "absl/strings/escaping.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/str_join.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/span.h" |
| #include "google/protobuf/compiler/code_generator.h" |
| #include "google/protobuf/io/printer.h" |
| #include "upb/mem/arena.hpp" |
| #include "upb/reflection/def.hpp" |
| #include "upb/util/def_to_proto.h" |
| #include "upb_generator/common/names.h" |
| #include "upb_generator/minitable/names.h" |
| #include "upb_generator/reflection/context.h" |
| #include "upb_generator/reflection/header.h" |
| #include "upb_generator/reflection/names.h" |
| |
| namespace upb::generator::reflection { |
| namespace { |
| |
| using Sub = google::protobuf::io::Printer::Sub; |
| |
| static std::string DefSourceFilename(upb::FileDefPtr file) { |
| return StripExtension(file.name()) + ".upbdefs.c"; |
| } |
| |
| void WriteIncludes(upb::FileDefPtr file, Context& ctx) { |
| ctx.Emit( |
| { |
| {"def_header_filename", DefHeaderFilename(file)}, |
| {"mini_table_header_filename", MiniTableHeaderFilename(file.name())}, |
| }, |
| R"( |
| #include "upb/reflection/def.h" |
| #include "$def_header_filename$" |
| #include "$mini_table_header_filename$" |
| )"); |
| } |
| |
| void WriteDefPoolFwdDecls(upb::FileDefPtr file, Context& ctx) { |
| if (file.dependency_count() == 0) return; |
| |
| for (int i = 0; i < file.dependency_count(); i++) { |
| ctx.Emit( |
| {{"dllexport_decl", ctx.options().dllexport_decl}, |
| {"def_init_symbol", ReflectionFileSymbol(file.dependency(i).name())}}, |
| R"cc( |
| extern$ dllexport_decl$ _upb_DefPool_Init $def_init_symbol$; |
| )cc"); |
| } |
| |
| ctx.Emit("\n"); |
| } |
| |
| void WriteStringArrayLine(absl::string_view data, Context& ctx) { |
| std::string line = absl::StrJoin(data, ", ", [](std::string* out, char ch) { |
| absl::StrAppendFormat(out, "'%v'", |
| absl::CEscape(absl::string_view(&ch, 1))); |
| }); |
| ctx.Emit({{"line", line}}, |
| R"cc( |
| $line$, |
| )cc"); |
| } |
| |
| void WriteStringArray(absl::string_view data, Context& ctx) { |
| const size_t kMaxLineLength = 12; |
| for (size_t i = 0; i < data.size(); i += kMaxLineLength) { |
| WriteStringArrayLine(data.substr(i, kMaxLineLength), ctx); |
| } |
| } |
| |
| void WriteDescriptor(upb::FileDefPtr file, Context& ctx) { |
| 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); |
| |
| ctx.Emit({{"serialized_size", file_data.size()}, |
| {"contents", [&] { WriteStringArray(file_data, ctx); }}}, |
| R"cc( |
| static const char descriptor[$serialized_size$] = { |
| $contents$, |
| }; |
| )cc"); |
| ctx.Emit("\n"); |
| } |
| |
| void WriteDependencies(upb::FileDefPtr file, Context& ctx) { |
| auto write_dep = [&](int i) { |
| ctx.Emit({{"sym", ReflectionFileSymbol(file.dependency(i).name())}}, |
| R"cc( |
| &$sym$, |
| )cc"); |
| }; |
| |
| auto write_deps = [&] { |
| for (int i = 0; i < file.dependency_count(); i++) write_dep(i); |
| }; |
| |
| ctx.Emit({{"dep_count", file.dependency_count() + 1}, |
| {google::protobuf::io::Printer::Sub("deps", write_deps).WithSuffix(",")}}, |
| R"cc( |
| static _upb_DefPool_Init *deps[$dep_count$] = { |
| $deps$, |
| NULL, |
| }; |
| )cc"); |
| ctx.Emit("\n"); |
| } |
| |
| void WriteDefPoolInitStruct(upb::FileDefPtr file, Context& ctx) { |
| ctx.Emit( |
| { |
| {"defpool_init_name", ReflectionFileSymbol(file.name())}, |
| {"file_name", file.name()}, |
| {"mini_table_file_var_name", MiniTableFileVarName(file.name())}, |
| }, |
| R"cc( |
| _upb_DefPool_Init $defpool_init_name$ = { |
| deps, |
| &$mini_table_file_var_name$, |
| "$file_name$", |
| UPB_STRINGVIEW_INIT(descriptor, sizeof(descriptor)), |
| }; |
| )cc"); |
| } |
| |
| void WriteDefPoolInit(upb::FileDefPtr file, Context& ctx) { |
| WriteDefPoolFwdDecls(file, ctx); |
| WriteDescriptor(file, ctx); |
| WriteDependencies(file, ctx); |
| WriteDefPoolInitStruct(file, ctx); |
| } |
| |
| void WriteDefSource(upb::FileDefPtr file, Context& ctx) { |
| ctx.Emit( |
| { |
| {Sub("file_warning", FileWarning(file.name())).WithSuffix(";")}, |
| {Sub("includes", [&] { WriteIncludes(file, ctx); }).WithSuffix(";")}, |
| {Sub("def_pool_init", [&] { WriteDefPoolInit(file, ctx); }) |
| .WithSuffix(";")}, |
| }, |
| R"cc( |
| $file_warning$; |
| $includes$; |
| |
| $def_pool_init$; |
| )cc"); |
| } |
| |
| } // namespace |
| |
| void GenerateReflectionSource(upb::FileDefPtr file, const Options& options, |
| google::protobuf::compiler::GeneratorContext* context) { |
| Context c_context(options, context->Open(DefSourceFilename(file))); |
| WriteDefSource(file, c_context); |
| } |
| |
| } // namespace upb::generator::reflection |