Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

381 lines
14 KiB

/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "protos_generator/gen_messages.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.h"
#include "protos_generator/gen_accessors.h"
#include "protos_generator/gen_extensions.h"
#include "protos_generator/gen_utils.h"
#include "protos_generator/output.h"
#include "upbc/common.h"
#include "upbc/file_layout.h"
namespace protos_generator {
namespace protobuf = ::google::protobuf;
void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor,
Output& output);
void WriteModelPublicDeclaration(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
void WriteExtensionIdentifiersInClassHeader(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
void WriteModelProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output);
void WriteModelCProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output);
void WriteInternalForwardDeclarationsInHeader(
const protobuf::Descriptor* message, Output& output);
void WriteDefaultInstanceHeader(const protobuf::Descriptor* message,
Output& output);
void WriteExtensionIdentifiersImplementation(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output);
// Writes message class declarations into .upb.proto.h.
//
// For each proto Foo, FooAccess and FooProxy/FooCProxy are generated
// that are exposed to users as Foo , Ptr<Foo> and Ptr<const Foo>.
void WriteMessageClassDeclarations(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
if (IsMapEntryMessage(descriptor)) {
// Skip map entry generation. Low level accessors for maps are
// generated that don't require a separate map type.
return;
}
// Forward declaration of Proto Class for GCC handling of free friend method.
output("class $0;", ClassName(descriptor));
output("namespace internal {\n");
WriteModelAccessDeclaration(descriptor, output);
output("\n");
WriteInternalForwardDeclarationsInHeader(descriptor, output);
output("\n");
output("} // namespace internal\n");
WriteModelPublicDeclaration(descriptor, file_exts, output);
output("namespace internal {\n");
WriteModelProxyDeclaration(descriptor, output);
WriteModelCProxyDeclaration(descriptor, output);
output("} // namespace internal\n");
}
void WriteModelAccessDeclaration(const protobuf::Descriptor* descriptor,
Output& output) {
output(
R"cc(
class $0Access {
public:
$0Access() {}
$0Access($1* msg, upb_Arena* arena) : msg_(msg), arena_(arena) {} // NOLINT
$0Access(const $1* msg, upb_Arena* arena)
: msg_(const_cast<$1*>(msg)), arena_(arena) {} // NOLINT
void* GetInternalArena() const { return arena_; }
)cc",
ClassName(descriptor), MessageName(descriptor));
WriteFieldAccessorsInHeader(descriptor, output);
output.Indent();
output(
R"cc(
private:
void* msg() const { return msg_; }
friend class $2;
friend class $0Proxy;
friend class $0CProxy;
friend void* ::protos::internal::GetInternalMsg<$2>(const $2& message);
friend void* ::protos::internal::GetInternalMsg<$2>(
const ::protos::Ptr<$2>& message);
$1* msg_;
upb_Arena* arena_;
)cc",
ClassName(descriptor), MessageName(descriptor),
QualifiedClassName(descriptor));
output.Outdent();
output("};\n");
}
void WriteModelPublicDeclaration(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
output(
R"cc(
class $0 final : private internal::$0Access {
public:
using Access = internal::$0Access;
using Proxy = internal::$0Proxy;
using CProxy = internal::$0CProxy;
$0();
$0(const $0& m) = delete;
$0& operator=(const $0& m) = delete;
$0($0&& m)
: Access(m.msg_, m.arena_),
owned_arena_(std::move(m.owned_arena_)) {}
$0& operator=($0&& m) {
msg_ = m.msg_;
arena_ = m.arena_;
m.msg_ = nullptr;
m.arena_ = nullptr;
owned_arena_ = std::move(m.owned_arena_);
return *this;
}
)cc",
ClassName(descriptor));
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessage, output);
WriteDefaultInstanceHeader(descriptor, output);
WriteExtensionIdentifiersInClassHeader(descriptor, file_exts, output);
output.Indent();
output.Indent();
if (descriptor->extension_range_count()) {
// for typetrait checking
output("using ExtendableType = $0;\n", ClassName(descriptor));
}
// Note: free function friends that are templates such as ::protos::Parse
// require explicit <$2> type parameter in declaration to be able to compile
// with gcc otherwise the compiler will fail with
// "has not been declared within namespace" error. Even though there is a
// namespace qualifier, cross namespace matching fails.
output(
R"cc(
static const upb_MiniTable* minitable();
using $0Access::GetInternalArena;
private:
$0(upb_Message* msg, upb_Arena* arena) : $0Access() {
msg_ = ($1*)msg;
arena_ = owned_arena_.ptr();
upb_Arena_Fuse(arena_, arena);
}
::protos::Arena owned_arena_;
friend Proxy;
friend CProxy;
friend absl::StatusOr<$2>(::protos::Parse<$2>(absl::string_view bytes,
int options));
friend absl::StatusOr<$2>(::protos::Parse<$2>(
absl::string_view bytes,
const ::protos::ExtensionRegistry& extension_registry,
int options));
friend upb_Arena* ::protos::internal::GetArena<$0>(const $0& message);
friend upb_Arena* ::protos::internal::GetArena<$0>(
const ::protos::Ptr<$0>& message);
friend $0(::protos::internal::MoveMessage<$0>(upb_Message* msg,
upb_Arena* arena));
)cc",
ClassName(descriptor), MessageName(descriptor),
QualifiedClassName(descriptor));
output.Outdent();
output("};\n\n");
}
void WriteModelProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output) {
// Foo::Proxy.
output(
R"cc(
class $0Proxy final : private internal::$0Access {
public:
$0Proxy() = delete;
$0Proxy(const $0Proxy& m) : internal::$0Access() {
msg_ = m.msg_;
arena_ = m.arena_;
}
$0Proxy operator=(const $0Proxy& m) {
msg_ = m.msg_;
arena_ = m.arena_;
return *this;
}
using $0Access::GetInternalArena;
)cc",
ClassName(descriptor));
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessageProxy,
output);
output("\n");
output.Indent(1);
output(
R"cc(
private:
$0Proxy(void* msg, upb_Arena* arena) : internal::$0Access(($1*)msg, arena) {}
friend $0::Proxy(::protos::CreateMessage<$0>(::protos::Arena& arena));
friend $0::Proxy(::protos::internal::CreateMessageProxy<$0>(
upb_Message*, upb_Arena*));
friend class $0CProxy;
friend class $0Access;
friend class ::protos::Ptr<$0>;
friend class ::protos::Ptr<const $0>;
friend upb_Arena* ::protos::internal::GetArena<$2>(const $2& message);
friend upb_Arena* ::protos::internal::GetArena<$2>(
const ::protos::Ptr<$2>& message);
static void Rebind($0Proxy& lhs, const $0Proxy& rhs) {
lhs.msg_ = rhs.msg_;
lhs.arena_ = rhs.arena_;
}
)cc",
ClassName(descriptor), MessageName(descriptor),
QualifiedClassName(descriptor));
output.Outdent(1);
output("};\n\n");
}
void WriteModelCProxyDeclaration(const protobuf::Descriptor* descriptor,
Output& output) {
// Foo::CProxy.
output(
R"cc(
class $0CProxy final : private internal::$0Access {
public:
$0CProxy() = delete;
$0CProxy(const $0* m) : internal::$0Access(m->msg_, nullptr) {}
using $0Access::GetInternalArena;
)cc",
ClassName(descriptor), MessageName(descriptor));
WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessageProxy,
output);
output.Indent(1);
output(
R"cc(
private:
$0CProxy(void* msg) : internal::$0Access(($1*)msg, nullptr){};
friend $0::CProxy(::protos::internal::CreateMessage<$0>(upb_Message* msg));
friend class ::protos::Ptr<$0>;
friend class ::protos::Ptr<const $0>;
static void Rebind($0CProxy& lhs, const $0CProxy& rhs) {
lhs.msg_ = rhs.msg_;
lhs.arena_ = rhs.arena_;
}
)cc",
ClassName(descriptor), MessageName(descriptor));
output.Outdent(1);
output("};\n\n");
}
void WriteDefaultInstanceHeader(const protobuf::Descriptor* message,
Output& output) {
output(" static ::protos::Ptr<const $0> default_instance();\n",
ClassName(message));
}
void WriteMessageImplementation(
const protobuf::Descriptor* descriptor,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
bool message_is_map_entry = descriptor->options().map_entry();
if (!message_is_map_entry) {
// Constructor.
output(
R"cc(
$0::$0() : $0Access() {
arena_ = owned_arena_.ptr();
msg_ = $1_new(arena_);
}
)cc",
ClassName(descriptor), MessageName(descriptor));
// Minitable
OutputIndenter i(output);
output(
R"cc(
const upb_MiniTable* $0::minitable() { return &$1; }
)cc",
ClassName(descriptor), ::upbc::MessageInit(descriptor));
}
::upbc::FileLayout layout(descriptor->file());
WriteAccessorsInSource(descriptor, layout, output);
if (!message_is_map_entry) {
output(
R"cc(
struct $0DefaultTypeInternal {
$1* msg;
};
$0DefaultTypeInternal _$0_default_instance_ =
$0DefaultTypeInternal{$1_new(upb_Arena_New())};
)cc",
ClassName(descriptor), MessageName(descriptor));
output(
R"cc(
::protos::Ptr<const $0> $0::default_instance() {
return ::protos::internal::CreateMessage<$0>(
(upb_Message *)_$0_default_instance_.msg);
}
)cc",
ClassName(descriptor));
}
}
void WriteInternalForwardDeclarationsInHeader(
const protobuf::Descriptor* message, Output& output) {
// Write declaration for internal re-usable default_instance without
// leaking implementation.
output(
R"cc(
struct $0DefaultTypeInternal;
extern $0DefaultTypeInternal _$0_default_instance_;
)cc",
ClassName(message));
}
void WriteExtensionIdentifiersInClassHeader(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
for (auto* ext : file_exts) {
if (ext->extension_scope() &&
ext->extension_scope()->full_name() == message->full_name()) {
WriteExtensionIdentifierHeader(ext, output);
}
}
}
void WriteExtensionIdentifiersImplementation(
const protobuf::Descriptor* message,
const std::vector<const protobuf::FieldDescriptor*>& file_exts,
Output& output) {
for (auto* ext : file_exts) {
if (ext->extension_scope() &&
ext->extension_scope()->full_name() == message->full_name()) {
WriteExtensionIdentifier(ext, output);
}
}
}
} // namespace protos_generator