blob: 931fd6eab101b360e6efff8204d423aa417a9571 [file]
// Copyright 2024 gRPC authors.
//
// Licensed 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 GRPCPP_IMPL_GENERIC_SERIALIZE_H
#define GRPCPP_IMPL_GENERIC_SERIALIZE_H
#include <grpc/byte_buffer_reader.h>
#include <grpc/event_engine/memory_allocator.h>
#include <grpc/impl/grpc_types.h>
#include <grpc/slice.h>
#include <grpcpp/impl/codegen/config_protobuf.h>
#include <grpcpp/impl/serialization_traits.h>
#include <grpcpp/support/byte_buffer.h>
#include <grpcpp/support/proto_buffer_reader.h>
#include <grpcpp/support/proto_buffer_writer.h>
#include <grpcpp/support/slice.h>
#include <grpcpp/support/status.h>
#include <cstddef>
#include <limits>
#include <type_traits>
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
/// This header provides serialization and deserialization between gRPC
/// messages serialized using protobuf and the C++ objects they represent.
namespace grpc {
// ProtoBufferWriter must be a subclass of ::protobuf::io::ZeroCopyOutputStream.
template <class ProtoBufferWriter, class T>
Status GenericSerialize(
const grpc::protobuf::MessageLite& msg, ByteBuffer* bb, bool* own_buffer,
grpc_event_engine::experimental::MemoryAllocator* allocator = nullptr) {
static_assert(std::is_base_of<protobuf::io::ZeroCopyOutputStream,
ProtoBufferWriter>::value,
"ProtoBufferWriter must be a subclass of "
"::protobuf::io::ZeroCopyOutputStream");
*own_buffer = true;
size_t byte_size = msg.ByteSizeLong();
if (byte_size > std::numeric_limits<int>::max()) {
return Status(StatusCode::INTERNAL,
"Protobuf is too large to be serialized",
absl::StrCat(byte_size, " bytes is beyond the limit 2^31-1"));
}
if (byte_size <= GRPC_SLICE_INLINED_SIZE) {
Slice slice(byte_size);
// We serialize directly into the allocated slices memory
ABSL_CHECK(slice.end() == msg.SerializeWithCachedSizesToArray(
const_cast<uint8_t*>(slice.begin())));
ByteBuffer tmp(&slice, 1);
bb->Swap(&tmp);
return grpc::Status::OK;
}
ProtoBufferWriter writer(bb, kProtoBufferWriterMaxBufferLength,
static_cast<int>(byte_size), allocator);
protobuf::io::CodedOutputStream cs(&writer);
msg.SerializeWithCachedSizes(&cs);
return !cs.HadError()
? grpc::Status::OK
: Status(StatusCode::INTERNAL, "Failed to serialize message");
}
// BufferReader must be a subclass of ::protobuf::io::ZeroCopyInputStream.
template <class ProtoBufferReader, class T>
Status GenericDeserialize(ByteBuffer* buffer,
grpc::protobuf::MessageLite* msg) {
static_assert(std::is_base_of<protobuf::io::ZeroCopyInputStream,
ProtoBufferReader>::value,
"ProtoBufferReader must be a subclass of "
"::protobuf::io::ZeroCopyInputStream");
if (buffer == nullptr) {
return Status(StatusCode::INTERNAL, "No payload");
}
Status result = grpc::Status::OK;
{
ProtoBufferReader reader(buffer);
if (!reader.status().ok()) {
return reader.status();
}
if (!msg->ParseFromZeroCopyStream(&reader)) {
result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
}
}
buffer->Clear();
return result;
}
} // namespace grpc
#endif // GRPCPP_IMPL_GENERIC_SERIALIZE_H