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
142 uint32_t field_number) {
143 return internal::Find<uint32_t, &Decoder::ReadUint32>(message, field_number);
144}
145
146template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
147inline Result<uint32_t> FindUint32(ConstByteSpan message, T field) {
148 return FindUint32(message, static_cast<uint32_t>(field));
149}
150
170 uint32_t field_number) {
171 return internal::Find<uint32_t, &StreamDecoder::ReadUint32>(message_stream,
172 field_number);
173}
174
175template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
176inline Result<uint32_t> FindUint32(stream::Reader& message_stream, T field) {
177 return FindUint32(message_stream, static_cast<uint32_t>(field));
178}
179
180using Uint32Finder = Finder<uint32_t, &Decoder::ReadUint32>;
181using Uint32StreamFinder = StreamFinder<uint32_t, &StreamDecoder::ReadUint32>;
182
201inline Result<int32_t> FindInt32(ConstByteSpan message, uint32_t field_number) {
202 return internal::Find<int32_t, &Decoder::ReadInt32>(message, field_number);
203}
204
205template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
206inline Result<int32_t> FindInt32(ConstByteSpan message, T field) {
207 return FindInt32(message, static_cast<uint32_t>(field));
208}
209
229 uint32_t field_number) {
230 return internal::Find<int32_t, &StreamDecoder::ReadInt32>(message_stream,
231 field_number);
232}
233
234template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
235inline Result<int32_t> FindInt32(stream::Reader& message_stream, T field) {
236 return FindInt32(message_stream, static_cast<uint32_t>(field));
237}
238
239using Int32Finder = Finder<int32_t, &Decoder::ReadInt32>;
240using Int32StreamFinder = StreamFinder<int32_t, &StreamDecoder::ReadInt32>;
241
261 uint32_t field_number) {
262 return internal::Find<int32_t, &Decoder::ReadSint32>(message, field_number);
263}
264
265template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
266inline Result<int32_t> FindSint32(ConstByteSpan message, T field) {
267 return FindSint32(message, static_cast<uint32_t>(field));
268}
269
289 uint32_t field_number) {
290 return internal::Find<int32_t, &StreamDecoder::ReadSint32>(message_stream,
291 field_number);
292}
293
294template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
295inline Result<int32_t> FindSint32(stream::Reader& message_stream, T field) {
296 return FindSint32(message_stream, static_cast<uint32_t>(field));
297}
298
299using Sint32Finder = Finder<int32_t, &Decoder::ReadSint32>;
300using Sint32StreamFinder = StreamFinder<int32_t, &StreamDecoder::ReadSint32>;
301
321 uint32_t field_number) {
322 return internal::Find<uint64_t, &Decoder::ReadUint64>(message, field_number);
323}
324
325template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
326inline Result<uint64_t> FindUint64(ConstByteSpan message, T field) {
327 return FindUint64(message, static_cast<uint32_t>(field));
328}
329
349 uint32_t field_number) {
350 return internal::Find<uint64_t, &StreamDecoder::ReadUint64>(message_stream,
351 field_number);
352}
353
354template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
355inline Result<uint64_t> FindUint64(stream::Reader& message_stream, T field) {
356 return FindUint64(message_stream, static_cast<uint32_t>(field));
357}
358
359using Uint64Finder = Finder<uint64_t, &Decoder::ReadUint64>;
360using Uint64StreamFinder = StreamFinder<uint64_t, &StreamDecoder::ReadUint64>;
361
380inline Result<int64_t> FindInt64(ConstByteSpan message, uint32_t field_number) {
381 return internal::Find<int64_t, &Decoder::ReadInt64>(message, field_number);
382}
383
384template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
385inline Result<int64_t> FindInt64(ConstByteSpan message, T field) {
386 return FindInt64(message, static_cast<uint32_t>(field));
387}
388
408 uint32_t field_number) {
409 return internal::Find<int64_t, &StreamDecoder::ReadInt64>(message_stream,
410 field_number);
411}
412
413template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
414inline Result<int64_t> FindInt64(stream::Reader& message_stream, T field) {
415 return FindInt64(message_stream, static_cast<uint32_t>(field));
416}
417
418using Int64Finder = Finder<int64_t, &Decoder::ReadInt64>;
419using Int64StreamFinder = StreamFinder<int64_t, &StreamDecoder::ReadInt64>;
420
440 uint32_t field_number) {
441 return internal::Find<int64_t, &Decoder::ReadSint64>(message, field_number);
442}
443
444template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
445inline Result<int64_t> FindSint64(ConstByteSpan message, T field) {
446 return FindSint64(message, static_cast<uint32_t>(field));
447}
448
468 uint32_t field_number) {
469 return internal::Find<int64_t, &StreamDecoder::ReadSint64>(message_stream,
470 field_number);
471}
472
473template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
474inline Result<int64_t> FindSint64(stream::Reader& message_stream, T field) {
475 return FindSint64(message_stream, static_cast<uint32_t>(field));
476}
477
478using Sint64Finder = Finder<int64_t, &Decoder::ReadSint64>;
479using Sint64StreamFinder = StreamFinder<int64_t, &StreamDecoder::ReadSint64>;
480
499inline Result<bool> FindBool(ConstByteSpan message, uint32_t field_number) {
500 return internal::Find<bool, &Decoder::ReadBool>(message, field_number);
501}
502
503template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
504inline Result<bool> FindBool(ConstByteSpan message, T field) {
505 return FindBool(message, static_cast<uint32_t>(field));
506}
507
526inline Result<bool> FindBool(stream::Reader& message_stream,
527 uint32_t field_number) {
528 return internal::Find<bool, &StreamDecoder::ReadBool>(message_stream,
529 field_number);
530}
531
532template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
533inline Result<bool> FindBool(stream::Reader& message_stream, T field) {
534 return FindBool(message_stream, static_cast<uint32_t>(field));
535}
536
537using BoolFinder = Finder<bool, &Decoder::ReadBool>;
538using BoolStreamFinder = StreamFinder<bool, &StreamDecoder::ReadBool>;
539
559 uint32_t field_number) {
560 return internal::Find<uint32_t, &Decoder::ReadFixed32>(message, field_number);
561}
562
563template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
564inline Result<uint32_t> FindFixed32(ConstByteSpan message, T field) {
565 return FindFixed32(message, static_cast<uint32_t>(field));
566}
567
587 uint32_t field_number) {
588 return internal::Find<uint32_t, &StreamDecoder::ReadFixed32>(message_stream,
589 field_number);
590}
591
592template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
593inline Result<uint32_t> FindFixed32(stream::Reader& message_stream, T field) {
594 return FindFixed32(message_stream, static_cast<uint32_t>(field));
595}
596
597using Fixed32Finder = Finder<uint32_t, &Decoder::ReadFixed32>;
598using Fixed32StreamFinder = StreamFinder<uint32_t, &StreamDecoder::ReadFixed32>;
599
619 uint32_t field_number) {
620 return internal::Find<uint64_t, &Decoder::ReadFixed64>(message, field_number);
621}
622
623template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
624inline Result<uint64_t> FindFixed64(ConstByteSpan message, T field) {
625 return FindFixed64(message, static_cast<uint32_t>(field));
626}
627
647 uint32_t field_number) {
648 return internal::Find<uint64_t, &StreamDecoder::ReadFixed64>(message_stream,
649 field_number);
650}
651
652template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
653inline Result<uint64_t> FindFixed64(stream::Reader& message_stream, T field) {
654 return FindFixed64(message_stream, static_cast<uint32_t>(field));
655}
656
657using Fixed64Finder = Finder<uint64_t, &Decoder::ReadFixed64>;
658using Fixed64StreamFinder = StreamFinder<uint64_t, &StreamDecoder::ReadFixed64>;
659
679 uint32_t field_number) {
680 return internal::Find<int32_t, &Decoder::ReadSfixed32>(message, field_number);
681}
682
683template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
684inline Result<int32_t> FindSfixed32(ConstByteSpan message, T field) {
685 return FindSfixed32(message, static_cast<uint32_t>(field));
686}
687
707 uint32_t field_number) {
708 return internal::Find<int32_t, &StreamDecoder::ReadSfixed32>(message_stream,
709 field_number);
710}
711
712template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
713inline Result<int32_t> FindSfixed32(stream::Reader& message_stream, T field) {
714 return FindSfixed32(message_stream, static_cast<uint32_t>(field));
715}
716
717using Sfixed32Finder = Finder<int32_t, &Decoder::ReadSfixed32>;
718using Sfixed32StreamFinder =
719 StreamFinder<int32_t, &StreamDecoder::ReadSfixed32>;
720
740 uint32_t field_number) {
741 return internal::Find<int64_t, &Decoder::ReadSfixed64>(message, field_number);
742}
743
744template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
745inline Result<int64_t> FindSfixed64(ConstByteSpan message, T field) {
746 return FindSfixed64(message, static_cast<uint32_t>(field));
747}
748
768 uint32_t field_number) {
769 return internal::Find<int64_t, &StreamDecoder::ReadSfixed64>(message_stream,
770 field_number);
771}
772
773template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
774inline Result<int64_t> FindSfixed64(stream::Reader& message_stream, T field) {
775 return FindSfixed64(message_stream, static_cast<uint32_t>(field));
776}
777
778using Sfixed64Finder = Finder<int64_t, &Decoder::ReadSfixed64>;
779using Sfixed64StreamFinder =
780 StreamFinder<int64_t, &StreamDecoder::ReadSfixed64>;
781
800inline Result<float> FindFloat(ConstByteSpan message, uint32_t field_number) {
801 return internal::Find<float, &Decoder::ReadFloat>(message, field_number);
802}
803
804template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
805inline Result<float> FindFloat(ConstByteSpan message, T field) {
806 return FindFloat(message, static_cast<uint32_t>(field));
807}
808
828 uint32_t field_number) {
829 return internal::Find<float, &StreamDecoder::ReadFloat>(message_stream,
830 field_number);
831}
832
833template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
834inline Result<float> FindFloat(stream::Reader& message_stream, T field) {
835 return FindFloat(message_stream, static_cast<uint32_t>(field));
836}
837
838using FloatFinder = Finder<float, &Decoder::ReadFloat>;
839using FloatStreamFinder = StreamFinder<float, &StreamDecoder::ReadFloat>;
840
859inline Result<double> FindDouble(ConstByteSpan message, uint32_t field_number) {
860 return internal::Find<double, &Decoder::ReadDouble>(message, field_number);
861}
862
863template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
864inline Result<double> FindDouble(ConstByteSpan message, T field) {
865 return FindDouble(message, static_cast<uint32_t>(field));
866}
867
886
888 uint32_t field_number) {
889 return internal::Find<double, &StreamDecoder::ReadDouble>(message_stream,
890 field_number);
891}
892
893template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
894inline Result<double> FindDouble(stream::Reader& message_stream, T field) {
895 return FindDouble(message_stream, static_cast<uint32_t>(field));
896}
897
898using DoubleFinder = Finder<double, &Decoder::ReadDouble>;
899using DoubleStreamFinder = StreamFinder<double, &StreamDecoder::ReadDouble>;
900
921 uint32_t field_number) {
922 return internal::Find<std::string_view, &Decoder::ReadString>(message,
923 field_number);
924}
925
926template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
927inline Result<std::string_view> FindString(ConstByteSpan message, T field) {
928 return FindString(message, static_cast<uint32_t>(field));
929}
930
953 uint32_t field_number,
954 span<char> out) {
955 StreamDecoder decoder(message_stream);
956 Status status = internal::AdvanceToField(decoder, field_number);
957 if (!status.ok()) {
958 return StatusWithSize(status, 0);
959 }
960 StatusWithSize sws = decoder.ReadString(out);
961
962 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
963 // a field. Remap this to FAILED_PRECONDITION for consistency with the
964 // non-stream Find.
965 return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
966}
967
989 uint32_t field_number,
990 InlineString<>& out) {
991 StatusWithSize sws;
992
993 out.resize_and_overwrite([&](char* data, size_t size) {
994 sws = FindString(message_stream, field_number, span(data, size));
995 return sws.size();
996 });
997
998 return sws;
999}
1000
1001template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
1002inline StatusWithSize FindString(stream::Reader& message_stream,
1003 T field,
1004 span<char> out) {
1005 return FindString(message_stream, static_cast<uint32_t>(field), out);
1006}
1007
1008template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
1009inline StatusWithSize FindString(stream::Reader& message_stream,
1010 T field,
1011 InlineString<>& out) {
1012 return FindString(message_stream, static_cast<uint32_t>(field), out);
1013}
1014
1015using StringFinder = Finder<std::string_view, &Decoder::ReadString>;
1016
1036 uint32_t field_number) {
1037 return internal::Find<ConstByteSpan, &Decoder::ReadBytes>(message,
1038 field_number);
1039}
1040
1041template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
1042inline Result<ConstByteSpan> FindBytes(ConstByteSpan message, T field) {
1043 return FindBytes(message, static_cast<uint32_t>(field));
1044}
1045
1066 uint32_t field_number,
1067 ByteSpan out) {
1068 StreamDecoder decoder(message_stream);
1069 Status status = internal::AdvanceToField(decoder, field_number);
1070 if (!status.ok()) {
1071 return StatusWithSize(status, 0);
1072 }
1073 StatusWithSize sws = decoder.ReadBytes(out);
1074
1075 // The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
1076 // a field. Remap this to FAILED_PRECONDITION for consistency with the
1077 // non-stream Find.
1078 return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
1079}
1080
1081template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
1082inline StatusWithSize FindBytes(stream::Reader& message_stream,
1083 T field,
1084 ByteSpan out) {
1085 return FindBytes(message_stream, static_cast<uint32_t>(field), out);
1086}
1087
1088using BytesFinder = Finder<ConstByteSpan, &Decoder::ReadBytes>;
1089
1109 uint32_t field_number) {
1110 // On the wire, a submessage is identical to bytes. This function exists only
1111 // to clarify users' intent.
1112 return FindBytes(message, field_number);
1113}
1114
1115template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
1116inline Result<ConstByteSpan> FindSubmessage(ConstByteSpan message, T field) {
1117 return FindSubmessage(message, static_cast<uint32_t>(field));
1118}
1119
1122 uint32_t field_number) {
1123 Decoder decoder(message);
1124 PW_TRY(internal::AdvanceToField(decoder, field_number));
1125 return decoder.RawFieldBytes();
1126}
1127
1128template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
1130 return FindRaw(message, static_cast<uint32_t>(field));
1131}
1132
1134
1135} // namespace pw::protobuf
pw::InlineBasicString is a fixed-capacity version of std::basic_string. In brief:
Definition: string.h:68
Definition: poll.h:25
Definition: status.h:109
constexpr bool ok() const
Definition: status.h:214
static constexpr Status FailedPrecondition()
System isn’t in the required state; e.g. deleting a non-empty directory.
Definition: status.h:162
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:351
Result< int32_t > FindInt32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an int32 field.
Definition: find.h:201
Result< int64_t > FindInt64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an int64 field.
Definition: find.h:380
Result< int64_t > FindSfixed64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sfixed64 field.
Definition: find.h:739
Result< ConstByteSpan > FindRaw(ConstByteSpan message, uint32_t field_number)
Returns a span containing the raw bytes of the value.
Definition: find.h:1121
Result< ConstByteSpan > FindBytes(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a bytes field.
Definition: find.h:1035
Result< int64_t > FindSint64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sint64 field.
Definition: find.h:439
Result< int32_t > FindSfixed32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sfixed32 field.
Definition: find.h:678
Result< int32_t > FindSint32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for an sint32 field.
Definition: find.h:260
Result< float > FindFloat(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a float field.
Definition: find.h:800
Result< uint64_t > FindFixed64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a fixed64 field.
Definition: find.h:618
Result< uint32_t > FindFixed32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a fixed32 field.
Definition: find.h:558
Result< ConstByteSpan > FindSubmessage(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a submessage.
Definition: find.h:1108
Result< std::string_view > FindString(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a string field.
Definition: find.h:920
Result< uint32_t > FindUint32(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a uint32 field.
Definition: find.h:141
Result< uint64_t > FindUint64(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a uint64 field.
Definition: find.h:320
Result< double > FindDouble(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a double field.
Definition: find.h:859
Result< bool > FindBool(ConstByteSpan message, uint32_t field_number)
Scans a serialized protobuf message for a bool field.
Definition: find.h:499
#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...