1 // Copyright 2023 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 /// @file pw_protobuf/find.h
17 ///
18 /// Sometimes, only a single field from a serialized message needs to be read.
19 /// In these cases, setting up a decoder and iterating through the message is a
20 /// lot of boilerplate. ``pw_protobuf`` provides convenient ``Find*()``
21 /// functions which handle this for you.
22 ///
23 /// @note Each call to ``Find*()`` linearly scans through the message. If you
24 /// have to read multiple fields, it is more efficient to instantiate your own
25 /// decoder as described above.
26 ///
27 /// @code{.cpp}
28 ///
29 /// pw::Status PrintCustomerAge(pw::ConstByteSpan serialized_customer) {
30 /// pw::Result<uint32_t> age = pw::protobuf::FindUint32(
31 /// serialized_customer, Customer::Fields::kAge);
32 /// if (!age.ok()) {
33 /// return age.status();
34 /// }
35 ///
36 /// PW_LOG_INFO("Customer's age is %u", *age);
37 /// return pw::OkStatus();
38 /// }
39 ///
40 /// @endcode
41
42 #include "pw_bytes/span.h"
43 #include "pw_protobuf/decoder.h"
44 #include "pw_protobuf/stream_decoder.h"
45 #include "pw_result/result.h"
46 #include "pw_status/try.h"
47 #include "pw_string/string.h"
48
49 namespace pw::protobuf {
50 namespace internal {
51
52 Status AdvanceToField(Decoder& decoder, uint32_t field_number);
53 Status AdvanceToField(StreamDecoder& decoder, uint32_t field_number);
54
55 template <typename T, auto ReadFn>
Find(ConstByteSpan message,uint32_t field_number)56 Result<T> Find(ConstByteSpan message, uint32_t field_number) {
57 T output;
58 Decoder decoder(message);
59 PW_TRY(AdvanceToField(decoder, field_number));
60 PW_TRY((decoder.*ReadFn)(&output));
61 return output;
62 }
63
64 template <typename T, auto ReadFn>
Find(stream::Reader & reader,uint32_t field_number)65 Result<T> Find(stream::Reader& reader, uint32_t field_number) {
66 StreamDecoder decoder(reader);
67 PW_TRY(AdvanceToField(decoder, field_number));
68 Result<T> result = (decoder.*ReadFn)();
69
70 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
71 // a field. Remap this to FAILED_PRECONDITION for consistency with the
72 // non-stream Find.
73 return result.status().IsNotFound() ? Result<T>(Status::FailedPrecondition())
74 : result;
75 }
76
77 } // namespace internal
78
79 /// @brief Scans a serialized protobuf message for a `uint32` field.
80 ///
81 /// @param message The serialized message to search.
82 /// @param field_number Protobuf field number of the field.
83 ///
84 /// @returns @rst
85 ///
86 /// .. pw-status-codes::
87 ///
88 /// OK: Returns the field.
89 ///
90 /// NOT_FOUND: The field is not present.
91 ///
92 /// DATA_LOSS: The serialized message is not a valid protobuf.
93 ///
94 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
95 ///
96 /// @endrst
FindUint32(ConstByteSpan message,uint32_t field_number)97 inline Result<uint32_t> FindUint32(ConstByteSpan message,
98 uint32_t field_number) {
99 return internal::Find<uint32_t, &Decoder::ReadUint32>(message, field_number);
100 }
101
102 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindUint32(ConstByteSpan message,T field)103 inline Result<uint32_t> FindUint32(ConstByteSpan message, T field) {
104 return FindUint32(message, static_cast<uint32_t>(field));
105 }
106
107 /// @brief Scans a serialized protobuf message for a `uint32` field.
108 ///
109 /// @param message_stream The serialized message to search.
110 /// @param field_number Protobuf field number of the field.
111 ///
112 /// @returns @rst
113 ///
114 /// .. pw-status-codes::
115 ///
116 /// OK: Returns the field.
117 ///
118 /// NOT_FOUND: The field is not present.
119 ///
120 /// DATA_LOSS: The serialized message is not a valid protobuf.
121 ///
122 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
123 ///
124 /// @endrst
FindUint32(stream::Reader & message_stream,uint32_t field_number)125 inline Result<uint32_t> FindUint32(stream::Reader& message_stream,
126 uint32_t field_number) {
127 return internal::Find<uint32_t, &StreamDecoder::ReadUint32>(message_stream,
128 field_number);
129 }
130
131 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindUint32(stream::Reader & message_stream,T field)132 inline Result<uint32_t> FindUint32(stream::Reader& message_stream, T field) {
133 return FindUint32(message_stream, static_cast<uint32_t>(field));
134 }
135
136 /// @brief Scans a serialized protobuf message for an `int32` field.
137 ///
138 /// @param message The serialized message to search.
139 /// @param field_number Protobuf field number of the field.
140 ///
141 /// @returns @rst
142 ///
143 /// .. pw-status-codes::
144 ///
145 /// OK: Returns the field.
146 ///
147 /// NOT_FOUND: The field is not present.
148 ///
149 /// DATA_LOSS: The serialized message is not a valid protobuf.
150 ///
151 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
152 ///
153 /// @endrst
FindInt32(ConstByteSpan message,uint32_t field_number)154 inline Result<int32_t> FindInt32(ConstByteSpan message, uint32_t field_number) {
155 return internal::Find<int32_t, &Decoder::ReadInt32>(message, field_number);
156 }
157
158 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindInt32(ConstByteSpan message,T field)159 inline Result<int32_t> FindInt32(ConstByteSpan message, T field) {
160 return FindInt32(message, static_cast<uint32_t>(field));
161 }
162
163 /// @brief Scans a serialized protobuf message for an `int32` field.
164 ///
165 /// @param message_stream The serialized message to search.
166 /// @param field_number Protobuf field number of the field.
167 ///
168 /// @returns @rst
169 ///
170 /// .. pw-status-codes::
171 ///
172 /// OK: Returns the field.
173 ///
174 /// NOT_FOUND: The field is not present.
175 ///
176 /// DATA_LOSS: The serialized message is not a valid protobuf.
177 ///
178 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
179 ///
180 /// @endrst
FindInt32(stream::Reader & message_stream,uint32_t field_number)181 inline Result<int32_t> FindInt32(stream::Reader& message_stream,
182 uint32_t field_number) {
183 return internal::Find<int32_t, &StreamDecoder::ReadInt32>(message_stream,
184 field_number);
185 }
186
187 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindInt32(stream::Reader & message_stream,T field)188 inline Result<int32_t> FindInt32(stream::Reader& message_stream, T field) {
189 return FindInt32(message_stream, static_cast<uint32_t>(field));
190 }
191
192 /// @brief Scans a serialized protobuf message for an `sint32` field.
193 ///
194 /// @param message The serialized message to search.
195 /// @param field_number Protobuf field number of the field.
196 ///
197 /// @returns @rst
198 ///
199 /// .. pw-status-codes::
200 ///
201 /// OK: Returns the field.
202 ///
203 /// NOT_FOUND: The field is not present.
204 ///
205 /// DATA_LOSS: The serialized message is not a valid protobuf.
206 ///
207 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
208 ///
209 /// @endrst
FindSint32(ConstByteSpan message,uint32_t field_number)210 inline Result<int32_t> FindSint32(ConstByteSpan message,
211 uint32_t field_number) {
212 return internal::Find<int32_t, &Decoder::ReadSint32>(message, field_number);
213 }
214
215 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSint32(ConstByteSpan message,T field)216 inline Result<int32_t> FindSint32(ConstByteSpan message, T field) {
217 return FindSint32(message, static_cast<uint32_t>(field));
218 }
219
220 /// @brief Scans a serialized protobuf message for an `sint32` field.
221 ///
222 /// @param message_stream The serialized message to search.
223 /// @param field_number Protobuf field number of the field.
224 ///
225 /// @returns @rst
226 ///
227 /// .. pw-status-codes::
228 ///
229 /// OK: Returns the field.
230 ///
231 /// NOT_FOUND: The field is not present.
232 ///
233 /// DATA_LOSS: The serialized message is not a valid protobuf.
234 ///
235 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
236 ///
237 /// @endrst
FindSint32(stream::Reader & message_stream,uint32_t field_number)238 inline Result<int32_t> FindSint32(stream::Reader& message_stream,
239 uint32_t field_number) {
240 return internal::Find<int32_t, &StreamDecoder::ReadSint32>(message_stream,
241 field_number);
242 }
243
244 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSint32(stream::Reader & message_stream,T field)245 inline Result<int32_t> FindSint32(stream::Reader& message_stream, T field) {
246 return FindSint32(message_stream, static_cast<uint32_t>(field));
247 }
248
249 /// @brief Scans a serialized protobuf message for a `uint64` field.
250 ///
251 /// @param message The serialized message to search.
252 /// @param field_number Protobuf field number of the field.
253 ///
254 /// @returns @rst
255 ///
256 /// .. pw-status-codes::
257 ///
258 /// OK: Returns the field.
259 ///
260 /// NOT_FOUND: The field is not present.
261 ///
262 /// DATA_LOSS: The serialized message is not a valid protobuf.
263 ///
264 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
265 ///
266 /// @endrst
FindUint64(ConstByteSpan message,uint32_t field_number)267 inline Result<uint64_t> FindUint64(ConstByteSpan message,
268 uint32_t field_number) {
269 return internal::Find<uint64_t, &Decoder::ReadUint64>(message, field_number);
270 }
271
272 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindUint64(ConstByteSpan message,T field)273 inline Result<uint64_t> FindUint64(ConstByteSpan message, T field) {
274 return FindUint64(message, static_cast<uint32_t>(field));
275 }
276
277 /// @brief Scans a serialized protobuf message for a `uint64` field.
278 ///
279 /// @param message_stream The serialized message to search.
280 /// @param field_number Protobuf field number of the field.
281 ///
282 /// @returns @rst
283 ///
284 /// .. pw-status-codes::
285 ///
286 /// OK: Returns the field.
287 ///
288 /// NOT_FOUND: The field is not present.
289 ///
290 /// DATA_LOSS: The serialized message is not a valid protobuf.
291 ///
292 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
293 ///
294 /// @endrst
FindUint64(stream::Reader & message_stream,uint32_t field_number)295 inline Result<uint64_t> FindUint64(stream::Reader& message_stream,
296 uint32_t field_number) {
297 return internal::Find<uint64_t, &StreamDecoder::ReadUint64>(message_stream,
298 field_number);
299 }
300
301 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindUint64(stream::Reader & message_stream,T field)302 inline Result<uint64_t> FindUint64(stream::Reader& message_stream, T field) {
303 return FindUint64(message_stream, static_cast<uint32_t>(field));
304 }
305
306 /// @brief Scans a serialized protobuf message for an `int64` field.
307 ///
308 /// @param message The serialized message to search.
309 /// @param field_number Protobuf field number of the field.
310 ///
311 /// @returns @rst
312 ///
313 /// .. pw-status-codes::
314 ///
315 /// OK: Returns the field.
316 ///
317 /// NOT_FOUND: The field is not present.
318 ///
319 /// DATA_LOSS: The serialized message is not a valid protobuf.
320 ///
321 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
322 ///
323 /// @endrst
FindInt64(ConstByteSpan message,uint32_t field_number)324 inline Result<int64_t> FindInt64(ConstByteSpan message, uint32_t field_number) {
325 return internal::Find<int64_t, &Decoder::ReadInt64>(message, field_number);
326 }
327
328 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindInt64(ConstByteSpan message,T field)329 inline Result<int64_t> FindInt64(ConstByteSpan message, T field) {
330 return FindInt64(message, static_cast<uint32_t>(field));
331 }
332
333 /// @brief Scans a serialized protobuf message for an `int64` field.
334 ///
335 /// @param message_stream The serialized message to search.
336 /// @param field_number Protobuf field number of the field.
337 ///
338 /// @returns @rst
339 ///
340 /// .. pw-status-codes::
341 ///
342 /// OK: Returns the field.
343 ///
344 /// NOT_FOUND: The field is not present.
345 ///
346 /// DATA_LOSS: The serialized message is not a valid protobuf.
347 ///
348 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
349 ///
350 /// @endrst
FindInt64(stream::Reader & message_stream,uint32_t field_number)351 inline Result<int64_t> FindInt64(stream::Reader& message_stream,
352 uint32_t field_number) {
353 return internal::Find<int64_t, &StreamDecoder::ReadInt64>(message_stream,
354 field_number);
355 }
356
357 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindInt64(stream::Reader & message_stream,T field)358 inline Result<int64_t> FindInt64(stream::Reader& message_stream, T field) {
359 return FindInt64(message_stream, static_cast<uint32_t>(field));
360 }
361
362 /// @brief Scans a serialized protobuf message for an `sint64` field.
363 ///
364 /// @param message The serialized message to search.
365 /// @param field_number Protobuf field number of the field.
366 ///
367 /// @returns @rst
368 ///
369 /// .. pw-status-codes::
370 ///
371 /// OK: Returns the field.
372 ///
373 /// NOT_FOUND: The field is not present.
374 ///
375 /// DATA_LOSS: The serialized message is not a valid protobuf.
376 ///
377 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
378 ///
379 /// @endrst
FindSint64(ConstByteSpan message,uint32_t field_number)380 inline Result<int64_t> FindSint64(ConstByteSpan message,
381 uint32_t field_number) {
382 return internal::Find<int64_t, &Decoder::ReadSint64>(message, field_number);
383 }
384
385 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSint64(ConstByteSpan message,T field)386 inline Result<int64_t> FindSint64(ConstByteSpan message, T field) {
387 return FindSint64(message, static_cast<uint32_t>(field));
388 }
389
390 /// @brief Scans a serialized protobuf message for an `sint64` field.
391 ///
392 /// @param message_stream The serialized message to search.
393 /// @param field_number Protobuf field number of the field.
394 ///
395 /// @returns @rst
396 ///
397 /// .. pw-status-codes::
398 ///
399 /// OK: Returns the field.
400 ///
401 /// NOT_FOUND: The field is not present.
402 ///
403 /// DATA_LOSS: The serialized message is not a valid protobuf.
404 ///
405 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
406 ///
407 /// @endrst
FindSint64(stream::Reader & message_stream,uint32_t field_number)408 inline Result<int64_t> FindSint64(stream::Reader& message_stream,
409 uint32_t field_number) {
410 return internal::Find<int64_t, &StreamDecoder::ReadSint64>(message_stream,
411 field_number);
412 }
413
414 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSint64(stream::Reader & message_stream,T field)415 inline Result<int64_t> FindSint64(stream::Reader& message_stream, T field) {
416 return FindSint64(message_stream, static_cast<uint32_t>(field));
417 }
418
419 /// @brief Scans a serialized protobuf message for a `bool` field.
420 ///
421 /// @param message The serialized message to search.
422 /// @param field_number Protobuf field number of the field.
423 ///
424 /// @returns @rst
425 ///
426 /// .. pw-status-codes::
427 ///
428 /// OK: Returns the field.
429 ///
430 /// NOT_FOUND: The field is not present.
431 ///
432 /// DATA_LOSS: The serialized message is not a valid protobuf.
433 ///
434 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
435 ///
436 /// @endrst
FindBool(ConstByteSpan message,uint32_t field_number)437 inline Result<bool> FindBool(ConstByteSpan message, uint32_t field_number) {
438 return internal::Find<bool, &Decoder::ReadBool>(message, field_number);
439 }
440
441 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindBool(ConstByteSpan message,T field)442 inline Result<bool> FindBool(ConstByteSpan message, T field) {
443 return FindBool(message, static_cast<uint32_t>(field));
444 }
445
446 /// @brief Scans a serialized protobuf message for a `bool` field.
447 ///
448 /// @param message_stream The serialized message to search.
449 /// @param field_number Protobuf field number of the field.
450 ///
451 /// @returns @rst
452 ///
453 /// .. pw-status-codes::
454 ///
455 /// OK: Returns the field.
456 ///
457 /// NOT_FOUND: The field is not present.
458 ///
459 /// DATA_LOSS: The serialized message is not a valid protobuf.
460 ///
461 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
462 ///
463 /// @endrst
FindBool(stream::Reader & message_stream,uint32_t field_number)464 inline Result<bool> FindBool(stream::Reader& message_stream,
465 uint32_t field_number) {
466 return internal::Find<bool, &StreamDecoder::ReadBool>(message_stream,
467 field_number);
468 }
469
470 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindBool(stream::Reader & message_stream,T field)471 inline Result<bool> FindBool(stream::Reader& message_stream, T field) {
472 return FindBool(message_stream, static_cast<uint32_t>(field));
473 }
474
475 /// @brief Scans a serialized protobuf message for a `fixed32` field.
476 ///
477 /// @param message The serialized message to search.
478 /// @param field_number Protobuf field number of the field.
479 ///
480 /// @returns @rst
481 ///
482 /// .. pw-status-codes::
483 ///
484 /// OK: Returns the field.
485 ///
486 /// NOT_FOUND: The field is not present.
487 ///
488 /// DATA_LOSS: The serialized message is not a valid protobuf.
489 ///
490 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
491 ///
492 /// @endrst
FindFixed32(ConstByteSpan message,uint32_t field_number)493 inline Result<uint32_t> FindFixed32(ConstByteSpan message,
494 uint32_t field_number) {
495 return internal::Find<uint32_t, &Decoder::ReadFixed32>(message, field_number);
496 }
497
498 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindFixed32(ConstByteSpan message,T field)499 inline Result<uint32_t> FindFixed32(ConstByteSpan message, T field) {
500 return FindFixed32(message, static_cast<uint32_t>(field));
501 }
502
503 /// @brief Scans a serialized protobuf message for a `fixed32` field.
504 ///
505 /// @param message_stream The serialized message to search.
506 /// @param field_number Protobuf field number of the field.
507 ///
508 /// @returns @rst
509 ///
510 /// .. pw-status-codes::
511 ///
512 /// OK: Returns the field.
513 ///
514 /// NOT_FOUND: The field is not present.
515 ///
516 /// DATA_LOSS: The serialized message is not a valid protobuf.
517 ///
518 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
519 ///
520 /// @endrst
FindFixed32(stream::Reader & message_stream,uint32_t field_number)521 inline Result<uint32_t> FindFixed32(stream::Reader& message_stream,
522 uint32_t field_number) {
523 return internal::Find<uint32_t, &StreamDecoder::ReadFixed32>(message_stream,
524 field_number);
525 }
526
527 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindFixed32(stream::Reader & message_stream,T field)528 inline Result<uint32_t> FindFixed32(stream::Reader& message_stream, T field) {
529 return FindFixed32(message_stream, static_cast<uint32_t>(field));
530 }
531
532 /// @brief Scans a serialized protobuf message for a `fixed64` field.
533 ///
534 /// @param message The serialized message to search.
535 /// @param field_number Protobuf field number of the field.
536 ///
537 /// @returns @rst
538 ///
539 /// .. pw-status-codes::
540 ///
541 /// OK: Returns the field.
542 ///
543 /// NOT_FOUND: The field is not present.
544 ///
545 /// DATA_LOSS: The serialized message is not a valid protobuf.
546 ///
547 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
548 ///
549 /// @endrst
FindFixed64(ConstByteSpan message,uint32_t field_number)550 inline Result<uint64_t> FindFixed64(ConstByteSpan message,
551 uint32_t field_number) {
552 return internal::Find<uint64_t, &Decoder::ReadFixed64>(message, field_number);
553 }
554
555 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindFixed64(ConstByteSpan message,T field)556 inline Result<uint64_t> FindFixed64(ConstByteSpan message, T field) {
557 return FindFixed64(message, static_cast<uint32_t>(field));
558 }
559
560 /// @brief Scans a serialized protobuf message for a `fixed64` field.
561 ///
562 /// @param message_stream The serialized message to search.
563 /// @param field_number Protobuf field number of the field.
564 ///
565 /// @returns @rst
566 ///
567 /// .. pw-status-codes::
568 ///
569 /// OK: Returns the field.
570 ///
571 /// NOT_FOUND: The field is not present.
572 ///
573 /// DATA_LOSS: The serialized message is not a valid protobuf.
574 ///
575 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
576 ///
577 /// @endrst
FindFixed64(stream::Reader & message_stream,uint32_t field_number)578 inline Result<uint64_t> FindFixed64(stream::Reader& message_stream,
579 uint32_t field_number) {
580 return internal::Find<uint64_t, &StreamDecoder::ReadFixed64>(message_stream,
581 field_number);
582 }
583
584 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindFixed64(stream::Reader & message_stream,T field)585 inline Result<uint64_t> FindFixed64(stream::Reader& message_stream, T field) {
586 return FindFixed64(message_stream, static_cast<uint32_t>(field));
587 }
588
589 /// @brief Scans a serialized protobuf message for an `sfixed32` field.
590 ///
591 /// @param message The serialized message to search.
592 /// @param field_number Protobuf field number of the field.
593 ///
594 /// @returns @rst
595 ///
596 /// .. pw-status-codes::
597 ///
598 /// OK: Returns the field.
599 ///
600 /// NOT_FOUND: The field is not present.
601 ///
602 /// DATA_LOSS: The serialized message is not a valid protobuf.
603 ///
604 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
605 ///
606 /// @endrst
FindSfixed32(ConstByteSpan message,uint32_t field_number)607 inline Result<int32_t> FindSfixed32(ConstByteSpan message,
608 uint32_t field_number) {
609 return internal::Find<int32_t, &Decoder::ReadSfixed32>(message, field_number);
610 }
611
612 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSfixed32(ConstByteSpan message,T field)613 inline Result<int32_t> FindSfixed32(ConstByteSpan message, T field) {
614 return FindSfixed32(message, static_cast<uint32_t>(field));
615 }
616
617 /// @brief Scans a serialized protobuf message for an `sfixed32` field.
618 ///
619 /// @param message_stream The serialized message to search.
620 /// @param field_number Protobuf field number of the field.
621 ///
622 /// @returns @rst
623 ///
624 /// .. pw-status-codes::
625 ///
626 /// OK: Returns the field.
627 ///
628 /// NOT_FOUND: The field is not present.
629 ///
630 /// DATA_LOSS: The serialized message is not a valid protobuf.
631 ///
632 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
633 ///
634 /// @endrst
FindSfixed32(stream::Reader & message_stream,uint32_t field_number)635 inline Result<int32_t> FindSfixed32(stream::Reader& message_stream,
636 uint32_t field_number) {
637 return internal::Find<int32_t, &StreamDecoder::ReadSfixed32>(message_stream,
638 field_number);
639 }
640
641 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSfixed32(stream::Reader & message_stream,T field)642 inline Result<int32_t> FindSfixed32(stream::Reader& message_stream, T field) {
643 return FindSfixed32(message_stream, static_cast<uint32_t>(field));
644 }
645
646 /// @brief Scans a serialized protobuf message for an `sfixed64` field.
647 ///
648 /// @param message The serialized message to search.
649 /// @param field_number Protobuf field number of the field.
650 ///
651 /// @returns @rst
652 ///
653 /// .. pw-status-codes::
654 ///
655 /// OK: Returns the field.
656 ///
657 /// NOT_FOUND: The field is not present.
658 ///
659 /// DATA_LOSS: The serialized message is not a valid protobuf.
660 ///
661 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
662 ///
663 /// @endrst
FindSfixed64(ConstByteSpan message,uint32_t field_number)664 inline Result<int64_t> FindSfixed64(ConstByteSpan message,
665 uint32_t field_number) {
666 return internal::Find<int64_t, &Decoder::ReadSfixed64>(message, field_number);
667 }
668
669 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSfixed64(ConstByteSpan message,T field)670 inline Result<int64_t> FindSfixed64(ConstByteSpan message, T field) {
671 return FindSfixed64(message, static_cast<uint32_t>(field));
672 }
673
674 /// @brief Scans a serialized protobuf message for an `sfixed64` field.
675 ///
676 /// @param message_stream The serialized message to search.
677 /// @param field_number Protobuf field number of the field.
678 ///
679 /// @returns @rst
680 ///
681 /// .. pw-status-codes::
682 ///
683 /// OK: Returns the field.
684 ///
685 /// NOT_FOUND: The field is not present.
686 ///
687 /// DATA_LOSS: The serialized message is not a valid protobuf.
688 ///
689 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
690 ///
691 /// @endrst
FindSfixed64(stream::Reader & message_stream,uint32_t field_number)692 inline Result<int64_t> FindSfixed64(stream::Reader& message_stream,
693 uint32_t field_number) {
694 return internal::Find<int64_t, &StreamDecoder::ReadSfixed64>(message_stream,
695 field_number);
696 }
697
698 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSfixed64(stream::Reader & message_stream,T field)699 inline Result<int64_t> FindSfixed64(stream::Reader& message_stream, T field) {
700 return FindSfixed64(message_stream, static_cast<uint32_t>(field));
701 }
702
703 /// @brief Scans a serialized protobuf message for a `float` field.
704 ///
705 /// @param message The serialized message to search.
706 /// @param field_number Protobuf field number of the field.
707 ///
708 /// @returns @rst
709 ///
710 /// .. pw-status-codes::
711 ///
712 /// OK: Returns the field.
713 ///
714 /// NOT_FOUND: The field is not present.
715 ///
716 /// DATA_LOSS: The serialized message is not a valid protobuf.
717 ///
718 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
719 ///
720 /// @endrst
FindFloat(ConstByteSpan message,uint32_t field_number)721 inline Result<float> FindFloat(ConstByteSpan message, uint32_t field_number) {
722 return internal::Find<float, &Decoder::ReadFloat>(message, field_number);
723 }
724
725 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindFloat(ConstByteSpan message,T field)726 inline Result<float> FindFloat(ConstByteSpan message, T field) {
727 return FindFloat(message, static_cast<uint32_t>(field));
728 }
729
730 /// @brief Scans a serialized protobuf message for a `float` field.
731 ///
732 /// @param message_stream The serialized message to search.
733 /// @param field_number Protobuf field number of the field.
734 ///
735 /// @returns @rst
736 ///
737 /// .. pw-status-codes::
738 ///
739 /// OK: Returns the field.
740 ///
741 /// NOT_FOUND: The field is not present.
742 ///
743 /// DATA_LOSS: The serialized message is not a valid protobuf.
744 ///
745 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
746 ///
747 /// @endrst
FindFloat(stream::Reader & message_stream,uint32_t field_number)748 inline Result<float> FindFloat(stream::Reader& message_stream,
749 uint32_t field_number) {
750 return internal::Find<float, &StreamDecoder::ReadFloat>(message_stream,
751 field_number);
752 }
753
754 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindFloat(stream::Reader & message_stream,T field)755 inline Result<float> FindFloat(stream::Reader& message_stream, T field) {
756 return FindFloat(message_stream, static_cast<uint32_t>(field));
757 }
758
759 /// @brief Scans a serialized protobuf message for a `double` field.
760 ///
761 /// @param message The serialized message to search.
762 /// @param field_number Protobuf field number of the field.
763 ///
764 /// @returns @rst
765 ///
766 /// .. pw-status-codes::
767 ///
768 /// OK: Returns the field.
769 ///
770 /// NOT_FOUND: The field is not present.
771 ///
772 /// DATA_LOSS: The serialized message is not a valid protobuf.
773 ///
774 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
775 ///
776 /// @endrst
FindDouble(ConstByteSpan message,uint32_t field_number)777 inline Result<double> FindDouble(ConstByteSpan message, uint32_t field_number) {
778 return internal::Find<double, &Decoder::ReadDouble>(message, field_number);
779 }
780
781 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindDouble(ConstByteSpan message,T field)782 inline Result<double> FindDouble(ConstByteSpan message, T field) {
783 return FindDouble(message, static_cast<uint32_t>(field));
784 }
785
786 /// @brief Scans a serialized protobuf message for a `double` field.
787 ///
788 /// @param message_stream The serialized message to search.
789 /// @param field_number Protobuf field number of the field.
790 ///
791 /// @returns @rst
792 ///
793 /// .. pw-status-codes::
794 ///
795 /// OK: Returns the field.
796 ///
797 /// NOT_FOUND: The field is not present.
798 ///
799 /// DATA_LOSS: The serialized message is not a valid protobuf.
800 ///
801 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
802 ///
803 /// @endrst
804
FindDouble(stream::Reader & message_stream,uint32_t field_number)805 inline Result<double> FindDouble(stream::Reader& message_stream,
806 uint32_t field_number) {
807 return internal::Find<double, &StreamDecoder::ReadDouble>(message_stream,
808 field_number);
809 }
810
811 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindDouble(stream::Reader & message_stream,T field)812 inline Result<double> FindDouble(stream::Reader& message_stream, T field) {
813 return FindDouble(message_stream, static_cast<uint32_t>(field));
814 }
815
816 /// @brief Scans a serialized protobuf message for a `string` field.
817 ///
818 /// @param message The serialized message to search.
819 /// @param field_number Protobuf field number of the field.
820 ///
821 /// @returns @rst
822 ///
823 /// .. pw-status-codes::
824 ///
825 /// OK: Returns a subspan of the buffer containing the string field.
826 /// **NOTE**: The returned string is NOT null-terminated.
827 ///
828 /// NOT_FOUND: The field is not present.
829 ///
830 /// DATA_LOSS: The serialized message is not a valid protobuf.
831 ///
832 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
833 ///
834 /// @endrst
FindString(ConstByteSpan message,uint32_t field_number)835 inline Result<std::string_view> FindString(ConstByteSpan message,
836 uint32_t field_number) {
837 return internal::Find<std::string_view, &Decoder::ReadString>(message,
838 field_number);
839 }
840
841 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindString(ConstByteSpan message,T field)842 inline Result<std::string_view> FindString(ConstByteSpan message, T field) {
843 return FindString(message, static_cast<uint32_t>(field));
844 }
845
846 /// @brief Scans a serialized protobuf message for a `string`field, copying its
847 /// data into the provided buffer.
848 ///
849 /// @param message_stream The serialized message to search.
850 /// @param field_number Protobuf field number of the field.
851 /// @param out The buffer to which to write the string.
852 ///
853 /// @returns @rst
854 ///
855 /// .. pw-status-codes::
856 ///
857 /// OK: Returns the size of the copied data.
858 /// **NOTE**: The returned string is NOT null-terminated.
859 ///
860 /// NOT_FOUND: The field is not present.
861 ///
862 /// DATA_LOSS: The serialized message is not a valid protobuf.
863 ///
864 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
865 ///
866 /// @endrst
FindString(stream::Reader & message_stream,uint32_t field_number,span<char> out)867 inline StatusWithSize FindString(stream::Reader& message_stream,
868 uint32_t field_number,
869 span<char> out) {
870 StreamDecoder decoder(message_stream);
871 Status status = internal::AdvanceToField(decoder, field_number);
872 if (!status.ok()) {
873 return StatusWithSize(status, 0);
874 }
875 StatusWithSize sws = decoder.ReadString(out);
876
877 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
878 // a field. Remap this to FAILED_PRECONDITION for consistency with the
879 // non-stream Find.
880 return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
881 }
882
883 /// @brief Scans a serialized protobuf message for a `string`field, copying its
884 /// data into the provided buffer.
885 ///
886 /// @param message_stream The serialized message to search.
887 /// @param field_number Protobuf field number of the field.
888 /// @param out String to which to write the found value.
889 ///
890 /// @returns @rst
891 ///
892 /// .. pw-status-codes::
893 ///
894 /// OK: Returns the size of the copied data.
895 ///
896 /// NOT_FOUND: The field is not present.
897 ///
898 /// DATA_LOSS: The serialized message is not a valid protobuf.
899 ///
900 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
901 ///
902 /// @endrst
FindString(stream::Reader & message_stream,uint32_t field_number,InlineString<> & out)903 inline StatusWithSize FindString(stream::Reader& message_stream,
904 uint32_t field_number,
905 InlineString<>& out) {
906 StatusWithSize sws;
907
908 out.resize_and_overwrite([&](char* data, size_t size) {
909 sws = FindString(message_stream, field_number, span(data, size));
910 return sws.size();
911 });
912
913 return sws;
914 }
915
916 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindString(stream::Reader & message_stream,T field,span<char> out)917 inline StatusWithSize FindString(stream::Reader& message_stream,
918 T field,
919 span<char> out) {
920 return FindString(message_stream, static_cast<uint32_t>(field), out);
921 }
922
923 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindString(stream::Reader & message_stream,T field,InlineString<> & out)924 inline StatusWithSize FindString(stream::Reader& message_stream,
925 T field,
926 InlineString<>& out) {
927 return FindString(message_stream, static_cast<uint32_t>(field), out);
928 }
929
930 /// @brief Scans a serialized protobuf message for a `bytes` field.
931 ///
932 /// @param message The serialized message to search.
933 /// @param field_number Protobuf field number of the field.
934 ///
935 /// @returns @rst
936 ///
937 /// .. pw-status-codes::
938 ///
939 /// OK: Returns the subspan of the buffer containing the bytes field.
940 ///
941 /// NOT_FOUND: The field is not present.
942 ///
943 /// DATA_LOSS: The serialized message is not a valid protobuf.
944 ///
945 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
946 ///
947 /// @endrst
FindBytes(ConstByteSpan message,uint32_t field_number)948 inline Result<ConstByteSpan> FindBytes(ConstByteSpan message,
949 uint32_t field_number) {
950 return internal::Find<ConstByteSpan, &Decoder::ReadBytes>(message,
951 field_number);
952 }
953
954 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindBytes(ConstByteSpan message,T field)955 inline Result<ConstByteSpan> FindBytes(ConstByteSpan message, T field) {
956 return FindBytes(message, static_cast<uint32_t>(field));
957 }
958
959 /// @brief Scans a serialized protobuf message for a `bytes` field, copying its
960 /// data into the provided buffer.
961 ///
962 /// @param message_stream The serialized message to search.
963 /// @param field_number Protobuf field number of the field.
964 ///
965 /// @returns @rst
966 ///
967 /// .. pw-status-codes::
968 ///
969 /// OK: Returns the size of the copied data.
970 ///
971 /// NOT_FOUND: The field is not present.
972 ///
973 /// DATA_LOSS: The serialized message is not a valid protobuf.
974 ///
975 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
976 ///
977 /// @endrst
FindBytes(stream::Reader & message_stream,uint32_t field_number,ByteSpan out)978 inline StatusWithSize FindBytes(stream::Reader& message_stream,
979 uint32_t field_number,
980 ByteSpan out) {
981 StreamDecoder decoder(message_stream);
982 Status status = internal::AdvanceToField(decoder, field_number);
983 if (!status.ok()) {
984 return StatusWithSize(status, 0);
985 }
986 StatusWithSize sws = decoder.ReadBytes(out);
987
988 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
989 // a field. Remap this to FAILED_PRECONDITION for consistency with the
990 // non-stream Find.
991 return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
992 }
993
994 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindBytes(stream::Reader & message_stream,T field,ByteSpan out)995 inline StatusWithSize FindBytes(stream::Reader& message_stream,
996 T field,
997 ByteSpan out) {
998 return FindBytes(message_stream, static_cast<uint32_t>(field), out);
999 }
1000
1001 /// @brief Scans a serialized protobuf message for a submessage.
1002 ///
1003 /// @param message The serialized message to search.
1004 /// @param field_number Protobuf field number of the field.
1005 ///
1006 /// @returns @rst
1007 ///
1008 /// .. pw-status-codes::
1009 ///
1010 /// OK: Returns the subspan of the buffer containing the submessage.
1011 ///
1012 /// NOT_FOUND: The field is not present.
1013 ///
1014 /// DATA_LOSS: The serialized message is not a valid protobuf.
1015 ///
1016 /// FAILED_PRECONDITION: The field exists, but is not the correct type.
1017 ///
1018 /// @endrst
FindSubmessage(ConstByteSpan message,uint32_t field_number)1019 inline Result<ConstByteSpan> FindSubmessage(ConstByteSpan message,
1020 uint32_t field_number) {
1021 // On the wire, a submessage is identical to bytes. This function exists only
1022 // to clarify users' intent.
1023 return FindBytes(message, field_number);
1024 }
1025
1026 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindSubmessage(ConstByteSpan message,T field)1027 inline Result<ConstByteSpan> FindSubmessage(ConstByteSpan message, T field) {
1028 return FindSubmessage(message, static_cast<uint32_t>(field));
1029 }
1030
1031 /// Returns a span containing the raw bytes of the value.
FindRaw(ConstByteSpan message,uint32_t field_number)1032 inline Result<ConstByteSpan> FindRaw(ConstByteSpan message,
1033 uint32_t field_number) {
1034 Decoder decoder(message);
1035 PW_TRY(internal::AdvanceToField(decoder, field_number));
1036 return decoder.RawFieldBytes();
1037 }
1038
1039 template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
FindRaw(ConstByteSpan message,T field)1040 Result<ConstByteSpan> FindRaw(ConstByteSpan message, T field) {
1041 return FindRaw(message, static_cast<uint32_t>(field));
1042 }
1043
1044 } // namespace pw::protobuf
1045