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