WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
ProtobufCallbacks.hpp
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/util/SmallVector.hpp"
15#include "wpi/util/array.hpp"
17
18namespace wpi::util {
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
27 // Add any extra elements to the backing vector
29 // Cause decoding to fail if extra elements exist
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::util::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::util::SmallVector<T, N>, N> {
336 public:
337 /**
338 * Constructs an UnpackCallback.
339 */
341 : DirectUnpackCallback<T, wpi::util::SmallVector<T, N>, N>{
342 m_storedBuffer} {
344 }
345
346 /**
347 * Gets a span pointing to the storage buffer.
348 *
349 * @return storage buffer span
350 */
351 std::span<T> Items() noexcept { return m_storedBuffer; }
352
353 /**
354 * Gets a const span pointing to the storage buffer.
355 *
356 * @return storage buffer span
357 */
358 std::span<const T> Items() const noexcept { return m_storedBuffer; }
359
360 /**
361 * Gets a reference to the backing small vector.
362 *
363 * @return small vector reference
364 */
365 wpi::util::SmallVector<T, N>& Vec() noexcept { return m_storedBuffer; }
366
367 private:
368 wpi::util::SmallVector<T, N> m_storedBuffer;
369};
370
371/**
372 * A DirectUnpackCallback backed by a std::vector.
373 *
374 * By default, any elements in the packed buffer past N will
375 * be ignored, but decoding will still succeed
376 *
377 * @tparam T object type
378 * @tparam N number of expected elements
379 */
380template <ProtoCallbackUnpackable T, size_t N = 1>
382 : public DirectUnpackCallback<T, std::vector<T>, N> {
383 public:
384 /**
385 * Constructs a StdVectorUnpackCallback.
386 */
388 : DirectUnpackCallback<T, std::vector<T>, N>{m_storedBuffer} {
390 }
391
392 /**
393 * Gets a span pointing to the storage buffer.
394 *
395 * @return storage buffer span
396 */
397 std::span<T> Items() noexcept { return m_storedBuffer; }
398
399 /**
400 * Gets a const span pointing to the storage buffer.
401 *
402 * @return storage buffer span
403 */
404 std::span<const T> Items() const noexcept { return m_storedBuffer; }
405
406 /**
407 * Gets a reference to the backing vector.
408 *
409 * @return vector reference
410 */
411 std::vector<T>& Vec() noexcept { return m_storedBuffer; }
412
413 private:
414 std::vector<T> m_storedBuffer;
415};
416
417/**
418 * A wrapper around a wpi::util::array that lets us
419 * treat it as a limited sized vector.
420 */
421template <ProtoCallbackUnpackable T, size_t N>
424 size_t m_currentIndex = 0;
425
426 size_t size() const { return m_currentIndex; }
427
428 template <typename... ArgTypes>
429 T& emplace_back(ArgTypes&&... Args) {
430 m_array[m_currentIndex] = T(std::forward<ArgTypes>(Args)...);
432 return m_array[m_currentIndex - 1];
433 }
434};
435
436/**
437 * A DirectUnpackCallback backed by a wpi::util::array<T, N>.
438 *
439 * Any elements in the packed buffer past N will
440 * be cause decoding to fail.
441 *
442 * @tparam T object type
443 * @tparam N small vector small size/number of expected elements
444 */
445template <ProtoCallbackUnpackable T, size_t N>
447 : public DirectUnpackCallback<T, WpiArrayEmplaceWrapper<T, N>, N> {
448 /**
449 * Constructs a WpiArrayUnpackCallback.
450 */
455
456 /**
457 * Returns if the buffer is completely filled up.
458 *
459 * @return true if buffer is full
460 */
461 bool IsFull() const noexcept { return m_array.m_currentIndex == N; }
462
463 /**
464 * Returns the number of elements in the buffer.
465 *
466 * @return number of elements
467 */
468 size_t Size() const noexcept { return m_array.m_currentIndex; }
469
470 /**
471 * Returns a reference to the backing array.
472 *
473 * @return array reference
474 */
475 wpi::util::array<T, N>& Array() noexcept { return m_array.m_array; }
476
477 private:
479};
480
481/**
482 * A callback method that will pack elements when called.
483 *
484 * @tparam T object type
485 */
486template <ProtoCallbackPackable T>
488 public:
489 /**
490 * Constructs a pack callback from a span of elements. The elements in the
491 * buffer _MUST_ stay alive throughout the entire encode call.
492 */
493 explicit PackCallback(std::span<const T> buffer) : m_buffer{buffer} {
494 m_callback.funcs.encode = CallbackFunc;
495 m_callback.arg = this;
496 }
497
498 /**
499 * Constructs a pack callback from a pointer to a single element.
500 * This element _MUST_ stay alive throughout the entire encode call.
501 * Do not pass a temporary here (This is why its a pointer and not a
502 * reference)
503 */
504 explicit PackCallback(const T* element)
505 : m_buffer{std::span<const T>{element, 1}} {
506 m_callback.funcs.encode = CallbackFunc;
507 m_callback.arg = this;
508 }
509 PackCallback(const PackCallback&) = delete;
513
514 /**
515 * Gets the nanopb callback pointing to this object.
516 *
517 * @return nanopb callback
518 */
519 pb_callback_t Callback() const { return m_callback; }
520
521 /**
522 * Gets a span pointing to the items
523 *
524 * @return span
525 */
526 std::span<const T> Bufs() const { return m_buffer; }
527
528 private:
529 static auto EncodeStreamTypeFinder() {
530 if constexpr (ProtobufSerializable<T>) {
531 return ProtoOutputStream<T>(nullptr);
532 } else {
533 return pb_ostream_t{};
534 }
535 }
536 using EncodeStreamType = decltype(EncodeStreamTypeFinder());
537
538 bool EncodeItem(EncodeStreamType& stream, const pb_field_t* field,
539 const T& value) const {
540 if constexpr (std::floating_point<T>) {
541 pb_type_t fieldType = PB_LTYPE(field->type);
542 switch (fieldType) {
543 case PB_LTYPE_FIXED32: {
544 float flt = static_cast<float>(value);
545 return pb_encode_fixed32(&stream, &flt);
546 }
547 case PB_LTYPE_FIXED64: {
548 double dbl = static_cast<double>(value);
549 return pb_encode_fixed64(&stream, &dbl);
550 }
551 default:
552 return false;
553 }
554 } else if constexpr (std::integral<T> || ProtoEnumeration<T>) {
555 pb_type_t fieldType = PB_LTYPE(field->type);
556 switch (fieldType) {
557 case PB_LTYPE_BOOL:
558 case PB_LTYPE_VARINT:
559 case PB_LTYPE_UVARINT:
560 return pb_encode_varint(&stream, value);
561 case PB_LTYPE_SVARINT:
562 return pb_encode_svarint(&stream, value);
563 case PB_LTYPE_FIXED32: {
564 uint32_t f = value;
565 return pb_encode_fixed32(&stream, &f);
566 }
567 case PB_LTYPE_FIXED64: {
568 uint64_t f = value;
569 return pb_encode_fixed64(&stream, &f);
570 }
571 default:
572 return false;
573 }
574 } else if constexpr (StringLike<T>) {
575 std::string_view view{value};
576 return pb_encode_string(&stream,
577 reinterpret_cast<const pb_byte_t*>(view.data()),
578 view.size());
579 } else if constexpr (ConstVectorLike<T>) {
580 std::span<const uint8_t> view{value};
581 return pb_encode_string(&stream,
582 reinterpret_cast<const pb_byte_t*>(view.data()),
583 view.size());
584 } else if constexpr (ProtobufSerializable<T>) {
585 return wpi::util::Protobuf<T>::Pack(stream, value);
586 }
587 }
588
589 bool EncodeLoop(pb_ostream_t* stream, const pb_field_t* field,
590 bool writeTag) const {
591 if constexpr (ProtobufSerializable<T>) {
592 ProtoOutputStream<T> ostream{stream};
593 for (auto&& i : m_buffer) {
594 if (writeTag) {
595 if (!pb_encode_tag_for_field(stream, field)) {
596 return false;
597 }
598 }
599 if (!EncodeItem(ostream, field, i)) {
600 return false;
601 }
602 }
603 } else {
604 for (auto&& i : m_buffer) {
605 if (writeTag) {
606 if (!pb_encode_tag_for_field(stream, field)) {
607 return false;
608 }
609 }
610 if (!EncodeItem(*stream, field, i)) {
611 return false;
612 }
613 }
614 }
615
616 return true;
617 }
618
619 bool PackedEncode(pb_ostream_t* stream, const pb_field_t* field) const {
620 // We're always going to used packed encoding.
621 // So first we need to get the packed size.
622
624 if (!EncodeLoop(&substream, field, false)) {
625 return false;
626 }
627
628 // Encode as a string tag
629 if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) {
630 return false;
631 }
632
633 // Write length as varint
634 size_t size = substream.bytes_written;
635 if (!pb_encode_varint(stream, static_cast<uint64_t>(size))) {
636 return false;
637 }
638
639 return EncodeLoop(stream, field, false);
640 }
641
642 bool CallbackFunc(pb_ostream_t* stream, const pb_field_t* field) const {
643 // First off, if we're empty, do nothing, but say we were successful
644 if (m_buffer.empty()) {
645 return true;
646 }
647
648 pb_type_t fieldType = PB_LTYPE(field->type);
649
650 if (!detail::ValidateType<T>(fieldType)) {
651 return false;
652 }
653
654 if constexpr (ProtoPackable<T>) {
655 return PackedEncode(stream, field);
656 } else {
657 return EncodeLoop(stream, field, true);
658 }
659 }
660
661 static bool CallbackFunc(pb_ostream_t* stream, const pb_field_t* field,
662 void* const* arg) {
663 return reinterpret_cast<const PackCallback*>(*arg)->CallbackFunc(stream,
664 field);
665 }
666
667 std::span<const T> m_buffer;
668 pb_callback_t m_callback;
669};
670
671} // namespace wpi::util
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:2846
@ space
Definition base.h:689
void SetLimits(DecodeLimits limit) noexcept
Set the limits on what happens if more elements exist in the buffer then expected.
Definition ProtobufCallbacks.hpp:134
DirectUnpackCallback(U &storage)
Constructs a callback from a vector like type.
Definition ProtobufCallbacks.hpp:119
DirectUnpackCallback(DirectUnpackCallback &&)=delete
DirectUnpackCallback(const DirectUnpackCallback &)=delete
DirectUnpackCallback & operator=(DirectUnpackCallback &&)=delete
DirectUnpackCallback & operator=(const DirectUnpackCallback &)=delete
pb_callback_t Callback() const
Gets the nanopb callback pointing to this object.
Definition ProtobufCallbacks.hpp:141
A callback method that will pack elements when called.
Definition ProtobufCallbacks.hpp:487
PackCallback(const PackCallback &)=delete
pb_callback_t Callback() const
Gets the nanopb callback pointing to this object.
Definition ProtobufCallbacks.hpp:519
PackCallback & operator=(const PackCallback &)=delete
PackCallback(const T *element)
Constructs a pack callback from a pointer to a single element.
Definition ProtobufCallbacks.hpp:504
PackCallback(PackCallback &&)=delete
std::span< const T > Bufs() const
Gets a span pointing to the items.
Definition ProtobufCallbacks.hpp:526
PackCallback & operator=(PackCallback &&)=delete
PackCallback(std::span< const T > buffer)
Constructs a pack callback from a span of elements.
Definition ProtobufCallbacks.hpp:493
Class for wrapping a nanopb ostream.
Definition Protobuf.hpp:119
std::vector< T > & Vec() noexcept
Gets a reference to the backing vector.
Definition ProtobufCallbacks.hpp:411
std::span< T > Items() noexcept
Gets a span pointing to the storage buffer.
Definition ProtobufCallbacks.hpp:397
std::span< const T > Items() const noexcept
Gets a const span pointing to the storage buffer.
Definition ProtobufCallbacks.hpp:404
StdVectorUnpackCallback()
Constructs a StdVectorUnpackCallback.
Definition ProtobufCallbacks.hpp:387
UnpackCallback()
Constructs an UnpackCallback.
Definition ProtobufCallbacks.hpp:340
wpi::util::SmallVector< T, N > & Vec() noexcept
Gets a reference to the backing small vector.
Definition ProtobufCallbacks.hpp:365
std::span< T > Items() noexcept
Gets a span pointing to the storage buffer.
Definition ProtobufCallbacks.hpp:351
std::span< const T > Items() const noexcept
Gets a const span pointing to the storage buffer.
Definition ProtobufCallbacks.hpp:358
This class is a wrapper around std::array that does compile time size checking.
Definition array.hpp:26
Definition ProtobufCallbacks.hpp:37
Definition ProtobufCallbacks.hpp:40
Definition ProtobufCallbacks.hpp:43
Definition ProtobufCallbacks.hpp:60
Definition ProtobufCallbacks.hpp:64
Definition ProtobufCallbacks.hpp:53
Definition ProtobufCallbacks.hpp:56
Specifies that a type is capable of protobuf serialization and deserialization.
Definition Protobuf.hpp:251
Definition ProtobufCallbacks.hpp:34
Definition ProtobufCallbacks.hpp:46
Definition ProtobufCallbacks.hpp:70
Converts a string literal into a format string that will be parsed at compile time and converted into...
Definition printf.h:50
Definition StringMap.hpp:773
constexpr bool ValidateType(pb_type_t type)
Definition ProtobufCallbacks.hpp:73
Definition raw_os_ostream.hpp:19
DecodeLimits
The behavior to use when more elements are in the message then expected when decoding.
Definition ProtobufCallbacks.hpp:24
@ Fail
Definition ProtobufCallbacks.hpp:30
@ Add
Definition ProtobufCallbacks.hpp:28
@ Ignore
Definition ProtobufCallbacks.hpp:26
Definition CvSource.hpp:15
struct pb_ostream_s pb_ostream_t
Definition pb.h:318
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
pb_field_iter_t pb_field_t
Definition pb.h:369
#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
struct pb_callback_s pb_callback_t
Definition pb.h:413
struct pb_istream_s pb_istream_t
Definition pb.h:317
#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)
pb_type_t type
Definition pb.h:359
pb_size_t tag
Definition pb.h:356
size_t bytes_left
Definition pb_decode.h:49
size_t bytes_written
Definition pb_encode.h:49
A wrapper around a wpi::util::array that lets us treat it as a limited sized vector.
Definition ProtobufCallbacks.hpp:422
size_t m_currentIndex
Definition ProtobufCallbacks.hpp:424
size_t size() const
Definition ProtobufCallbacks.hpp:426
T & emplace_back(ArgTypes &&... Args)
Definition ProtobufCallbacks.hpp:429
wpi::util::array< T, N > m_array
Definition ProtobufCallbacks.hpp:423
bool IsFull() const noexcept
Returns if the buffer is completely filled up.
Definition ProtobufCallbacks.hpp:461
size_t Size() const noexcept
Returns the number of elements in the buffer.
Definition ProtobufCallbacks.hpp:468
WpiArrayUnpackCallback()
Constructs a WpiArrayUnpackCallback.
Definition ProtobufCallbacks.hpp:451
wpi::util::array< T, N > & Array() noexcept
Returns a reference to the backing array.
Definition ProtobufCallbacks.hpp:475
Definition array.hpp:15