blob: 7bdcbf1e45a67d6554de6bd821a70d1be0fd0223 [file]
// Protocol Buffers - Google's data interchange format
// Copyright 2022 Google Inc. 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
//
// Defines MessageTraits, a trait that provides access to the message prototype,
// class data, and the parse table. Specialized by codegen with hard-coded
// values to avoid runtime lookups.
//
// This file intentionally does not depend on protobuf_lite.
#ifndef GOOGLE_PROTOBUF_MESSAGE_TRAITS_H__
#define GOOGLE_PROTOBUF_MESSAGE_TRAITS_H__
#include <type_traits>
namespace google {
namespace protobuf {
class Message;
class MessageLite;
namespace internal {
struct ClassData;
template <typename MessageT>
const ClassData* GetClassData(const MessageT& msg);
template <typename T>
struct FallbackMessageTraits {
static const void* default_instance() { return &T::default_instance(); }
static constexpr const auto* class_data() {
return GetClassData(static_cast<const MessageLite&>(T::default_instance()));
}
static const auto* tc_table() { return class_data()->GetTcParseTable(); }
// We can't make a constexpr pointer to the default, so use a function pointer
// instead.
static constexpr auto StrongPointer() { return &T::default_instance; }
};
// Traits for messages.
// We use a class scope variable template, which can be specialized with a
// different type in a non-defining declaration.
// We need non-defining declarations because we might have duplicates of the
// same trait specification on each dependent coming from different .proto.h
// files.
struct MessageTraitsImpl {
template <typename T>
static FallbackMessageTraits<T> value;
};
template <typename T>
using MessageTraits = decltype(MessageTraitsImpl::value<T>);
// Returns the ClassData for the given message. If the concrete message type is
// known, this returns a compile-time constant. Otherwise, `ClassData` is loaded
// from `MessageLite::GetClassData()`.
template <typename MessageT>
const ClassData* GetClassData(const MessageT& msg) {
if constexpr (std::is_same_v<MessageT, MessageLite> ||
std::is_same_v<MessageT, Message>) {
return msg.GetClassData();
} else {
return MessageTraits<MessageT>::class_data();
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_MESSAGE_TRAITS_H__