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