| // 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()}, | |
| {"defpool_init_name", ReflectionFileSymbol(file.name())}, | |
| {"contents", [&] { WriteStringArray(file_data, ctx); }}}, | |
| R"cc( | |
| static const char descriptor_$defpool_init_name$[$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}, | |
| {"defpool_init_name", ReflectionFileSymbol(file.name())}, | |
| {google::protobuf::io::Printer::Sub("deps", write_deps).WithSuffix(",")}}, | |
| R"cc( | |
| static _upb_DefPool_Init* deps_$defpool_init_name$[$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_$defpool_init_name$, | |
| &$mini_table_file_var_name$, | |
| "$file_name$", | |
| UPB_STRINGVIEW_INIT(descriptor_$defpool_init_name$, | |
| sizeof(descriptor_$defpool_init_name$)), | |
| }; | |
| )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 |