blob: a573f1f57554ee5f857db33635824b12134c158f [file] [log] [blame]
// 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