9static const char *
const TAG =
"api.proto";
11uint32_t ProtoSize::varint_slow(
uint32_t value) {
return varint_wide(value); }
16 *this->
pos_++ =
static_cast<uint8_t
>(value | 0x80);
18 }
while (value > 0x7F);
20 *this->
pos_++ =
static_cast<uint8_t
>(value);
25 uint32_t result32 = buffer[0] & 0x7F;
26#ifdef USE_API_VARINT64
31 for (
uint32_t i = 1; i < limit; i++) {
32 uint8_t
val = buffer[i];
34 if ((
val & 0x80) == 0) {
35 return {result32, i + 1};
38#ifdef USE_API_VARINT64
45#ifdef USE_API_VARINT64
47 uint64_t result64 = result32;
49 for (
uint32_t i = 4; i < limit; i++) {
50 uint8_t
val = buffer[i];
51 result64 |= uint64_t(
val & 0x7F) << (i * 7);
52 if ((
val & 0x80) == 0) {
53 return {result64, i + 1};
62 const uint8_t *ptr = buffer;
68 if (!res.has_value()) {
78 if (field_id == target_field_id) {
86 if (!res.has_value()) {
94 if (!res.has_value()) {
99 if (field_length >
static_cast<size_t>(
end - ptr)) {
148 uint8_t *(*encode_fn)(
const void *,
152 uint8_t *len_pos = this->
pos_;
155 uint8_t *body_start = this->
pos_;
156 this->
pos_ = encode_fn(value, *
this PROTO_ENCODE_DEBUG_INIT(this->
buffer_));
158 if (body_size < 128) [[likely]] {
160 *len_pos =
static_cast<uint8_t
>(body_size);
167 std::memmove(body_start + extra, body_start, body_size);
168 uint8_t *
end = this->
pos_ + extra;
170 this->
pos_ = len_pos;
177 uint8_t *(*encode_fn)(
const void *,
179 if (nested_size == 0)
183#ifdef ESPHOME_DEBUG_API
184 uint8_t *start = this->
pos_;
185 this->
pos_ = encode_fn(value, *
this PROTO_ENCODE_DEBUG_INIT(this->
buffer_));
186 if (
static_cast<uint32_t>(this->
pos_ - start) != nested_size)
189 this->
pos_ = encode_fn(value, *
this PROTO_ENCODE_DEBUG_INIT(this->
buffer_));
193#ifdef ESPHOME_DEBUG_API
195 ESP_LOGE(TAG,
"Proto encode bounds check failed in %s: need %zu bytes, %td available", caller, bytes,
end -
pos);
199 if (this->
pos_ + bytes > this->
buffer_->
data() + this->buffer_->size()) {
200 ESP_LOGE(TAG,
"ProtoWriteBuffer bounds check failed in %s: bytes=%zu offset=%td buf_size=%zu", caller, bytes,
206 ESP_LOGE(TAG,
"encode_message: size mismatch for field %" PRIu32
": calculated=%" PRIu32
" actual=%td", field_id,
214 const uint8_t *ptr = buffer;
220 if (!res.has_value()) {
221 ESP_LOGV(TAG,
"Invalid field start at offset %ld", (
long) (ptr - buffer));
230 switch (field_type) {
233 if (!res.has_value()) {
234 ESP_LOGV(TAG,
"Invalid VarInt at offset %ld", (
long) (ptr - buffer));
238 ESP_LOGV(TAG,
"Cannot decode VarInt field %" PRIu32
" with value %" PRIu64
"!", field_id,
239 static_cast<uint64_t
>(res.value));
246 if (!res.has_value()) {
247 ESP_LOGV(TAG,
"Invalid Length Delimited at offset %ld", (
long) (ptr - buffer));
252 if (field_length >
static_cast<size_t>(
end - ptr)) {
253 ESP_LOGV(TAG,
"Out-of-bounds Length Delimited at offset %ld", (
long) (ptr - buffer));
257 ESP_LOGV(TAG,
"Cannot decode Length Delimited field %" PRIu32
"!", field_id);
264 ESP_LOGV(TAG,
"Out-of-bounds Fixed32-bit at offset %ld", (
long) (ptr - buffer));
268#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
270 memcpy(&
val, ptr, 4);
275 ESP_LOGV(TAG,
"Cannot decode 32-bit field %" PRIu32
" with value %" PRIu32
"!", field_id,
val);
281 ESP_LOGV(TAG,
"Invalid field type %" PRIu32
" at offset %ld", field_type, (
long) (ptr - buffer));
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)
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 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 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 debug_check_encode_size_(uint32_t field_id, uint32_t expected, ptrdiff_t actual)
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())
void ESPHOME_ALWAYS_INLINE encode_varint_raw(uint32_t value)
constexpr uint8_t WIRE_TYPE_VARINT
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 uint8_t WIRE_TYPE_FIXED32
void proto_check_bounds_failed(const uint8_t *pos, size_t bytes, const uint8_t *end, const char *caller)
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Result of parsing a varint: value + number of bytes consumed.