1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
// 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__
|