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);
26#ifdef USE_API_VARINT64
31 for (
uint32_t i = 1; i < limit; 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++) {
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)) {
150 uint8_t *len_pos =
pos;
151 PROTO_ENCODE_CHECK_BOUNDS(
pos, 1);
152 uint8_t *body_start =
pos + 1;
153 uint8_t *after_body = encode_fn(value, body_start PROTO_ENCODE_DEBUG_ARG);
157 *len_pos =
static_cast<uint8_t
>(body_size);
162 PROTO_ENCODE_CHECK_BOUNDS(after_body, extra);
163 std::memmove(body_start + extra, body_start, body_size);
166 return after_body + extra;
173 return encode_fn(value,
pos PROTO_ENCODE_DEBUG_ARG);
176#ifdef ESPHOME_DEBUG_API
178 ESP_LOGE(TAG,
"Proto encode bounds check failed in %s: need %zu bytes, %td available", caller, bytes,
end -
pos);
184 ESP_LOGE(TAG,
"Proto encode ended %td bytes off the calculated size",
end - expected);
189 if (actual ==
static_cast<ptrdiff_t
>(expected))
191 ESP_LOGE(TAG,
"encode_message: size mismatch for field %" PRIu32
": calculated=%" PRIu32
" actual=%td", field_id,
196 if (this->
pos_ + bytes > this->
buffer_->
data() + this->buffer_->size()) {
197 ESP_LOGE(TAG,
"ProtoWriteBuffer bounds check failed in %s: bytes=%zu offset=%td buf_size=%zu", caller, bytes,
206 const uint8_t *ptr =
buffer;
213 if (*ptr < 0x80) [[likely]] {
218 if (!res.has_value())
227 if (!read_varint(tag_value)) {
228 ESP_LOGV(TAG,
"Invalid field start at offset %ld", (
long) (ptr -
buffer));
235 const uint8_t *data = ptr;
239 if (!read_varint(scalar)) {
240 ESP_LOGV(TAG,
"Invalid VarInt at offset %ld", (
long) (ptr -
buffer));
244 switch (field_type) {
247 if (!read_varint(length_value)) {
248 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 scalar = field_length;
263 ESP_LOGV(TAG,
"Out-of-bounds Fixed32-bit at offset %ld", (
long) (ptr -
buffer));
272 ESP_LOGV(TAG,
"Invalid field type %" PRIu32
" at offset %ld", field_type, (
long) (ptr -
buffer));
276 field(msg, tag, data, scalar);
static void decode_fields(void *msg, const uint8_t *buffer, size_t length, DecodeFieldFn field)
Walk buffer and hand every field to field.
void(*)(void *msg, uint32_t tag, const uint8_t *data, proto_varint_value_t scalar) DecodeFieldFn
Stores one decoded field into msg; generated per message type.
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 uint8_t *ESPHOME_ALWAYS_INLINE encode_varint_raw(uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM, uint32_t value)
static uint8_t * encode_sized_sub_message_body(uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM, uint32_t nested_size, const void *value, ProtoEncodeFn encode_fn)
Length and body for a precomputed size.
static uint8_t * 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 uint8_t * encode_sub_message_body(uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM, const void *value, ProtoEncodeFn encode_fn)
Length and body, length backpatched after the body is written.
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 encode_varint_raw_slow_(uint32_t value) __attribute__((noinline))
void debug_check_bounds_(size_t bytes, const char *caller=__builtin_FUNCTION())
uint8_t *(*)(const void *, uint8_t *PROTO_ENCODE_DEBUG_PARAM) ProtoEncodeFn
Generated encode body: writes the fields at pos, returns the cursor past them.
constexpr uint8_t WIRE_TYPE_VARINT
ESPHOME_LOG_TAG(TAG, "api.connection")
uint64_t proto_varint_value_t
Type used for decoded varint values - uint64_t when BLE needs 64-bit addresses, uint32_t otherwise.
void proto_check_encode_end(const uint8_t *end, const uint8_t *expected)
Aborts unless an encode body ended exactly where calculate_size() promised.
constexpr uint32_t VARINT_MAX_1_BYTE
void proto_check_sub_message_size(uint32_t field_id, uint32_t expected, const uint8_t *len_pos, const uint8_t *end)
Aborts unless a sized sub-message (length prefix at len_pos) ended where its calculated size said.
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.