15#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
16#define HAS_PROTO_MESSAGE_DUMP
43 return (
static_cast<uint32_t>(value) << 1) ^ (
static_cast<uint32_t>(value >> 31));
47 return (
static_cast<uint64_t
>(value) << 1) ^ (
static_cast<uint64_t
>(value >> 63));
51 return (value & 1) ?
static_cast<int32_t
>(~(value >> 1)) :
static_cast<int32_t
>(value >> 1);
55 return (value & 1) ?
static_cast<int64_t
>(~(value >> 1)) :
static_cast<int64_t
>(value >> 1);
63 while (
len > 0 && (*data & 0x80)) {
80 *buffer++ =
static_cast<uint8_t
>(
val | 0x80);
83 *buffer =
static_cast<uint8_t
>(
val);
117#ifdef USE_API_VARINT64
141#ifdef ESPHOME_DEBUG_API
146 if ((buffer[0] & 0x80) == 0) [[likely]]
147 return {buffer[0], 1};
163#ifdef USE_API_VARINT64
214#ifdef ESPHOME_DEBUG_API
215#define PROTO_ENCODE_DEBUG_PARAM , uint8_t *proto_debug_end_
216#define PROTO_ENCODE_DEBUG_ARG , proto_debug_end_
217#define PROTO_ENCODE_DEBUG_INIT(buf) , (buf)->data() + (buf)->size()
218#define PROTO_ENCODE_CHECK_BOUNDS(pos, n) \
220 if ((pos) + (n) > proto_debug_end_) \
221 proto_check_bounds_failed(pos, n, proto_debug_end_, __builtin_FUNCTION()); \
225#define PROTO_ENCODE_DEBUG_PARAM
226#define PROTO_ENCODE_DEBUG_ARG
227#define PROTO_ENCODE_DEBUG_INIT(buf)
228#define PROTO_ENCODE_CHECK_BOUNDS(pos, n)
236 if (value < 128) [[likely]] {
238 *this->
pos_++ =
static_cast<uint8_t
>(value);
266 uint8_t *(*encode_fn)(
const void *,
ProtoWriteBuffer &PROTO_ENCODE_DEBUG_PARAM));
269 uint8_t *(*encode_fn)(
const void *,
ProtoWriteBuffer &PROTO_ENCODE_DEBUG_PARAM));
279#ifdef ESPHOME_DEBUG_API
304 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
305 *
pos++ =
static_cast<uint8_t
>(value | 0x80);
307 }
while (value > 0x7F);
308 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
309 *
pos++ =
static_cast<uint8_t
>(value);
311 static inline void ESPHOME_ALWAYS_INLINE
encode_varint_raw(uint8_t *__restrict__ &
pos PROTO_ENCODE_DEBUG_PARAM,
314 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
315 *
pos++ =
static_cast<uint8_t
>(value);
324 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
325 *
pos++ =
static_cast<uint8_t
>(value);
329 PROTO_ENCODE_CHECK_BOUNDS(
pos, 2);
330 *
pos++ =
static_cast<uint8_t
>(value | 0x80);
331 *
pos++ =
static_cast<uint8_t
>(value >> 7);
339 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
340 *
pos++ =
static_cast<uint8_t
>(value);
345 static inline void ESPHOME_ALWAYS_INLINE
encode_field_raw(uint8_t *__restrict__ &
pos PROTO_ENCODE_DEBUG_PARAM,
350 static inline void ESPHOME_ALWAYS_INLINE
write_raw_byte(uint8_t *__restrict__ &
pos PROTO_ENCODE_DEBUG_PARAM,
352 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
357 static inline void ESPHOME_ALWAYS_INLINE
reserve_byte(uint8_t *__restrict__ &
pos PROTO_ENCODE_DEBUG_PARAM) {
358 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
362 static inline void ESPHOME_ALWAYS_INLINE
encode_raw(uint8_t *__restrict__ &
pos PROTO_ENCODE_DEBUG_PARAM,
363 const void *data,
size_t len) {
364 PROTO_ENCODE_CHECK_BOUNDS(
pos,
len);
365 std::memcpy(
pos, data,
len);
372#ifdef ESPHOME_DEBUG_API
373 assert(ref.
size() < 128 &&
"encode_short_string_force: string exceeds max_data_length < 128");
375 PROTO_ENCODE_CHECK_BOUNDS(
pos, 2 + ref.
size());
377 pos[1] =
static_cast<uint8_t
>(ref.
size());
384 PROTO_ENCODE_CHECK_BOUNDS(
pos, 5);
386#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
387 std::memcpy(
pos + 1, &value, 4);
389 pos[1] =
static_cast<uint8_t
>(value & 0xFF);
390 pos[2] =
static_cast<uint8_t
>((value >> 8) & 0xFF);
391 pos[3] =
static_cast<uint8_t
>((value >> 16) & 0xFF);
392 pos[4] =
static_cast<uint8_t
>((value >> 24) & 0xFF);
397 const char *
string,
size_t len,
bool force =
false) {
398 if (
len == 0 && !force)
402 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1 +
len);
403 *
pos++ =
static_cast<uint8_t
>(
len);
406 PROTO_ENCODE_CHECK_BOUNDS(
pos,
len);
408 std::memcpy(
pos,
string,
len);
412 const std::string &value,
bool force =
false) {
413 encode_string(
pos PROTO_ENCODE_DEBUG_ARG, field_id, value.data(), value.size(), force);
416 const StringRef &ref,
bool force =
false) {
420 const uint8_t *data,
size_t len,
bool force =
false) {
421 encode_string(
pos PROTO_ENCODE_DEBUG_ARG, field_id,
reinterpret_cast<const char *
>(data),
len, force);
424 uint32_t value,
bool force =
false) {
425 if (value == 0 && !force)
431 uint64_t value,
bool force =
false) {
432 if (value == 0 && !force)
438 bool force =
false) {
439 if (!value && !force)
442 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
443 *
pos++ = value ? 0x01 : 0x00;
446 uint32_t value,
bool force =
false) {
447 if (value == 0 && !force)
450 PROTO_ENCODE_CHECK_BOUNDS(
pos, 4);
451#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
452 std::memcpy(
pos, &value, 4);
455 *
pos++ = (value >> 0) & 0xFF;
456 *
pos++ = (value >> 8) & 0xFF;
457 *
pos++ = (value >> 16) & 0xFF;
458 *
pos++ = (value >> 24) & 0xFF;
466 bool force =
false) {
468 if (
raw == 0 && !force)
473 bool force =
false) {
476 encode_uint64(
pos PROTO_ENCODE_DEBUG_ARG, field_id,
static_cast<uint64_t
>(value), force);
482 bool force =
false) {
483 encode_uint64(
pos PROTO_ENCODE_DEBUG_ARG, field_id,
static_cast<uint64_t
>(value), force);
486 int32_t value,
bool force =
false) {
490 int64_t value,
bool force =
false) {
496 uint32_t field_id,
const T &value) {
510#ifdef HAS_PROTO_MESSAGE_DUMP
525 append_impl_(str, strlen(str));
531 append_impl_(str,
len);
540 memset(buf_ + pos_, c, n);
553 append_impl_(str, strlen(str));
564 const char *
c_str()
const {
return buf_; }
565 size_t size()
const {
return pos_; }
570 size_t pos()
const {
return pos_; }
582 void append_impl_(
const char *str,
size_t len) {
587 memcpy(buf_ + pos_, str,
len);
607#ifdef HAS_PROTO_MESSAGE_DUMP
609 virtual const LogString *
message_name()
const {
return LOG_STR(
"unknown"); }
656 static constexpr inline uint8_t ESPHOME_ALWAYS_INLINE
varint16(uint16_t value) {
661 static constexpr inline uint8_t ESPHOME_ALWAYS_INLINE
varint8(uint8_t value) {
674 if (__builtin_is_constant_evaluated())
675 return varint_wide(value);
676 return varint_slow(value);
685 if (__builtin_is_constant_evaluated())
686 return varint_wide(value);
687 return varint_slow(value);
694 static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE varint_wide(
uint32_t value) {
713 if (value <= UINT32_MAX) {
718 if (value < (1ULL << 35)) {
720 }
else if (value < (1ULL << 42)) {
722 }
else if (value < (1ULL << 49)) {
724 }
else if (value < (1ULL << 56)) {
726 }
else if (value < (1ULL << 63)) {
762 return varint(
static_cast<uint64_t
>(value));
780 return value ? field_id_size + (value < 0 ? 10 : varint(static_cast<uint32_t>(value))) : 0;
783 return field_id_size + (value < 0 ? 10 : varint(static_cast<uint32_t>(value)));
786 return value ? field_id_size +
varint(value) : 0;
789 return field_id_size +
varint(value);
794 return float_to_raw(value) != 0 ? field_id_size + 4 : 0;
797 return value ? field_id_size + 4 : 0;
800 return value ? field_id_size + 4 : 0;
809 return value ? field_id_size +
varint(value) : 0;
812 return field_id_size +
varint(value);
815 return value ? field_id_size +
varint(value) : 0;
818 return field_id_size +
varint(value);
833 return value ? field_id_size + 8 : 0;
836 return value ? field_id_size + 8 : 0;
839 return nested_size ? field_id_size +
varint(nested_size) + nested_size : 0;
843 return field_id_size +
varint(nested_size) + nested_size;
851 return static_cast<const T *
>(msg)->encode(buf PROTO_ENCODE_DEBUG_ARG);
StringRef is a reference to a string owned by something else.
constexpr const char * c_str() const
constexpr size_type size() const
Byte buffer that skips zero-initialization on resize().
Fixed-size buffer for message dumps - avoids heap allocation.
const char * c_str() const
DumpBuffer & append(size_t n, char c)
void append_p_esp8266(const char *str)
Out-of-line ESP8266 PROGMEM append to avoid inlining strlen_P/memcpy_P at every call site.
DumpBuffer & append_p(const char *str)
Append a PROGMEM string (flash-safe on ESP8266, regular append on other platforms)
size_t pos() const
Get current position for use with buf_append_printf.
static constexpr size_t CAPACITY
DumpBuffer & append(const char *str, size_t len)
DumpBuffer & append(const char *str)
char * data()
Get writable buffer pointer for use with buf_append_printf.
void set_pos(size_t pos)
Update position after buf_append_printf call.
uint32_t as_fixed32() const
int32_t as_sfixed32() const
Proto32Bit(uint32_t value)
virtual bool decode_32bit(uint32_t field_id, Proto32Bit value)
virtual bool decode_varint(uint32_t field_id, proto_varint_value_t value)
void decode(const uint8_t *buffer, size_t length)
~ProtoDecodableMessage()=default
virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value)
static uint32_t count_repeated_field(const uint8_t *buffer, size_t length, uint32_t target_field_id)
Count occurrences of a repeated field in a protobuf buffer.
Static encode helpers for generated encode() functions.
static void encode_bool(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, bool value, bool force=false)
static void encode_string(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, const char *string, size_t len, bool force=false)
static void encode_sint32(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, int32_t value, bool force=false)
static void ESPHOME_ALWAYS_INLINE encode_varint_raw_64(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint64_t value)
static void ESPHOME_ALWAYS_INLINE encode_varint_raw_short(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t value)
Encode a varint that is expected to be 1-2 bytes (e.g. zigzag RSSI, small lengths).
static void encode_string(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, const StringRef &ref, bool force=false)
static void encode_int64(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, int64_t value, bool force=false)
static void encode_varint_raw_loop(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, T value)
Write a multi-byte varint directly through a pos pointer.
static void ESPHOME_ALWAYS_INLINE write_raw_byte(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint8_t b)
Write a single precomputed tag byte. Tag must be < 128.
static void encode_float(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, float value, bool force=false)
static void encode_short_string_force(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint8_t tag, const StringRef &ref)
Encode tag + 1-byte length + raw string data.
static void ESPHOME_ALWAYS_INLINE write_tag_and_fixed32(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint8_t tag, uint32_t value)
Write a precomputed tag byte + 32-bit value in one operation.
static void encode_optional_sub_message(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, ProtoWriteBuffer &buffer, uint32_t field_id, const T &value)
static void encode_sub_message(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, ProtoWriteBuffer &buffer, uint32_t field_id, const T &value)
Sub-message encoding: sync pos to buffer, delegate, get pos from return value.
static void ESPHOME_ALWAYS_INLINE reserve_byte(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM)
Reserve one byte for later backpatch (e.g., sub-message length).
static void encode_sint64(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, int64_t value, bool force=false)
static void ESPHOME_ALWAYS_INLINE encode_raw(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, const void *data, size_t len)
Write raw bytes to the buffer (no tag, no length prefix).
static void encode_fixed32(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, uint32_t value, bool force=false)
static void ESPHOME_ALWAYS_INLINE encode_field_raw(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, uint32_t type)
static void ESPHOME_ALWAYS_INLINE encode_varint_raw(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t value)
static void encode_uint64(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, uint64_t value, bool force=false)
static void encode_int32(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, int32_t value, bool force=false)
static void encode_bytes(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, const uint8_t *data, size_t len, bool force=false)
static void encode_uint32(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, uint32_t value, bool force=false)
static void encode_string(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, const std::string &value, bool force=false)
void decode_to_message(T &msg) const
Decode the length-delimited data into a message instance.
const uint8_t *const value_
const uint8_t * data() const
ProtoLengthDelimited(const uint8_t *value, size_t length)
std::string as_string() const
virtual const LogString * message_name() const
uint8_t * encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const
uint32_t calculate_size() const
virtual const char * dump_to(DumpBuffer &out) const =0
static constexpr uint32_t calc_uint64(uint32_t field_id_size, uint64_t value)
static constexpr uint32_t calc_int64(uint32_t field_id_size, int64_t value)
static constexpr uint8_t ESPHOME_ALWAYS_INLINE varint8(uint8_t value)
static constexpr uint32_t calc_bool(uint32_t field_id_size, bool value)
static constexpr uint32_t calc_message(uint32_t field_id_size, uint32_t nested_size)
static constexpr uint32_t calc_sint32(uint32_t field_id_size, int32_t value)
static constexpr uint32_t calc_sint64_force(uint32_t field_id_size, int64_t value)
static constexpr uint32_t ESPHOME_ALWAYS_INLINE calc_uint64_force(uint32_t field_id_size, uint64_t value)
static constexpr uint32_t field(uint32_t field_id, uint32_t type)
Calculates the size in bytes needed to encode a field ID and wire type.
static constexpr uint32_t ESPHOME_ALWAYS_INLINE varint(uint32_t value)
Calculates the size in bytes needed to encode a uint32_t value as a varint.
static constexpr uint32_t calc_uint32_force(uint32_t field_id_size, uint32_t value)
static constexpr uint32_t varint(int32_t value)
Calculates the size in bytes needed to encode an int32_t value as a varint.
static constexpr uint32_t calc_int64_force(uint32_t field_id_size, int64_t value)
static constexpr uint32_t calc_sfixed64(uint32_t field_id_size, int64_t value)
static constexpr uint32_t calc_uint32(uint32_t field_id_size, uint32_t value)
static constexpr uint32_t VARINT_THRESHOLD_3_BYTE
static constexpr uint8_t ESPHOME_ALWAYS_INLINE varint16(uint16_t value)
static constexpr uint32_t calc_length(uint32_t field_id_size, size_t len)
static constexpr uint32_t calc_int32(uint32_t field_id_size, int32_t value)
static constexpr uint32_t calc_fixed64(uint32_t field_id_size, uint64_t value)
static constexpr uint32_t ESPHOME_ALWAYS_INLINE varint_short(uint32_t value)
Size of a varint expected to be 1-2 bytes (e.g.
static constexpr uint32_t varint(int64_t value)
Calculates the size in bytes needed to encode an int64_t value as a varint.
static constexpr uint32_t ESPHOME_ALWAYS_INLINE calc_length_force(uint32_t field_id_size, size_t len)
static constexpr uint32_t calc_bool_force(uint32_t field_id_size)
static constexpr uint32_t calc_sfixed32(uint32_t field_id_size, int32_t value)
static constexpr uint32_t varint(uint64_t value)
Calculates the size in bytes needed to encode a uint64_t value as a varint.
static uint32_t calc_float(uint32_t field_id_size, float value)
static constexpr uint32_t calc_sint64(uint32_t field_id_size, int64_t value)
static constexpr uint32_t calc_int32_force(uint32_t field_id_size, int32_t value)
static constexpr uint32_t calc_fixed32(uint32_t field_id_size, uint32_t value)
static constexpr uint32_t VARINT_THRESHOLD_2_BYTE
static constexpr uint32_t ESPHOME_ALWAYS_INLINE calc_message_force(uint32_t field_id_size, uint32_t nested_size)
static constexpr uint32_t ESPHOME_ALWAYS_INLINE calc_sint32_force(uint32_t field_id_size, int32_t value)
static constexpr uint32_t VARINT_THRESHOLD_1_BYTE
static constexpr uint32_t VARINT_THRESHOLD_4_BYTE
Static varint parsing methods for the protobuf wire format.
static ProtoVarIntResult ESPHOME_ALWAYS_INLINE parse_non_empty(const uint8_t *buffer, uint32_t len)
Parse a varint from buffer.
static ProtoVarIntResult parse_wide(const uint8_t *buffer, uint32_t len, uint32_t result32) __attribute__((noinline))
Continue parsing varint bytes 4-9 with 64-bit arithmetic.
static ProtoVarIntResult parse_slow(const uint8_t *buffer, uint32_t len) __attribute__((noinline))
static ProtoVarIntResult ESPHOME_ALWAYS_INLINE parse(const uint8_t *buffer, uint32_t len)
Parse a varint from buffer (safe for empty buffers).
void set_pos(uint8_t *pos)
void debug_check_encode_size_(uint32_t field_id, uint32_t expected, ptrdiff_t actual)
void debug_check_bounds_(size_t bytes)
void encode_varint_raw_slow_(uint32_t value) __attribute__((noinline))
void encode_field_raw(uint32_t field_id, uint32_t type)
Encode a field key (tag/wire type combination).
void encode_optional_sub_message(uint32_t field_id, const T &value)
Encode an optional singular submessage field — skips if empty.
void encode_sub_message(uint32_t field_id, const T &value)
Single-pass encode for repeated submessage elements.
void debug_check_bounds_(size_t bytes, const char *caller=__builtin_FUNCTION())
uint8_t * get_pos() const
APIBuffer * get_buffer() const
void ESPHOME_ALWAYS_INLINE encode_varint_raw(uint32_t value)
ProtoWriteBuffer(APIBuffer *buffer, size_t write_pos)
ProtoWriteBuffer(APIBuffer *buffer)
struct @65::@66 __attribute__
Wake the main loop task from an ISR. ISR-safe.
constexpr uint32_t encode_zigzag32(int32_t value)
constexpr uint32_t VARINT_MAX_2_BYTE
constexpr uint8_t WIRE_TYPE_VARINT
uint64_t proto_varint_value_t
Type used for decoded varint values - uint64_t when BLE needs 64-bit addresses, uint32_t otherwise.
uint8_t * proto_encode_msg(const void *msg, ProtoWriteBuffer &buf PROTO_ENCODE_DEBUG_PARAM)
const char * proto_enum_to_string(T value)
constexpr uint32_t VARINT_MAX_1_BYTE
constexpr uint64_t encode_zigzag64(int64_t value)
constexpr uint8_t WIRE_TYPE_MASK
constexpr uint32_t PROTO_VARINT_PARSE_FAILED
Sentinel value for consumed field indicating parse failure.
constexpr uint8_t WIRE_TYPE_LENGTH_DELIMITED
constexpr int32_t decode_zigzag32(uint32_t value)
constexpr uint8_t WIRE_TYPE_FIXED32
uint32_t float_to_raw(float value)
constexpr int64_t decode_zigzag64(uint64_t value)
void encode_varint_to_buffer(uint32_t val, uint8_t *buffer)
Encode a varint directly into a pre-allocated buffer.
uint16_t count_packed_varints(const uint8_t *data, size_t len)
Count number of varints in a packed buffer.
void proto_check_bounds_failed(const uint8_t *pos, size_t bytes, const uint8_t *end, const char *caller)
Result of parsing a varint: value + number of bytes consumed.
constexpr bool has_value() const
proto_varint_value_t value