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
15 #include "proto_bloat.h"
16 #include "pw_bloat/bloat_this_binary.h"
17 #include "pw_protobuf/decoder.h"
18 #include "pw_protobuf/encoder.h"
19 #include "pw_protobuf/stream_decoder.h"
20 #include "pw_protobuf_test_protos/size_report.pwpb.h"
21 #include "pw_result/result.h"
22 #include "pw_status/status.h"
23
24 #ifndef _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
25 #define _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN 0
26 #endif // _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
27
28 #ifndef _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
29 #define _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT 0
30 #endif // _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
31
32 #ifndef _PW_PROTOBUF_SIZE_REPORT_MESSAGE
33 #define _PW_PROTOBUF_SIZE_REPORT_MESSAGE 0
34 #endif // _PW_PROTOBUF_SIZE_REPORT_MESSAGE
35
36 namespace pw::protobuf_size_report {
37 namespace {
38
39 namespace ItemInfo = pwpb::ItemInfo;
40 namespace ResponseInfo = pwpb::ResponseInfo;
41
42 template <typename T>
ConsumeValue(T val)43 PW_NO_INLINE void ConsumeValue(T val) {
44 [[maybe_unused]] volatile T no_optimize = val;
45 }
46
47 #if _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
48
49 std::array<std::byte, ItemInfo::kMaxEncodedSizeBytes> encode_buffer;
50 pw::protobuf::MemoryEncoder encoder(encode_buffer);
51
BasicEncode()52 PW_NO_INLINE void BasicEncode() {
53 pw::Status status;
54 volatile enum KeyType : uint32_t {
55 NONE = 0,
56 KEY_STRING = 1,
57 KEY_TOKEN = 2,
58 } which_key = KeyType::KEY_STRING;
59 volatile bool has_timestamp = true;
60 volatile bool has_has_value = false;
61 if (which_key == KeyType::KEY_STRING) {
62 encoder.WriteString(1, "test");
63 } else if (which_key == KeyType::KEY_TOKEN) {
64 encoder.WriteFixed32(2, 99999);
65 }
66
67 if (has_timestamp) {
68 encoder.WriteInt64(3, 1663003467);
69 }
70
71 if (has_has_value) {
72 encoder.WriteBool(4, true);
73 }
74
75 {
76 pw::protobuf::StreamEncoder submessage_encoder =
77 encoder.GetNestedEncoder(5);
78 status.Update(submessage_encoder.WriteInt64(1, 0x5001DBADFEEDBEE5));
79 status.Update(submessage_encoder.WriteInt32(2, 128));
80 status.Update(submessage_encoder.WriteInt32(3, 2));
81 }
82 ConsumeValue(status);
83 }
84
85 std::array<std::byte, ItemInfo::kMaxEncodedSizeBytes> decode_buffer;
86 pw::protobuf::Decoder decoder(decode_buffer);
87
DecodeItemInfo(pw::ConstByteSpan data)88 PW_NO_INLINE void DecodeItemInfo(pw::ConstByteSpan data) {
89 pw::protobuf::Decoder submessage_decoder(data);
90 while (submessage_decoder.Next().ok()) {
91 switch (submessage_decoder.FieldNumber()) {
92 case static_cast<uint32_t>(ItemInfo::Fields::kOffset): {
93 uint64_t value;
94 if (submessage_decoder.ReadUint64(&value).ok()) {
95 ConsumeValue(value);
96 }
97 break;
98 }
99 case static_cast<uint32_t>(ItemInfo::Fields::kSize): {
100 uint32_t value;
101 if (submessage_decoder.ReadUint32(&value).ok()) {
102 ConsumeValue(value);
103 }
104 break;
105 }
106 case static_cast<uint32_t>(ItemInfo::Fields::kAccessLevel): {
107 uint32_t value;
108
109 if (submessage_decoder.ReadUint32(&value).ok()) {
110 ConsumeValue(value);
111 }
112 break;
113 }
114 }
115 }
116 }
117
BasicDecode()118 PW_NO_INLINE void BasicDecode() {
119 volatile enum KeyType : uint32_t {
120 NONE = 0,
121 KEY_STRING = 1,
122 KEY_TOKEN = 2,
123 } which_key = KeyType::NONE;
124 volatile bool has_timestamp = false;
125 volatile bool has_has_value = false;
126
127 while (decoder.Next().ok()) {
128 switch (decoder.FieldNumber()) {
129 case static_cast<uint32_t>(ResponseInfo::Fields::kKeyString): {
130 which_key = KeyType::KEY_STRING;
131 std::string_view value;
132 if (decoder.ReadString(&value).ok()) {
133 ConsumeValue(value);
134 }
135 break;
136 }
137 case static_cast<uint32_t>(ResponseInfo::Fields::kKeyToken): {
138 which_key = KeyType::KEY_TOKEN;
139 uint32_t value;
140 if (decoder.ReadUint32(&value).ok()) {
141 ConsumeValue(value);
142 }
143 break;
144 }
145 case static_cast<uint32_t>(ResponseInfo::Fields::kTimestamp): {
146 uint64_t value;
147 has_timestamp = true;
148 if (decoder.ReadUint64(&value).ok()) {
149 ConsumeValue(value);
150 }
151 break;
152 }
153 case static_cast<uint32_t>(ResponseInfo::Fields::kHasValue): {
154 bool value;
155 has_has_value = true;
156 if (decoder.ReadBool(&value).ok()) {
157 ConsumeValue(value);
158 }
159 break;
160 }
161 case static_cast<uint32_t>(ResponseInfo::Fields::kItemInfo): {
162 pw::ConstByteSpan value;
163 if (decoder.ReadBytes(&value).ok()) {
164 DecodeItemInfo(value);
165 }
166 break;
167 }
168 }
169 }
170 ConsumeValue(which_key);
171 ConsumeValue(has_timestamp);
172 ConsumeValue(has_has_value);
173 }
174
175 #endif // _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
176
177 #if _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
178
179 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> encode_buffer;
180 ResponseInfo::MemoryEncoder encoder(encode_buffer);
181
BasicEncode()182 PW_NO_INLINE void BasicEncode() {
183 pw::Status status;
184 volatile enum KeyType : uint32_t {
185 NONE = 0,
186 KEY_STRING = 1,
187 KEY_TOKEN = 2,
188 } which_key = KeyType::KEY_STRING;
189 volatile bool has_timestamp = true;
190 volatile bool has_has_value = false;
191 if (which_key == KeyType::KEY_STRING) {
192 encoder.WriteKeyString("test");
193 } else if (which_key == KeyType::KEY_TOKEN) {
194 encoder.WriteKeyToken(99999);
195 }
196
197 if (has_timestamp) {
198 encoder.WriteTimestamp(1663003467);
199 }
200
201 if (has_has_value) {
202 encoder.WriteHasValue(true);
203 }
204
205 {
206 ItemInfo::StreamEncoder submessage_encoder = encoder.GetItemInfoEncoder();
207 status.Update(submessage_encoder.WriteOffset(0x5001DBADFEEDBEE5));
208 status.Update(submessage_encoder.WriteSize(128));
209 status.Update(submessage_encoder.WriteAccessLevel(ItemInfo::Access::WRITE));
210 }
211 ConsumeValue(status);
212 }
213
214 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> decode_buffer;
215 pw::stream::MemoryReader reader(decode_buffer);
216 ResponseInfo::StreamDecoder decoder(reader);
217
DecodeItemInfo(ItemInfo::StreamDecoder & submessage_decoder)218 PW_NO_INLINE void DecodeItemInfo(ItemInfo::StreamDecoder& submessage_decoder) {
219 while (submessage_decoder.Next().ok()) {
220 pw::Result<ItemInfo::Fields> field = submessage_decoder.Field();
221 if (!field.ok()) {
222 ConsumeValue(field.status());
223 return;
224 }
225
226 switch (field.value()) {
227 case ItemInfo::Fields::kOffset: {
228 pw::Result<uint64_t> value = submessage_decoder.ReadOffset();
229 if (value.ok()) {
230 ConsumeValue(value);
231 }
232 break;
233 }
234 case ItemInfo::Fields::kSize: {
235 pw::Result<uint32_t> value = submessage_decoder.ReadSize();
236 if (value.ok()) {
237 ConsumeValue(value);
238 }
239 break;
240 }
241 case ItemInfo::Fields::kAccessLevel: {
242 pw::Result<ItemInfo::Access> value =
243 submessage_decoder.ReadAccessLevel();
244 if (value.ok()) {
245 ConsumeValue(value);
246 }
247 break;
248 }
249 }
250 }
251 }
252
BasicDecode()253 PW_NO_INLINE void BasicDecode() {
254 volatile enum KeyType : uint32_t {
255 NONE = 0,
256 KEY_STRING = 1,
257 KEY_TOKEN = 2,
258 } which_key = KeyType::NONE;
259 volatile bool has_timestamp = false;
260 volatile bool has_has_value = false;
261
262 while (decoder.Next().ok()) {
263 while (decoder.Next().ok()) {
264 pw::Result<ResponseInfo::Fields> field = decoder.Field();
265 if (!field.ok()) {
266 ConsumeValue(field.status());
267 return;
268 }
269
270 switch (field.value()) {
271 case ResponseInfo::Fields::kKeyString: {
272 which_key = KeyType::KEY_STRING;
273 std::array<char, 8> value;
274 pw::StatusWithSize status = decoder.ReadKeyString(value);
275 if (status.ok()) {
276 ConsumeValue(pw::span(value));
277 }
278 break;
279 }
280 case ResponseInfo::Fields::kKeyToken: {
281 which_key = KeyType::KEY_TOKEN;
282 pw::Result<uint32_t> value = decoder.ReadKeyToken();
283 if (value.ok()) {
284 ConsumeValue(value);
285 }
286 break;
287 }
288 case ResponseInfo::Fields::kTimestamp: {
289 has_timestamp = true;
290 pw::Result<int64_t> value = decoder.ReadTimestamp();
291 if (value.ok()) {
292 ConsumeValue(value);
293 }
294 break;
295 }
296 case ResponseInfo::Fields::kHasValue: {
297 has_has_value = true;
298 pw::Result<bool> value = decoder.ReadHasValue();
299 if (value.ok()) {
300 ConsumeValue(value);
301 }
302 break;
303 }
304 case ResponseInfo::Fields::kItemInfo: {
305 ItemInfo::StreamDecoder submessage_decoder =
306 decoder.GetItemInfoDecoder();
307 DecodeItemInfo(submessage_decoder);
308 break;
309 }
310 }
311 }
312 }
313 ConsumeValue(which_key);
314 ConsumeValue(has_timestamp);
315 ConsumeValue(has_has_value);
316 }
317 #endif // _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
318
319 #if _PW_PROTOBUF_SIZE_REPORT_MESSAGE
320
321 ResponseInfo::Message message;
322
323 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> encode_buffer;
324 ResponseInfo::MemoryEncoder encoder(encode_buffer);
325
BasicEncode()326 PW_NO_INLINE void BasicEncode() {
327 volatile enum KeyType : uint32_t {
328 NONE = 0,
329 KEY_STRING = 1,
330 KEY_TOKEN = 2,
331 } which_key = KeyType::KEY_STRING;
332 volatile bool has_timestamp = true;
333 volatile bool has_has_value = false;
334 if (which_key == KeyType::KEY_STRING) {
335 message.key_string.SetEncoder(
336 [](ResponseInfo::StreamEncoder& key_string_encoder) -> pw::Status {
337 key_string_encoder.WriteKeyString("test");
338 return pw::OkStatus();
339 });
340 } else if (which_key == KeyType::KEY_TOKEN) {
341 message.key_token = 99999;
342 }
343 message.timestamp =
344 has_timestamp ? std::optional<uint32_t>(1663003467) : std::nullopt;
345 message.has_value = has_has_value ? std::optional<bool>(false) : std::nullopt;
346
347 message.item_info.offset = 0x5001DBADFEEDBEE5;
348 message.item_info.size = 128;
349 message.item_info.access_level = ItemInfo::Access::WRITE;
350 ConsumeValue(encoder.Write(message));
351 }
352
353 std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> decode_buffer;
354 pw::stream::MemoryReader reader(decode_buffer);
355 ResponseInfo::StreamDecoder decoder(reader);
356
BasicDecode()357 PW_NO_INLINE void BasicDecode() {
358 volatile enum KeyType : uint32_t {
359 NONE = 0,
360 KEY_STRING = 1,
361 KEY_TOKEN = 2,
362 } which_key = KeyType::NONE;
363 volatile bool has_timestamp = false;
364 volatile bool has_has_value = false;
365 if (pw::Status status = decoder.Read(message); status.ok()) {
366 ConsumeValue(status);
367 has_timestamp = message.timestamp.has_value();
368 has_has_value = message.has_value.has_value();
369 }
370 ConsumeValue(which_key);
371 ConsumeValue(has_timestamp);
372 ConsumeValue(has_has_value);
373 }
374 #endif // _PW_PROTOBUF_SIZE_REPORT_MESSAGE
375
376 } // namespace
377 } // namespace pw::protobuf_size_report
378
main()379 int main() {
380 pw::bloat::BloatThisBinary();
381 pw::protobuf_size_report::BloatWithBase();
382 pw::protobuf_size_report::BloatWithEncoder();
383 pw::protobuf_size_report::BloatWithStreamDecoder();
384 pw::protobuf_size_report::BloatWithDecoder();
385 pw::protobuf_size_report::BloatWithTableEncoder();
386 pw::protobuf_size_report::BloatWithTableDecoder();
387 pw::protobuf_size_report::BasicEncode();
388 pw::protobuf_size_report::BasicDecode();
389 return 0;
390 }
391