xref: /aosp_15_r20/external/pigweed/pw_rpc/pwpb/public/pw_rpc/pwpb/serde.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <array>
17 
18 #include "pw_protobuf/encoder.h"
19 #include "pw_protobuf/internal/codegen.h"
20 #include "pw_protobuf/stream_decoder.h"
21 #include "pw_span/span.h"
22 #include "pw_stream/null_stream.h"
23 
24 namespace pw::rpc {
25 
26 using PwpbMessageDescriptor =
27     const span<const protobuf::internal::MessageField>*;
28 
29 // Serializer/deserializer for a pw_protobuf message.
30 class PwpbSerde {
31  public:
PwpbSerde(PwpbMessageDescriptor table)32   explicit constexpr PwpbSerde(PwpbMessageDescriptor table) : table_(table) {}
33 
34   PwpbSerde(const PwpbSerde&) = default;
35   PwpbSerde& operator=(const PwpbSerde&) = default;
36 
37   // Encodes a pw_protobuf struct to the serialized wire format.
38   template <typename Message>
Encode(const Message & message,ByteSpan buffer)39   StatusWithSize Encode(const Message& message, ByteSpan buffer) const {
40     return Encoder(buffer).Write(as_bytes(span(&message, 1)), table_);
41   }
42 
43   // Calculates the encoded size of the provided protobuf struct without
44   // actually encoding it.
45   template <typename Message>
EncodedSizeBytes(const Message & message)46   StatusWithSize EncodedSizeBytes(const Message& message) const {
47     // TODO: b/269515470 - Use kScratchBufferSizeBytes instead of a fixed size.
48     std::array<std::byte, 64> scratch_buffer;
49 
50     stream::CountingNullStream output;
51     StreamEncoder encoder(output, scratch_buffer);
52     const Status result = encoder.Write(as_bytes(span(&message, 1)), *table_);
53 
54     // TODO: b/269633514 - Add 16 to the encoded size because pw_protobuf
55     //     sometimes fails to encode to buffers that exactly fit the output.
56     return StatusWithSize(result, output.bytes_written() + 16);
57   }
58 
59   // Decodes a serialized protobuf into a pw_protobuf message struct.
60   template <typename Message>
Decode(ConstByteSpan buffer,Message & message)61   Status Decode(ConstByteSpan buffer, Message& message) const {
62     return Decoder(buffer).Read(as_writable_bytes(span(&message, 1)), table_);
63   }
64 
65  private:
66   class Encoder : public protobuf::MemoryEncoder {
67    public:
Encoder(ByteSpan buffer)68     constexpr Encoder(ByteSpan buffer) : protobuf::MemoryEncoder(buffer) {}
69 
Write(ConstByteSpan message,PwpbMessageDescriptor table)70     StatusWithSize Write(ConstByteSpan message, PwpbMessageDescriptor table) {
71       const Status status = protobuf::MemoryEncoder::Write(message, *table);
72       return StatusWithSize(status, size());
73     }
74   };
75 
76   class StreamEncoder : public protobuf::StreamEncoder {
77    public:
StreamEncoder(stream::Writer & writer,ByteSpan buffer)78     constexpr StreamEncoder(stream::Writer& writer, ByteSpan buffer)
79         : protobuf::StreamEncoder(writer, buffer) {}
80 
81     using protobuf::StreamEncoder::Write;  // Make this method public
82   };
83 
84   class Decoder : public protobuf::StreamDecoder {
85    public:
Decoder(ConstByteSpan buffer)86     constexpr Decoder(ConstByteSpan buffer)
87         : protobuf::StreamDecoder(reader_), reader_(buffer) {}
88 
Read(ByteSpan message,PwpbMessageDescriptor table)89     Status Read(ByteSpan message, PwpbMessageDescriptor table) {
90       return protobuf::StreamDecoder::Read(message, *table);
91     }
92 
93    private:
94     stream::MemoryReader reader_;
95   };
96 
97   PwpbMessageDescriptor table_;
98 };
99 
100 // Serializer/deserializer for pw_protobuf request and response message structs
101 // within an RPC method.
102 class PwpbMethodSerde {
103  public:
PwpbMethodSerde(PwpbMessageDescriptor request_table,PwpbMessageDescriptor response_table)104   constexpr PwpbMethodSerde(PwpbMessageDescriptor request_table,
105                             PwpbMessageDescriptor response_table)
106       : request_serde_(request_table), response_serde_(response_table) {}
107 
108   PwpbMethodSerde(const PwpbMethodSerde&) = delete;
109   PwpbMethodSerde& operator=(const PwpbMethodSerde&) = delete;
110 
request()111   const PwpbSerde& request() const { return request_serde_; }
response()112   const PwpbSerde& response() const { return response_serde_; }
113 
114  private:
115   PwpbSerde request_serde_;
116   PwpbSerde response_serde_;
117 };
118 
119 }  // namespace pw::rpc
120