1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 #include "pw_rpc/internal/packet.h"
17 #include "pw_protobuf/decoder.h"
19 namespace pw::rpc::internal {
23 Result<Packet> Packet::FromBuffer(ConstByteSpan data) {
26 protobuf::Decoder decoder(data);
28 while ((status = decoder.Next()).ok()) {
29 RpcPacket::Fields field =
30 static_cast<RpcPacket::Fields>(decoder.FieldNumber());
33 case RpcPacket::Fields::TYPE: {
35 decoder.ReadUint32(&value);
36 packet.set_type(static_cast<PacketType>(value));
40 case RpcPacket::Fields::CHANNEL_ID:
41 decoder.ReadUint32(&packet.channel_id_);
44 case RpcPacket::Fields::SERVICE_ID:
45 decoder.ReadFixed32(&packet.service_id_);
48 case RpcPacket::Fields::METHOD_ID:
49 decoder.ReadFixed32(&packet.method_id_);
52 case RpcPacket::Fields::PAYLOAD:
53 decoder.ReadBytes(&packet.payload_);
56 case RpcPacket::Fields::STATUS: {
58 decoder.ReadUint32(&value);
59 packet.set_status(static_cast<Status::Code>(value));
65 if (status.IsDataLoss()) {
72 Result<ConstByteSpan> Packet::Encode(ByteSpan buffer) const {
73 pw::protobuf::NestedEncoder encoder(buffer);
74 RpcPacket::Encoder rpc_packet(&encoder);
76 // The payload is encoded first, as it may share the encode buffer.
77 rpc_packet.WritePayload(payload_);
79 rpc_packet.WriteType(type_);
80 rpc_packet.WriteChannelId(channel_id_);
81 rpc_packet.WriteServiceId(service_id_);
82 rpc_packet.WriteMethodId(method_id_);
83 rpc_packet.WriteStatus(status_.code());
85 return encoder.Encode();
88 size_t Packet::MinEncodedSizeBytes() const {
89 size_t reserved_size = 0;
91 reserved_size += 1; // channel_id key
92 reserved_size += varint::EncodedSize(channel_id());
93 reserved_size += 1 + sizeof(uint32_t); // service_id key and fixed32
94 reserved_size += 1 + sizeof(uint32_t); // method_id key and fixed32
96 // Packet type always takes two bytes to encode (varint key + varint enum).
99 // Status field always takes two bytes to encode (varint key + varint status).
102 // Payload field takes at least two bytes to encode (varint key + length).
105 return reserved_size;
108 } // namespace pw::rpc::internal