• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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