From 49516d5099459e4d906b311a712d62e7c2c32644 Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang Date: Mon, 14 Oct 2024 00:36:34 +0800 Subject: [PATCH] Add NonreflectableMessage See https://github.com/apache/brpc/pull/2722#issuecomment-2272559689 inspired by unreflectable_message of @oathdruid. --- src/brpc/message_helper.h | 32 +++++ src/brpc/nonreflectable_message.h | 200 ++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 src/brpc/message_helper.h create mode 100644 src/brpc/nonreflectable_message.h diff --git a/src/brpc/message_helper.h b/src/brpc/message_helper.h new file mode 100644 index 0000000000..a910890067 --- /dev/null +++ b/src/brpc/message_helper.h @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#ifndef BRPC_MESSAGE_HELPER_H +#define BRPC_MESSAGE_HELPER_H + +#include "brpc/nonreflectable_message.h" + +namespace brpc { + +template +struct MessageHelper { + using BaseType = NonreflectableMessage; +}; + +} // namespace brpc + +#endif // BRPC_MESSAGE_HELPER_H diff --git a/src/brpc/nonreflectable_message.h b/src/brpc/nonreflectable_message.h new file mode 100644 index 0000000000..db69a95f2b --- /dev/null +++ b/src/brpc/nonreflectable_message.h @@ -0,0 +1,200 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#ifndef BRPC_NONREFLECTABLE_MESSAGE_H +#define BRPC_NONREFLECTABLE_MESSAGE_H + +#include + +namespace brpc { + +// +// In bRPC, some non-Protobuf based protocol messages are also designed to implement +// Protobuf Message interfaces, to provide a unified protocol message. +// The API of Protobuf Message changes frequently, and these non-Protobuf based protocol +// messages do not rely on the reflection functionality of Protobuf. +// +// NonreflectableMessage is designed to isolate upstream API changes and +// provides basic implementations to simplify the adaptation process. +// +// Function implementations are kept order with the upstream, +// and use only #if version_check #endif, to make maintenance easier. +// +template +class NonreflectableMessage : public ::google::protobuf::Message { +public: +#if GOOGLE_PROTOBUF_VERSION < 3019000 + Message* New() const override { + return new T(); + } +#endif + +#if GOOGLE_PROTOBUF_VERSION >= 3000000 + Message* New(::google::protobuf::Arena* arena) const override { + return ::google::protobuf::Arena::Create(arena); + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 3021000 + void CopyFrom(const ::google::protobuf::Message& other) override { + if (&other == this) { + return; + } + Clear(); + MergeFrom(other); + } +#endif + + inline void CopyFrom(const NonreflectableMessage& other) { + if (&other == this) { + return; + } + Clear(); + MergeFrom(other); + } + +#if GOOGLE_PROTOBUF_VERSION < 5026000 + void MergeFrom(const ::google::protobuf::Message& other) override { + if (&other == this) { + return; + } + + // Cross-type merging is meaningless, call implementation of subclass +#if GOOGLE_PROTOBUF_VERSION >= 3007000 + const T* same_type_other = ::google::protobuf::DynamicCastToGenerated(&other); +#elif GOOGLE_PROTOBUF_VERSION >= 3000000 + const T* same_type_other = ::google::protobuf::internal::DynamicCastToGenerated(&other); +#endif // GOOGLE_PROTOBUF_VERSION + if (same_type_other != nullptr) { + MergeFrom(*same_type_other); + } else { + Message::MergeFrom(other); + } + } +#endif // member function closure + + virtual void MergeFrom(const T&) = 0; + +#if GOOGLE_PROTOBUF_VERSION > 3019000 && GOOGLE_PROTOBUF_VERSION < 5026000 + // Unsupported by default. + std::string InitializationErrorString() const override { + return "unknown error"; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 3019000 + // Unsupported by default. + void DiscardUnknownFields() override {} +#endif + +#if GOOGLE_PROTOBUF_VERSION < 5026000 + // Unsupported by default. + size_t SpaceUsedLong() const override { + return 0; + } +#endif + + // Unsupported by default. + ::std::string GetTypeName() const override { + return {}; + } + + void Clear() override {} + +#if GOOGLE_PROTOBUF_VERSION < 3010000 + bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream*) override { + return true; + } +#endif + + // Quickly check if all required fields have values set. + // Unsupported by default. + bool IsInitialized() const override { + return true; + } + +#if GOOGLE_PROTOBUF_VERSION >= 3010000 && GOOGLE_PROTOBUF_VERSION <= 5026000 + const char* _InternalParse( + const char* ptr, ::google::protobuf::internal::ParseContext*) override { + return ptr; + } +#endif + + // Size of bytes after serialization. + size_t ByteSizeLong() const override { + return 0; + } + +#if GOOGLE_PROTOBUF_VERSION >= 3007000 && GOOGLE_PROTOBUF_VERSION < 3010000 + void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream*) const override {} +#endif + +#if GOOGLE_PROTOBUF_VERSION >= 3010000 && GOOGLE_PROTOBUF_VERSION < 3011000 + uint8_t* InternalSerializeWithCachedSizesToArray( + uint8_t* ptr, ::google::protobuf::io::EpsCopyOutputStream*) const override { + return ptr; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION >= 3011000 + uint8_t* _InternalSerialize( + uint8_t* ptr, ::google::protobuf::io::EpsCopyOutputStream*) const override { + return ptr; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 4025000 + // Unnecessary for Nonreflectable message. + int GetCachedSize() const override { + return 0; + } +#endif + +#if GOOGLE_PROTOBUF_VERSION < 4025000 + // Unnecessary for Nonreflectable message. + void SetCachedSize(int) const override {} +#endif + +public: + // Only can be used to determine whether the Types are the same. + ::google::protobuf::Metadata GetMetadata() const override { + ::google::protobuf::Metadata metadata{}; + // can only be used to + metadata.descriptor = reinterpret_cast(&_instance); + metadata.reflection = reinterpret_cast(&_instance); + return metadata; + } + + // Only can be used to determine whether the Types are the same. + inline static const ::google::protobuf::Descriptor* descriptor() noexcept { + return default_instance().GetMetadata().descriptor; + } + + inline static const T& default_instance() noexcept { + return _instance; + } + +private: + static T _instance; +}; + +template +T NonreflectableMessage::_instance; + +} // namespace brpc + +#endif // BRPC_NONREFLECTABLE_MESSAGE_H