WPILibC++ 2025.1.1
Loading...
Searching...
No Matches
ProtobufCallbacks.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <span>
8#include <utility>
9#include <vector>
10
11#include <fmt/format.h>
12
13#include "pb.h"
14#include "wpi/SmallVector.h"
15#include "wpi/array.h"
17
18namespace wpi {
19
20/**
21 * The behavior to use when more elements are in the message then expected when
22 * decoding.
23 */
24enum class DecodeLimits {
25 // Ignore any extra elements
26 Ignore,
27 // Add any extra elements to the backing vector
28 Add,
29 // Cause decoding to fail if extra elements exist
30 Fail,
31};
32
33template <class T>
34concept StringLike = std::is_convertible_v<T, std::string_view>;
35
36template <class T>
37concept ConstVectorLike = std::is_convertible_v<T, std::span<const uint8_t>>;
38
39template <class T>
40concept MutableVectorLike = std::is_convertible_v<T, std::span<uint8_t>>;
41
42template <typename T>
44
45template <typename T>
46concept UnpackBytes = requires(T& t) {
47 { t.resize(size_t()) }; // NOLINT
48 { t.size() } -> std::same_as<size_t>;
49 { t.data() } -> std::convertible_to<void*>;
51
52template <typename T>
53concept ProtoEnumeration = std::is_enum_v<T>;
54
55template <typename T>
57 ProtoEnumeration<T> || std::integral<T> || std::floating_point<T>;
58
59template <typename T>
62
63template <typename T>
66
67namespace detail {
68
69template <typename T>
71
72template <Validatable T>
73constexpr bool ValidateType(pb_type_t type) {
74 switch (type) {
75 case PB_LTYPE_BOOL:
76 return std::integral<T>;
77 case PB_LTYPE_VARINT:
78 return std::signed_integral<T> || ProtoEnumeration<T>;
80 return std::unsigned_integral<T>;
82 return std::signed_integral<T>;
84 return std::integral<T> || std::floating_point<T>;
86 return std::integral<T> || std::floating_point<T>;
87 case PB_LTYPE_BYTES:
88 case PB_LTYPE_STRING:
92 default:
93 return false;
94 }
95}
96
97} // namespace detail
98
99/**
100 * A callback method that will directly unpack elements into
101 * the specified vector like data structure. The size passed
102 * is the expected number of elements.
103 *
104 * By default, any elements in the packed buffer past N will
105 * still be added to the vector.
106 *
107 * @tparam T object type
108 * @tparam U vector type to pack into
109 * @tparam N number of elements
110 */
111template <ProtoCallbackUnpackable T, typename U, size_t N = 1>
113 public:
114 /**
115 * Constructs a callback from a vector like type.
116 *
117 * @param storage the vector to store into
118 */
119 explicit DirectUnpackCallback(U& storage) : m_storage{storage} {
120 m_callback.funcs.decode = CallbackFunc;
121 m_callback.arg = this;
122 }
127
128 /**
129 * Set the limits on what happens if more elements exist in the buffer then
130 * expected.
131 *
132 * @param limit the limit to set
133 */
134 void SetLimits(DecodeLimits limit) noexcept { m_limits = limit; }
135
136 /**
137 * Gets the nanopb callback pointing to this object.
138 *
139 * @return nanopb callback
140 */
141 pb_callback_t Callback() const { return m_callback; }
142
143 private:
144 bool SizeCheck(bool* retVal) const {
145 if (m_storage.size() >= N) {
146 switch (m_limits) {
148 *retVal = true;
149 return false;
150
152 break;
153
154 default:
155 *retVal = false;
156 return false;
157 }
158 }
159 return true;
160 }
161
162 bool Decode(pb_istream_t* stream, pb_type_t fieldType) {
163 if constexpr (ProtoPackable<T>) {
164 switch (fieldType) {
165 case PB_LTYPE_BOOL:
166 if constexpr (std::integral<T>) {
167 bool val = false;
168 if (!pb_decode_bool(stream, &val)) {
169 return false;
170 }
171 m_storage.emplace_back(static_cast<T>(val));
172 return true;
173 } else {
174 return false;
175 }
176 case PB_LTYPE_VARINT:
177 if constexpr (std::signed_integral<T> || ProtoEnumeration<T>) {
178 int64_t val = 0;
179 if (!pb_decode_varint(stream, reinterpret_cast<uint64_t*>(&val))) {
180 return false;
181 }
182 m_storage.emplace_back(static_cast<T>(val));
183 return true;
184 } else {
185 return false;
186 }
187 case PB_LTYPE_UVARINT:
188 if constexpr (std::unsigned_integral<T>) {
189 uint64_t val = 0;
190 if (!pb_decode_varint(stream, &val)) {
191 return false;
192 }
193 m_storage.emplace_back(static_cast<T>(val));
194 return true;
195 } else {
196 return false;
197 }
198 case PB_LTYPE_SVARINT:
199 if constexpr (std::signed_integral<T>) {
200 int64_t val = 0;
201 if (!pb_decode_svarint(stream, &val)) {
202 return false;
203 }
204 m_storage.emplace_back(static_cast<T>(val));
205 return true;
206 } else {
207 return false;
208 }
209 case PB_LTYPE_FIXED32:
210 if constexpr (std::signed_integral<T>) {
211 int32_t val = 0;
212 if (!pb_decode_fixed32(stream, &val)) {
213 return false;
214 }
215 m_storage.emplace_back(static_cast<T>(val));
216 return true;
217 } else if constexpr (std::unsigned_integral<T>) {
218 uint32_t val = 0;
219 if (!pb_decode_fixed32(stream, &val)) {
220 return false;
221 }
222 m_storage.emplace_back(static_cast<T>(val));
223 return true;
224 }
225 if constexpr (std::floating_point<T>) {
226 float val = 0;
227 if (!pb_decode_fixed32(stream, &val)) {
228 return false;
229 }
230 m_storage.emplace_back(static_cast<T>(val));
231 return true;
232 } else {
233 return false;
234 }
235 case PB_LTYPE_FIXED64:
236 if constexpr (std::signed_integral<T>) {
237 int64_t val = 0;
238 if (!pb_decode_fixed64(stream, &val)) {
239 return false;
240 }
241 m_storage.emplace_back(static_cast<T>(val));
242 return true;
243 } else if constexpr (std::unsigned_integral<T>) {
244 uint64_t val = 0;
245 if (!pb_decode_fixed64(stream, &val)) {
246 return false;
247 }
248 m_storage.emplace_back(static_cast<T>(val));
249 return true;
250 }
251 if constexpr (std::floating_point<T>) {
252 double val = 0;
253 if (!pb_decode_fixed64(stream, &val)) {
254 return false;
255 }
256 m_storage.emplace_back(static_cast<T>(val));
257 return true;
258 } else {
259 return false;
260 }
261 default:
262 return false;
263 }
264 } else if constexpr (UnpackBytes<T>) {
265 T& space = m_storage.emplace_back(T{});
266 space.resize(stream->bytes_left);
267 return pb_read(stream, reinterpret_cast<pb_byte_t*>(space.data()),
268 space.size());
269 } else if constexpr (ProtobufSerializable<T>) {
270 ProtoInputStream<T> istream{stream};
271 auto decoded = wpi::Protobuf<T>::Unpack(istream);
272 if (decoded.has_value()) {
273 m_storage.emplace_back(std::move(decoded.value()));
274 return true;
275 }
276 return false;
277 }
278 }
279
280 bool CallbackFunc(pb_istream_t* stream, const pb_field_t* field) {
281 pb_type_t fieldType = PB_LTYPE(field->type);
282
283 if (!detail::ValidateType<T>(fieldType)) {
284 return false;
285 }
286
287 // Validate our types
288 if constexpr (ProtoPackable<T>) {
289 // Handle decode loop
290 while (stream->bytes_left > 0) {
291 bool sizeRetVal = 0;
292 if (!SizeCheck(&sizeRetVal)) {
293 return sizeRetVal;
294 }
295
296 if (!Decode(stream, fieldType)) {
297 return false;
298 }
299 }
300 return true;
301 } else {
302 // At this point, do the size check
303 bool sizeRetVal = 0;
304 if (!SizeCheck(&sizeRetVal)) {
305 return sizeRetVal;
306 }
307
308 // At this point, we're good to decode
309 return Decode(stream, fieldType);
310 }
311 }
312
313 static bool CallbackFunc(pb_istream_t* stream, const pb_field_t* field,
314 void** arg) {
315 return reinterpret_cast<DirectUnpackCallback*>(*arg)->CallbackFunc(stream,
316 field);
317 }
318
319 U& m_storage;
320 pb_callback_t m_callback;
322};
323
324/**
325 * A DirectUnpackCallback backed by a SmallVector<T, N>.
326 *
327 * By default, any elements in the packed buffer past N will
328 * be ignored, but decoding will still succeed
329 *
330 * @tparam T object type
331 * @tparam N small vector small size/number of expected elements
332 */
333template <ProtoCallbackUnpackable T, size_t N = 1>
335 : public DirectUnpackCallback<T, wpi::SmallVector<T, N>, N> {
336 public:
337 /**
338 * Constructs an UnpackCallback.
339 */
341 : DirectUnpackCallback<T, wpi::SmallVector<T, N>, N>{m_storedBuffer} {
343 }
344
345 /**
346 * Gets a span pointing to the storage buffer.
347 *
348 * @return storage buffer span
349 */
350 std::span<T> Items() noexcept { return m_storedBuffer; }
351
352 /**
353 * Gets a const span pointing to the storage buffer.
354 *
355 * @return storage buffer span
356 */
357 std::span<const T> Items() const noexcept { return m_storedBuffer; }
358
359 /**
360 * Gets a reference to the backing small vector.
361 *
362 * @return small vector reference
363 */
364 wpi::SmallVector<T, N>& Vec() noexcept { return m_storedBuffer; }
365
366 private:
367 wpi::SmallVector<T, N> m_storedBuffer;
368};
369
370/**
371 * A DirectUnpackCallback backed by a std::vector.
372 *
373 * By default, any elements in the packed buffer past N will
374 * be ignored, but decoding will still succeed
375 *
376 * @tparam T object type
377 * @tparam N number of expected elements
378 */
379template <ProtoCallbackUnpackable T, size_t N = 1>
381 : public DirectUnpackCallback<T, std::vector<T>, N> {
382 public:
383 /**
384 * Constructs a StdVectorUnpackCallback.
385 */
387 : DirectUnpackCallback<T, std::vector<T>, N>{m_storedBuffer} {
389 }
390
391 /**
392 * Gets a span pointing to the storage buffer.
393 *
394 * @return storage buffer span
395 */
396 std::span<T> Items() noexcept { return m_storedBuffer; }
397
398 /**
399 * Gets a const span pointing to the storage buffer.
400 *
401 * @return storage buffer span
402 */
403 std::span<const T> Items() const noexcept { return m_storedBuffer; }
404
405 /**
406 * Gets a reference to the backing vector.
407 *
408 * @return vector reference
409 */
410 std::vector<T>& Vec() noexcept { return m_storedBuffer; }
411
412 private:
413 std::vector<T> m_storedBuffer;
414};
415
416/**
417 * A wrapper around a wpi::array that lets us
418 * treat it as a limited sized vector.
419 */
420template <ProtoCallbackUnpackable T, size_t N>
423 size_t m_currentIndex = 0;
424
425 size_t size() const { return m_currentIndex; }
426
427 template <typename... ArgTypes>
428 T& emplace_back(ArgTypes&&... Args) {
429 m_array[m_currentIndex] = T(std::forward<ArgTypes>(Args)...);
431 return m_array[m_currentIndex - 1];
432 }
433};
434
435/**
436 * A DirectUnpackCallback backed by a wpi::array<T, N>.
437 *
438 * Any elements in the packed buffer past N will
439 * be cause decoding to fail.
440 *
441 * @tparam T object type
442 * @tparam N small vector small size/number of expected elements
443 */
444template <ProtoCallbackUnpackable T, size_t N>
446 : public DirectUnpackCallback<T, WpiArrayEmplaceWrapper<T, N>, N> {
447 /**
448 * Constructs a WpiArrayUnpackCallback.
449 */
454
455 /**
456 * Returns if the buffer is completely filled up.
457 *
458 * @return true if buffer is full
459 */
460 bool IsFull() const noexcept { return m_array.m_currentIndex == N; }
461
462 /**
463 * Returns the number of elements in the buffer.
464 *
465 * @return number of elements
466 */
467 size_t Size() const noexcept { return m_array.m_currentIndex; }
468
469 /**
470 * Returns a reference to the backing array.
471 *
472 * @return array reference
473 */
474 wpi::array<T, N>& Array() noexcept { return m_array.m_array; }
475
476 private:
478};
479
480/**
481 * A callback method that will pack elements when called.
482 *
483 * @tparam T object type
484 */
485template <ProtoCallbackPackable T>
487 public:
488 /**
489 * Constructs a pack callback from a span of elements. The elements in the
490 * buffer _MUST_ stay alive throughout the entire encode call.
491 */
492 explicit PackCallback(std::span<const T> buffer) : m_buffer{buffer} {
493 m_callback.funcs.encode = CallbackFunc;
494 m_callback.arg = this;
495 }
496
497 /**
498 * Constructs a pack callback from a pointer to a single element.
499 * This element _MUST_ stay alive throughout the entire encode call.
500 * Do not pass a temporary here (This is why its a pointer and not a
501 * reference)
502 */
503 explicit PackCallback(const T* element)
504 : m_buffer{std::span<const T>{element, 1}} {
505 m_callback.funcs.encode = CallbackFunc;
506 m_callback.arg = this;
507 }
508 PackCallback(const PackCallback&) = delete;
512
513 /**
514 * Gets the nanopb callback pointing to this object.
515 *
516 * @return nanopb callback
517 */
518 pb_callback_t Callback() const { return m_callback; }
519
520 /**
521 * Gets a span pointing to the items
522 *
523 * @return span
524 */
525 std::span<const T> Bufs() const { return m_buffer; }
526
527 private:
528 static auto EncodeStreamTypeFinder() {
529 if constexpr (ProtobufSerializable<T>) {
530 return ProtoOutputStream<T>(nullptr);
531 } else {
532 return pb_ostream_t{};
533 }
534 }
535 using EncodeStreamType = decltype(EncodeStreamTypeFinder());
536
537 bool EncodeItem(EncodeStreamType& stream, const pb_field_t* field,
538 const T& value) const {
539 if constexpr (std::floating_point<T>) {
540 pb_type_t fieldType = PB_LTYPE(field->type);
541 switch (fieldType) {
542 case PB_LTYPE_FIXED32: {
543 float flt = static_cast<float>(value);
544 return pb_encode_fixed32(&stream, &flt);
545 }
546 case PB_LTYPE_FIXED64: {
547 double dbl = static_cast<double>(value);
548 return pb_encode_fixed64(&stream, &dbl);
549 }
550 default:
551 return false;
552 }
553 } else if constexpr (std::integral<T> || ProtoEnumeration<T>) {
554 pb_type_t fieldType = PB_LTYPE(field->type);
555 switch (fieldType) {
556 case PB_LTYPE_BOOL:
557 case PB_LTYPE_VARINT:
558 case PB_LTYPE_UVARINT:
559 return pb_encode_varint(&stream, value);
560 case PB_LTYPE_SVARINT:
561 return pb_encode_svarint(&stream, value);
562 case PB_LTYPE_FIXED32: {
563 uint32_t f = value;
564 return pb_encode_fixed32(&stream, &f);
565 }
566 case PB_LTYPE_FIXED64: {
567 uint64_t f = value;
568 return pb_encode_fixed64(&stream, &f);
569 }
570 default:
571 return false;
572 }
573 } else if constexpr (StringLike<T>) {
574 std::string_view view{value};
575 return pb_encode_string(&stream,
576 reinterpret_cast<const pb_byte_t*>(view.data()),
577 view.size());
578 } else if constexpr (ConstVectorLike<T>) {
579 std::span<const uint8_t> view{value};
580 return pb_encode_string(&stream,
581 reinterpret_cast<const pb_byte_t*>(view.data()),
582 view.size());
583 } else if constexpr (ProtobufSerializable<T>) {
584 return wpi::Protobuf<T>::Pack(stream, value);
585 }
586 }
587
588 bool EncodeLoop(pb_ostream_t* stream, const pb_field_t* field,
589 bool writeTag) const {
590 if constexpr (ProtobufSerializable<T>) {
591 ProtoOutputStream<T> ostream{stream};
592 for (auto&& i : m_buffer) {
593 if (writeTag) {
594 if (!pb_encode_tag_for_field(stream, field)) {
595 return false;
596 }
597 }
598 if (!EncodeItem(ostream, field, i)) {
599 return false;
600 }
601 }
602 } else {
603 for (auto&& i : m_buffer) {
604 if (writeTag) {
605 if (!pb_encode_tag_for_field(stream, field)) {
606 return false;
607 }
608 }
609 if (!EncodeItem(*stream, field, i)) {
610 return false;
611 }
612 }
613 }
614
615 return true;
616 }
617
618 bool PackedEncode(pb_ostream_t* stream, const pb_field_t* field) const {
619 // We're always going to used packed encoding.
620 // So first we need to get the packed size.
621
623 if (!EncodeLoop(&substream, field, false)) {
624 return false;
625 }
626
627 // Encode as a string tag
628 if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) {
629 return false;
630 }
631
632 // Write length as varint
633 size_t size = substream.bytes_written;
634 if (!pb_encode_varint(stream, static_cast<uint64_t>(size))) {
635 return false;
636 }
637
638 return EncodeLoop(stream, field, false);
639 }
640
641 bool CallbackFunc(pb_ostream_t* stream, const pb_field_t* field) const {
642 // First off, if we're empty, do nothing, but say we were successful
643 if (m_buffer.empty()) {
644 return true;
645 }
646
647 pb_type_t fieldType = PB_LTYPE(field->type);
648
649 if (!detail::ValidateType<T>(fieldType)) {
650 return false;
651 }
652
653 if constexpr (ProtoPackable<T>) {
654 return PackedEncode(stream, field);
655 } else {
656 return EncodeLoop(stream, field, true);
657 }
658 }
659
660 static bool CallbackFunc(pb_ostream_t* stream, const pb_field_t* field,
661 void* const* arg) {
662 return reinterpret_cast<const PackCallback*>(*arg)->CallbackFunc(stream,
663 field);
664 }
665
666 std::span<const T> m_buffer;
667 pb_callback_t m_callback;
668};
669
670} // namespace wpi
This file defines the SmallVector class.
A callback method that will directly unpack elements into the specified vector like data structure.
Definition ProtobufCallbacks.h:112
pb_callback_t Callback() const
Gets the nanopb callback pointing to this object.
Definition ProtobufCallbacks.h:141
DirectUnpackCallback(DirectUnpackCallback &&)=delete
DirectUnpackCallback & operator=(const DirectUnpackCallback &)=delete
DirectUnpackCallback(U &storage)
Constructs a callback from a vector like type.
Definition ProtobufCallbacks.h:119
DirectUnpackCallback & operator=(DirectUnpackCallback &&)=delete
DirectUnpackCallback(const DirectUnpackCallback &)=delete
void SetLimits(DecodeLimits limit) noexcept
Set the limits on what happens if more elements exist in the buffer then expected.
Definition ProtobufCallbacks.h:134
A callback method that will pack elements when called.
Definition ProtobufCallbacks.h:486
PackCallback(const T *element)
Constructs a pack callback from a pointer to a single element.
Definition ProtobufCallbacks.h:503
PackCallback(std::span< const T > buffer)
Constructs a pack callback from a span of elements.
Definition ProtobufCallbacks.h:492
PackCallback(const PackCallback &)=delete
PackCallback & operator=(PackCallback &&)=delete
PackCallback(PackCallback &&)=delete
std::span< const T > Bufs() const
Gets a span pointing to the items.
Definition ProtobufCallbacks.h:525
PackCallback & operator=(const PackCallback &)=delete
pb_callback_t Callback() const
Gets the nanopb callback pointing to this object.
Definition ProtobufCallbacks.h:518
Class for wrapping a nanopb ostream.
Definition Protobuf.h:119
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition SmallVector.h:1212
A DirectUnpackCallback backed by a std::vector.
Definition ProtobufCallbacks.h:381
std::span< const T > Items() const noexcept
Gets a const span pointing to the storage buffer.
Definition ProtobufCallbacks.h:403
std::vector< T > & Vec() noexcept
Gets a reference to the backing vector.
Definition ProtobufCallbacks.h:410
std::span< T > Items() noexcept
Gets a span pointing to the storage buffer.
Definition ProtobufCallbacks.h:396
StdVectorUnpackCallback()
Constructs a StdVectorUnpackCallback.
Definition ProtobufCallbacks.h:386
A DirectUnpackCallback backed by a SmallVector<T, N>.
Definition ProtobufCallbacks.h:335
wpi::SmallVector< T, N > & Vec() noexcept
Gets a reference to the backing small vector.
Definition ProtobufCallbacks.h:364
std::span< const T > Items() const noexcept
Gets a const span pointing to the storage buffer.
Definition ProtobufCallbacks.h:357
UnpackCallback()
Constructs an UnpackCallback.
Definition ProtobufCallbacks.h:340
std::span< T > Items() noexcept
Gets a span pointing to the storage buffer.
Definition ProtobufCallbacks.h:350
This class is a wrapper around std::array that does compile time size checking.
Definition array.h:26
Definition ProtobufCallbacks.h:37
Definition ProtobufCallbacks.h:40
Definition ProtobufCallbacks.h:43
Definition ProtobufCallbacks.h:60
Definition ProtobufCallbacks.h:64
Definition ProtobufCallbacks.h:53
Definition ProtobufCallbacks.h:56
Specifies that a type is capable of protobuf serialization and deserialization.
Definition Protobuf.h:251
Definition ProtobufCallbacks.h:34
Definition ProtobufCallbacks.h:46
Definition ProtobufCallbacks.h:70
detail namespace with internal helper functions
Definition input_adapters.h:32
@ value
the parser finished reading a JSON value
Implement std::hash so that hash_code can be used in STL containers.
Definition PointerIntPair.h:280
constexpr bool ValidateType(pb_type_t type)
Definition ProtobufCallbacks.h:73
Foonathan namespace.
Definition ntcore_cpp.h:26
DecodeLimits
The behavior to use when more elements are in the message then expected when decoding.
Definition ProtobufCallbacks.h:24
uint_least8_t pb_byte_t
Definition pb.h:228
#define PB_LTYPE_STRING
Definition pb.h:256
#define PB_LTYPE_BOOL
Definition pb.h:240
#define PB_LTYPE_FIXED64
Definition pb.h:245
#define PB_LTYPE_SVARINT
Definition pb.h:243
#define PB_LTYPE_UVARINT
Definition pb.h:242
#define PB_LTYPE(x)
Definition pb.h:300
#define PB_LTYPE_VARINT
Definition pb.h:241
#define PB_LTYPE_BYTES
Definition pb.h:252
@ PB_WT_STRING
Definition pb.h:433
#define PB_LTYPE_FIXED32
Definition pb.h:244
#define PB_LTYPE_SUBMESSAGE
Definition pb.h:260
pb_byte_t pb_type_t
Definition pb.h:235
bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
bool pb_decode_fixed32(pb_istream_t *stream, void *dest)
bool pb_decode_bool(pb_istream_t *stream, bool *dest)
bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest)
bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field)
#define PB_OSTREAM_SIZING
Definition pb_encode.h:124
bool pb_encode_varint(pb_ostream_t *stream, uint64_t value)
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value)
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
bool pb_encode_fixed32(pb_ostream_t *stream, const void *value)
bool pb_encode_svarint(pb_ostream_t *stream, int64_t value)
bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size)
Definition pb.h:414
bool(* decode)(pb_istream_t *stream, const pb_field_t *field, void **arg)
Definition pb.h:419
void * arg
Definition pb.h:424
union pb_callback_s::@20 funcs
bool(* encode)(pb_ostream_t *stream, const pb_field_t *field, void *const *arg)
Definition pb.h:420
Definition pb.h:347
pb_type_t type
Definition pb.h:359
pb_size_t tag
Definition pb.h:356
Definition pb_decode.h:27
size_t bytes_left
Definition pb_decode.h:49
Definition pb_encode.h:26
size_t bytes_written
Definition pb_encode.h:49
Protobuf serialization template.
Definition Protobuf.h:36
A wrapper around a wpi::array that lets us treat it as a limited sized vector.
Definition ProtobufCallbacks.h:421
T & emplace_back(ArgTypes &&... Args)
Definition ProtobufCallbacks.h:428
wpi::array< T, N > m_array
Definition ProtobufCallbacks.h:422
size_t m_currentIndex
Definition ProtobufCallbacks.h:423
size_t size() const
Definition ProtobufCallbacks.h:425
A DirectUnpackCallback backed by a wpi::array<T, N>.
Definition ProtobufCallbacks.h:446
bool IsFull() const noexcept
Returns if the buffer is completely filled up.
Definition ProtobufCallbacks.h:460
WpiArrayUnpackCallback()
Constructs a WpiArrayUnpackCallback.
Definition ProtobufCallbacks.h:450
size_t Size() const noexcept
Returns the number of elements in the buffer.
Definition ProtobufCallbacks.h:467
wpi::array< T, N > & Array() noexcept
Returns a reference to the backing array.
Definition ProtobufCallbacks.h:474
Definition array.h:15
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Returns a named argument to be used in a formatting function.
Definition base.h:2775