C/C++ API Reference
Loading...
Searching...
No Matches
find.h
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#include "pw_bytes/span.h"
17#include "pw_protobuf/decoder.h"
18#include "pw_protobuf/stream_decoder.h"
19#include "pw_result/result.h"
20#include "pw_status/try.h"
21#include "pw_string/string.h"
22
23namespace pw::protobuf {
24
25namespace internal {
26
27Status AdvanceToField(Decoder& decoder, uint32_t field_number);
28Status AdvanceToField(StreamDecoder& decoder, uint32_t field_number);
29
30} // namespace internal
31
33
34template <typename T, auto kReadFn>
35class Finder {
36 public:
37 constexpr Finder(ConstByteSpan message, uint32_t field_number)
38 : decoder_(message), field_number_(field_number) {}
39
40 Result<T> Next() {
41 T output;
42 PW_TRY(internal::AdvanceToField(decoder_, field_number_));
43 PW_TRY((decoder_.*kReadFn)(&output));
44 return output;
45 }
46
47 private:
48 Decoder decoder_;
49 uint32_t field_number_;
50};
51
52template <typename T, auto kReadFn>
54 public:
55 constexpr StreamFinder(stream::Reader& reader, uint32_t field_number)
56 : decoder_(reader), field_number_(field_number) {}
57
58 Result<T> Next() {
59 PW_TRY(internal::AdvanceToField(decoder_, field_number_));
60 Result<T> result = (decoder_.*kReadFn)();
61
62 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type
63 // for a field. Remap this to FAILED_PRECONDITION for consistency with the
64 // non-stream Find.
65 return result.status().IsNotFound()
67 : result;
68 }
69
70 private:
71 StreamDecoder decoder_;
72 uint32_t field_number_;
73};
74
75template <typename T>
76class EnumFinder : private Finder<uint32_t, &Decoder::ReadUint32> {
77 public:
78 using Finder::Finder;
79
80 Result<T> Next() {
81 Result<uint32_t> result = Finder::Next();
82 if (!result.ok()) {
83 return result.status();
84 }
85 return static_cast<T>(result.value());
86 }
87};
88
89template <typename T>
91 : private StreamFinder<uint32_t, &StreamDecoder::ReadUint32> {
92 public:
93 using StreamFinder::StreamFinder;
94
95 Result<T> Next() {
96 Result<uint32_t> result = StreamFinder::Next();
97 if (!result.ok()) {
98 return result.status();
99 }
100 return static_cast<T>(result.value());
101 }
102};
103
105
106namespace internal {
107template <typename T, auto kReadFn>
108Result<T> Find(ConstByteSpan message, uint32_t field_number) {
109 Finder<T, kReadFn> finder(message, field_number);
110 return finder.Next();
111}
112
113template <typename T, auto kReadFn>
114Result<T> Find(stream::Reader& reader, uint32_t field_number) {
115 StreamFinder<T, kReadFn> finder(reader, field_number);
116 return finder.Next();
117}
118
119} // namespace internal
120
122
133 uint32_t field_number) {
134 return internal::Find<uint32_t, &Decoder::ReadUint32>(message, field_number);
135}
136
137template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
138inline Result<uint32_t> FindUint32(ConstByteSpan message, T field) {
139 return FindUint32(message, static_cast<uint32_t>(field));
140}
141
152 uint32_t field_number) {
153 return internal::Find<uint32_t, &StreamDecoder::ReadUint32>(message_stream,
154 field_number);
155}
156
157template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
158inline Result<uint32_t> FindUint32(stream::Reader& message_stream, T field) {
159 return FindUint32(message_stream, static_cast<uint32_t>(field));
160}
161
162using Uint32Finder = Finder<uint32_t, &Decoder::ReadUint32>;
163using Uint32StreamFinder = StreamFinder<uint32_t, &StreamDecoder::ReadUint32>;
164
174inline Result<int32_t> FindInt32(ConstByteSpan message, uint32_t field_number) {
175 return internal::Find<int32_t, &Decoder::ReadInt32>(message, field_number);
176}
177
178template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
179inline Result<int32_t> FindInt32(ConstByteSpan message, T field) {
180 return FindInt32(message, static_cast<uint32_t>(field));
181}
182
193 uint32_t field_number) {
194 return internal::Find<int32_t, &StreamDecoder::ReadInt32>(message_stream,
195 field_number);
196}
197
198template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
199inline Result<int32_t> FindInt32(stream::Reader& message_stream, T field) {
200 return FindInt32(message_stream, static_cast<uint32_t>(field));
201}
202
203using Int32Finder = Finder<int32_t, &Decoder::ReadInt32>;
204using Int32StreamFinder = StreamFinder<int32_t, &StreamDecoder::ReadInt32>;
205
216 uint32_t field_number) {
217 return internal::Find<int32_t, &Decoder::ReadSint32>(message, field_number);
218}
219
220template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
221inline Result<int32_t> FindSint32(ConstByteSpan message, T field) {
222 return FindSint32(message, static_cast<uint32_t>(field));
223}
224
235 uint32_t field_number) {
236 return internal::Find<int32_t, &StreamDecoder::ReadSint32>(message_stream,
237 field_number);
238}
239
240template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
241inline Result<int32_t> FindSint32(stream::Reader& message_stream, T field) {
242 return FindSint32(message_stream, static_cast<uint32_t>(field));
243}
244
245using Sint32Finder = Finder<int32_t, &Decoder::ReadSint32>;
246using Sint32StreamFinder = StreamFinder<int32_t, &StreamDecoder::ReadSint32>;
247
258 uint32_t field_number) {
259 return internal::Find<uint64_t, &Decoder::ReadUint64>(message, field_number);
260}
261
262template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
263inline Result<uint64_t> FindUint64(ConstByteSpan message, T field) {
264 return FindUint64(message, static_cast<uint32_t>(field));
265}
266
277 uint32_t field_number) {
278 return internal::Find<uint64_t, &StreamDecoder::ReadUint64>(message_stream,
279 field_number);
280}
281
282template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
283inline Result<uint64_t> FindUint64(stream::Reader& message_stream, T field) {
284 return FindUint64(message_stream, static_cast<uint32_t>(field));
285}
286
287using Uint64Finder = Finder<uint64_t, &Decoder::ReadUint64>;
288using Uint64StreamFinder = StreamFinder<uint64_t, &StreamDecoder::ReadUint64>;
289
299inline Result<int64_t> FindInt64(ConstByteSpan message, uint32_t field_number) {
300 return internal::Find<int64_t, &Decoder::ReadInt64>(message, field_number);
301}
302
303template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
304inline Result<int64_t> FindInt64(ConstByteSpan message, T field) {
305 return FindInt64(message, static_cast<uint32_t>(field));
306}
307
318 uint32_t field_number) {
319 return internal::Find<int64_t, &StreamDecoder::ReadInt64>(message_stream,
320 field_number);
321}
322
323template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
324inline Result<int64_t> FindInt64(stream::Reader& message_stream, T field) {
325 return FindInt64(message_stream, static_cast<uint32_t>(field));
326}
327
328using Int64Finder = Finder<int64_t, &Decoder::ReadInt64>;
329using Int64StreamFinder = StreamFinder<int64_t, &StreamDecoder::ReadInt64>;
330
341 uint32_t field_number) {
342 return internal::Find<int64_t, &Decoder::ReadSint64>(message, field_number);
343}
344
345template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
346inline Result<int64_t> FindSint64(ConstByteSpan message, T field) {
347 return FindSint64(message, static_cast<uint32_t>(field));
348}
349
360 uint32_t field_number) {
361 return internal::Find<int64_t, &StreamDecoder::ReadSint64>(message_stream,
362 field_number);
363}
364
365template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
366inline Result<int64_t> FindSint64(stream::Reader& message_stream, T field) {
367 return FindSint64(message_stream, static_cast<uint32_t>(field));
368}
369
370using Sint64Finder = Finder<int64_t, &Decoder::ReadSint64>;
371using Sint64StreamFinder = StreamFinder<int64_t, &StreamDecoder::ReadSint64>;
372
382inline Result<bool> FindBool(ConstByteSpan message, uint32_t field_number) {
383 return internal::Find<bool, &Decoder::ReadBool>(message, field_number);
384}
385
386template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
387inline Result<bool> FindBool(ConstByteSpan message, T field) {
388 return FindBool(message, static_cast<uint32_t>(field));
389}
390
400inline Result<bool> FindBool(stream::Reader& message_stream,
401 uint32_t field_number) {
402 return internal::Find<bool, &StreamDecoder::ReadBool>(message_stream,
403 field_number);
404}
405
406template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
407inline Result<bool> FindBool(stream::Reader& message_stream, T field) {
408 return FindBool(message_stream, static_cast<uint32_t>(field));
409}
410
411using BoolFinder = Finder<bool, &Decoder::ReadBool>;
412using BoolStreamFinder = StreamFinder<bool, &StreamDecoder::ReadBool>;
413
424 uint32_t field_number) {
425 return internal::Find<uint32_t, &Decoder::ReadFixed32>(message, field_number);
426}
427
428template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
429inline Result<uint32_t> FindFixed32(ConstByteSpan message, T field) {
430 return FindFixed32(message, static_cast<uint32_t>(field));
431}
432
443 uint32_t field_number) {
444 return internal::Find<uint32_t, &StreamDecoder::ReadFixed32>(message_stream,
445 field_number);
446}
447
448template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
449inline Result<uint32_t> FindFixed32(stream::Reader& message_stream, T field) {
450 return FindFixed32(message_stream, static_cast<uint32_t>(field));
451}
452
453using Fixed32Finder = Finder<uint32_t, &Decoder::ReadFixed32>;
454using Fixed32StreamFinder = StreamFinder<uint32_t, &StreamDecoder::ReadFixed32>;
455
466 uint32_t field_number) {
467 return internal::Find<uint64_t, &Decoder::ReadFixed64>(message, field_number);
468}
469
470template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
471inline Result<uint64_t> FindFixed64(ConstByteSpan message, T field) {
472 return FindFixed64(message, static_cast<uint32_t>(field));
473}
474
485 uint32_t field_number) {
486 return internal::Find<uint64_t, &StreamDecoder::ReadFixed64>(message_stream,
487 field_number);
488}
489
490template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
491inline Result<uint64_t> FindFixed64(stream::Reader& message_stream, T field) {
492 return FindFixed64(message_stream, static_cast<uint32_t>(field));
493}
494
495using Fixed64Finder = Finder<uint64_t, &Decoder::ReadFixed64>;
496using Fixed64StreamFinder = StreamFinder<uint64_t, &StreamDecoder::ReadFixed64>;
497
508 uint32_t field_number) {
509 return internal::Find<int32_t, &Decoder::ReadSfixed32>(message, field_number);
510}
511
512template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
513inline Result<int32_t> FindSfixed32(ConstByteSpan message, T field) {
514 return FindSfixed32(message, static_cast<uint32_t>(field));
515}
516
527 uint32_t field_number) {
528 return internal::Find<int32_t, &StreamDecoder::ReadSfixed32>(message_stream,
529 field_number);
530}
531
532template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
533inline Result<int32_t> FindSfixed32(stream::Reader& message_stream, T field) {
534 return FindSfixed32(message_stream, static_cast<uint32_t>(field));
535}
536
537using Sfixed32Finder = Finder<int32_t, &Decoder::ReadSfixed32>;
538using Sfixed32StreamFinder =
539 StreamFinder<int32_t, &StreamDecoder::ReadSfixed32>;
540
551 uint32_t field_number) {
552 return internal::Find<int64_t, &Decoder::ReadSfixed64>(message, field_number);
553}
554
555template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
556inline Result<int64_t> FindSfixed64(ConstByteSpan message, T field) {
557 return FindSfixed64(message, static_cast<uint32_t>(field));
558}
559
570 uint32_t field_number) {
571 return internal::Find<int64_t, &StreamDecoder::ReadSfixed64>(message_stream,
572 field_number);
573}
574
575template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
576inline Result<int64_t> FindSfixed64(stream::Reader& message_stream, T field) {
577 return FindSfixed64(message_stream, static_cast<uint32_t>(field));
578}
579
580using Sfixed64Finder = Finder<int64_t, &Decoder::ReadSfixed64>;
581using Sfixed64StreamFinder =
582 StreamFinder<int64_t, &StreamDecoder::ReadSfixed64>;
583
593inline Result<float> FindFloat(ConstByteSpan message, uint32_t field_number) {
594 return internal::Find<float, &Decoder::ReadFloat>(message, field_number);
595}
596
597template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
598inline Result<float> FindFloat(ConstByteSpan message, T field) {
599 return FindFloat(message, static_cast<uint32_t>(field));
600}
601
612 uint32_t field_number) {
613 return internal::Find<float, &StreamDecoder::ReadFloat>(message_stream,
614 field_number);
615}
616
617template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
618inline Result<float> FindFloat(stream::Reader& message_stream, T field) {
619 return FindFloat(message_stream, static_cast<uint32_t>(field));
620}
621
622using FloatFinder = Finder<float, &Decoder::ReadFloat>;
623using FloatStreamFinder = StreamFinder<float, &StreamDecoder::ReadFloat>;
624
634inline Result<double> FindDouble(ConstByteSpan message, uint32_t field_number) {
635 return internal::Find<double, &Decoder::ReadDouble>(message, field_number);
636}
637
638template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
639inline Result<double> FindDouble(ConstByteSpan message, T field) {
640 return FindDouble(message, static_cast<uint32_t>(field));
641}
642
653 uint32_t field_number) {
654 return internal::Find<double, &StreamDecoder::ReadDouble>(message_stream,
655 field_number);
656}
657
658template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
659inline Result<double> FindDouble(stream::Reader& message_stream, T field) {
660 return FindDouble(message_stream, static_cast<uint32_t>(field));
661}
662
663using DoubleFinder = Finder<double, &Decoder::ReadDouble>;
664using DoubleStreamFinder = StreamFinder<double, &StreamDecoder::ReadDouble>;
665
678 uint32_t field_number) {
679 return internal::Find<std::string_view, &Decoder::ReadString>(message,
680 field_number);
681}
682
683template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
684inline Result<std::string_view> FindString(ConstByteSpan message, T field) {
685 return FindString(message, static_cast<uint32_t>(field));
686}
687
703 uint32_t field_number,
704 span<char> out) {
705 StreamDecoder decoder(message_stream);
706 Status status = internal::AdvanceToField(decoder, field_number);
707 if (!status.ok()) {
708 return StatusWithSize(status, 0);
709 }
710 StatusWithSize sws = decoder.ReadString(out);
711
712 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
713 // a field. Remap this to FAILED_PRECONDITION for consistency with the
714 // non-stream Find.
715 return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
716}
717
731 uint32_t field_number,
732 InlineString<>& out) {
733 StatusWithSize sws;
734
735 out.resize_and_overwrite([&](char* data, size_t size) {
736 sws = FindString(message_stream, field_number, span(data, size));
737 return sws.size();
738 });
739
740 return sws;
741}
742
743template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
744inline StatusWithSize FindString(stream::Reader& message_stream,
745 T field,
746 span<char> out) {
747 return FindString(message_stream, static_cast<uint32_t>(field), out);
748}
749
750template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
751inline StatusWithSize FindString(stream::Reader& message_stream,
752 T field,
753 InlineString<>& out) {
754 return FindString(message_stream, static_cast<uint32_t>(field), out);
755}
756
757using StringFinder = Finder<std::string_view, &Decoder::ReadString>;
758
769 uint32_t field_number) {
770 return internal::Find<ConstByteSpan, &Decoder::ReadBytes>(message,
771 field_number);
772}
773
774template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
775inline Result<ConstByteSpan> FindBytes(ConstByteSpan message, T field) {
776 return FindBytes(message, static_cast<uint32_t>(field));
777}
778
791 uint32_t field_number,
792 ByteSpan out) {
793 StreamDecoder decoder(message_stream);
794 Status status = internal::AdvanceToField(decoder, field_number);
795 if (!status.ok()) {
796 return StatusWithSize(status, 0);
797 }
798 StatusWithSize sws = decoder.ReadBytes(out);
799
800 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
801 // a field. Remap this to FAILED_PRECONDITION for consistency with the
802 // non-stream Find.
803 return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
804}
805
806template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
807inline StatusWithSize FindBytes(stream::Reader& message_stream,
808 T field,
809 ByteSpan out) {
810 return FindBytes(message_stream, static_cast<uint32_t>(field), out);
811}
812
813using BytesFinder = Finder<ConstByteSpan, &Decoder::ReadBytes>;
814
825 uint32_t field_number) {
826 // On the wire, a submessage is identical to bytes. This function exists only
827 // to clarify users' intent.
828 return FindBytes(message, field_number);
829}
830
831template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
832inline Result<ConstByteSpan> FindSubmessage(ConstByteSpan message, T field) {
833 return FindSubmessage(message, static_cast<uint32_t>(field));
834}
835
838 uint32_t field_number) {
839 Decoder decoder(message);
840 PW_TRY(internal::AdvanceToField(decoder, field_number));
841 return decoder.RawFieldBytes();
842}
843
844template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
846 return FindRaw(message, static_cast<uint32_t>(field));
847}
848
850
851} // namespace pw::protobuf
pw::InlineBasicString is a fixed-capacity version of std::basic_string. In brief:
Definition: string.h:68
Definition: result.h:143
constexpr bool ok() const
Definition: result.h:447
constexpr const T & value() const &PW_ATTRIBUTE_LIFETIME_BOUND
Definition: result.h:808
constexpr Status status() const
Definition: result.h:803
Definition: status.h:120
constexpr bool IsNotFound() const
Definition: status.h:365
constexpr bool ok() const
Definition: status.h:346
static constexpr Status FailedPrecondition()
Definition: status.h:243
Definition: status_with_size.h:51
constexpr size_t size() const
Definition: status_with_size.h:148
Definition: decoder.h:50
Definition: find.h:76
Definition: find.h:91
Definition: find.h:35
Definition: stream_decoder.h:69
Definition: find.h:53
Definition: stream.h:326
Result< int32_t > FindInt32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an int32 field.
Definition: find.h:174
Result< int64_t > FindInt64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an int64 field.
Definition: find.h:299
Result< int64_t > FindSfixed64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sfixed64 field.
Definition: find.h:550
Result< ConstByteSpan > FindRaw(ConstByteSpan message, uint32_t field_number)
Returns a span containing the raw bytes of the value.
Definition: find.h:837
Result< ConstByteSpan > FindBytes(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a bytes field.
Definition: find.h:768
Result< int64_t > FindSint64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sint64 field.
Definition: find.h:340
Result< int32_t > FindSfixed32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sfixed32 field.
Definition: find.h:507
Result< int32_t > FindSint32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sint32 field.
Definition: find.h:215
Result< float > FindFloat(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a float field.
Definition: find.h:593
Result< uint64_t > FindFixed64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a fixed64 field.
Definition: find.h:465
Result< uint32_t > FindFixed32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a fixed32 field.
Definition: find.h:423
Result< ConstByteSpan > FindSubmessage(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a submessage.
Definition: find.h:824
Result< std::string_view > FindString(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a string field.
Definition: find.h:677
Result< uint32_t > FindUint32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a uint32 field.
Definition: find.h:132
Result< uint64_t > FindUint64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a uint64 field.
Definition: find.h:257
Result< double > FindDouble(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a double field.
Definition: find.h:634
Result< bool > FindBool(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a bool field.
Definition: find.h:382
#define PW_TRY(expr)
Returns early if expr is a non-OK Status or Result.
Definition: try.h:27
pw::InlineBasicString and pw::InlineString are safer alternatives to std::basic_string and std::strin...