|
|
|
// Protocol Buffers - Google's data interchange format
|
|
|
|
// Copyright 2024 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
|
|
|
|
|
|
|
|
#ifndef GOOGLE_PROTOBUF_COMPILER_HPB_CONTEXT_H__
|
|
|
|
#define GOOGLE_PROTOBUF_COMPILER_HPB_CONTEXT_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 "absl/types/source_location.h"
|
|
|
|
#include "absl/types/span.h"
|
|
|
|
#include "google/protobuf/descriptor.h"
|
|
|
|
#include "google/protobuf/io/printer.h"
|
|
|
|
#include "google/protobuf/io/zero_copy_stream.h"
|
|
|
|
#include "upb/reflection/def.hpp"
|
|
|
|
#include "upb_generator/common/cpp_to_upb_def.h"
|
|
|
|
|
|
|
|
namespace google::protobuf::hpb_generator {
|
|
|
|
|
|
|
|
enum class Backend { UPB, CPP };
|
|
|
|
|
|
|
|
struct Options {
|
|
|
|
Backend backend = Backend::UPB;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This Context object will be used throughout hpb generation.
|
|
|
|
* It is a thin wrapper around an io::Printer and can be easily extended
|
|
|
|
* to support more options.
|
|
|
|
*
|
|
|
|
* Expected usage is:
|
|
|
|
* SomeGenerationFunc(..., Context& context) {
|
|
|
|
* context.Emit({{"some_key", some_computed_val}}, R"cc(
|
|
|
|
* // hpb gencode ...
|
|
|
|
* )cc);
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
class Context final {
|
|
|
|
public:
|
|
|
|
Context(const FileDescriptor* file, io::ZeroCopyOutputStream* stream,
|
|
|
|
const Options& options)
|
|
|
|
: stream_(stream), printer_(stream_), options_(options) {
|
|
|
|
BuildDefPool(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Emit(absl::Span<const io::Printer::Sub> vars, absl::string_view format,
|
|
|
|
absl::SourceLocation loc = absl::SourceLocation::current()) {
|
|
|
|
printer_.Emit(vars, format, loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Emit(absl::string_view format,
|
|
|
|
absl::SourceLocation loc = absl::SourceLocation::current()) {
|
|
|
|
printer_.Emit(format, loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: b/373438292 - Remove EmitLegacy in favor of Emit.
|
|
|
|
// This is an interim solution while we migrate from Output to io::Printer
|
|
|
|
template <class... Arg>
|
|
|
|
void EmitLegacy(absl::string_view format, const Arg&... arg) {
|
|
|
|
auto res = absl::Substitute(format, arg...);
|
|
|
|
printer_.Emit(res, absl::SourceLocation::current());
|
|
|
|
}
|
|
|
|
|
|
|
|
const Options& options() { return options_; }
|
|
|
|
io::Printer& printer() { return printer_; }
|
|
|
|
|
|
|
|
inline std::string GetLayoutIndex(const FieldDescriptor* field) {
|
|
|
|
return absl::StrCat(
|
|
|
|
upb::generator::FindBaseFieldDef(pool_, field).layout_index());
|
|
|
|
}
|
|
|
|
|
|
|
|
Context(const Context&) = delete;
|
|
|
|
Context& operator=(const Context&) = delete;
|
|
|
|
Context(Context&&) = delete;
|
|
|
|
Context& operator=(Context&&) = delete;
|
|
|
|
|
|
|
|
private:
|
|
|
|
inline void BuildDefPool(const FileDescriptor* file) {
|
|
|
|
upb::generator::AddFile(file, &pool_);
|
|
|
|
}
|
|
|
|
|
|
|
|
io::ZeroCopyOutputStream* stream_;
|
|
|
|
io::Printer printer_;
|
|
|
|
const Options& options_;
|
|
|
|
upb::DefPool pool_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: b/373438292 - re-house these 4 legacy funcs post io::Printer move
|
|
|
|
inline std::string ToCIdent(absl::string_view str) {
|
|
|
|
return absl::StrReplaceAll(str, {{".", "_"}, {"/", "_"}, {"-", "_"}});
|
|
|
|
}
|
|
|
|
|
|
|
|
inline std::string ToPreproc(absl::string_view str) {
|
|
|
|
return absl::AsciiStrToUpper(ToCIdent(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void EmitFileWarning(const google::protobuf::FileDescriptor* file, Context& ctx) {
|
|
|
|
ctx.EmitLegacy(
|
|
|
|
R"cc(
|
|
|
|
/* This file was generated by hpb_generator (Handle Protobuf) "
|
|
|
|
from the input
|
|
|
|
* file:
|
|
|
|
*
|
|
|
|
* $0
|
|
|
|
*
|
|
|
|
* Do not edit -- your changes will be discarded when the file is
|
|
|
|
* regenerated. */
|
|
|
|
)cc",
|
|
|
|
file->name());
|
|
|
|
ctx.Emit("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: b/346865271 append ::hpb instead of ::protos after namespace swap
|
|
|
|
inline std::string NamespaceFromPackageName(absl::string_view package_name) {
|
|
|
|
return absl::StrCat(absl::StrReplaceAll(package_name, {{".", "::"}}),
|
|
|
|
"::protos");
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void WrapNamespace(const google::protobuf::FileDescriptor* file, Context& ctx, T&& body) {
|
|
|
|
if (file->package().empty()) {
|
|
|
|
body();
|
|
|
|
} else {
|
|
|
|
ctx.Emit(
|
|
|
|
{
|
|
|
|
{"body", body},
|
|
|
|
{"namespace", NamespaceFromPackageName(file->package())},
|
|
|
|
},
|
|
|
|
R"cc(
|
|
|
|
namespace $namespace$ {
|
|
|
|
|
|
|
|
$body$
|
|
|
|
|
|
|
|
} // namespace $namespace$
|
|
|
|
)cc");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace protobuf
|
|
|
|
} // namespace google::hpb_generator
|
|
|
|
|
|
|
|
#endif // GOOGLE_PROTOBUF_COMPILER_HPB_CONTEXT_H__
|