1 // Copyright 2024 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef GRPCPP_IMPL_GENERIC_SERIALIZE_H
16 #define GRPCPP_IMPL_GENERIC_SERIALIZE_H
17
18 #include <grpc/byte_buffer_reader.h>
19 #include <grpc/impl/grpc_types.h>
20 #include <grpc/slice.h>
21 #include <grpcpp/impl/codegen/config_protobuf.h>
22 #include <grpcpp/impl/serialization_traits.h>
23 #include <grpcpp/support/byte_buffer.h>
24 #include <grpcpp/support/proto_buffer_reader.h>
25 #include <grpcpp/support/proto_buffer_writer.h>
26 #include <grpcpp/support/slice.h>
27 #include <grpcpp/support/status.h>
28
29 #include <type_traits>
30
31 #include "absl/log/absl_check.h"
32
33 /// This header provides serialization and deserialization between gRPC
34 /// messages serialized using protobuf and the C++ objects they represent.
35
36 namespace grpc {
37
38 // ProtoBufferWriter must be a subclass of ::protobuf::io::ZeroCopyOutputStream.
39 template <class ProtoBufferWriter, class T>
GenericSerialize(const grpc::protobuf::MessageLite & msg,ByteBuffer * bb,bool * own_buffer)40 Status GenericSerialize(const grpc::protobuf::MessageLite& msg, ByteBuffer* bb,
41 bool* own_buffer) {
42 static_assert(std::is_base_of<protobuf::io::ZeroCopyOutputStream,
43 ProtoBufferWriter>::value,
44 "ProtoBufferWriter must be a subclass of "
45 "::protobuf::io::ZeroCopyOutputStream");
46 *own_buffer = true;
47 int byte_size = static_cast<int>(msg.ByteSizeLong());
48 if (static_cast<size_t>(byte_size) <= GRPC_SLICE_INLINED_SIZE) {
49 Slice slice(byte_size);
50 // We serialize directly into the allocated slices memory
51 ABSL_CHECK(slice.end() == msg.SerializeWithCachedSizesToArray(
52 const_cast<uint8_t*>(slice.begin())));
53 ByteBuffer tmp(&slice, 1);
54 bb->Swap(&tmp);
55
56 return grpc::Status::OK;
57 }
58 ProtoBufferWriter writer(bb, kProtoBufferWriterMaxBufferLength, byte_size);
59 protobuf::io::CodedOutputStream cs(&writer);
60 msg.SerializeWithCachedSizes(&cs);
61 return !cs.HadError()
62 ? grpc::Status::OK
63 : Status(StatusCode::INTERNAL, "Failed to serialize message");
64 }
65
66 // BufferReader must be a subclass of ::protobuf::io::ZeroCopyInputStream.
67 template <class ProtoBufferReader, class T>
GenericDeserialize(ByteBuffer * buffer,grpc::protobuf::MessageLite * msg)68 Status GenericDeserialize(ByteBuffer* buffer,
69 grpc::protobuf::MessageLite* msg) {
70 static_assert(std::is_base_of<protobuf::io::ZeroCopyInputStream,
71 ProtoBufferReader>::value,
72 "ProtoBufferReader must be a subclass of "
73 "::protobuf::io::ZeroCopyInputStream");
74 if (buffer == nullptr) {
75 return Status(StatusCode::INTERNAL, "No payload");
76 }
77 Status result = grpc::Status::OK;
78 {
79 ProtoBufferReader reader(buffer);
80 if (!reader.status().ok()) {
81 return reader.status();
82 }
83 if (!msg->ParseFromZeroCopyStream(&reader)) {
84 result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
85 }
86 }
87 buffer->Clear();
88 return result;
89 }
90
91 } // namespace grpc
92
93 #endif // GRPCPP_IMPL_GENERIC_SERIALIZE_H
94