DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
protobuf.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file protobuf.h
6 * @brief Protocol Buffers wire codec (DETWS_ENABLE_PROTOBUF) - zero-heap streaming writer
7 * + cursor reader over caller buffers, the same shape as the shipped CBOR /
8 * MessagePack codecs. This is the standalone Protobuf deliverable; gRPC (framed
9 * Protobuf over HTTP/2) is gated on the HTTP/2 roadmap item.
10 *
11 * Wire format (https://protobuf.dev/programming-guides/encoding/):
12 * - A field is a tag varint `(field_number << 3) | wire_type` then the value.
13 * - Varints are little-endian base-128 with the high bit as a continuation flag.
14 * - Wire types: 0 VARINT (int/uint/sint/bool/enum), 1 I64 (fixed64/double, 8 bytes LE),
15 * 2 LEN (string/bytes/embedded message), 5 I32 (fixed32/float, 4 bytes LE). Groups
16 * (3/4) are deprecated and rejected by the reader.
17 * - sint32/sint64 use ZigZag: `(n << 1) ^ (n >> 31|63)`.
18 *
19 * The writer encodes one field at a time into a caller buffer (fail-closed on overflow);
20 * embedded messages are built into a separate buffer and added with @ref pb_bytes. The
21 * reader is a cursor: it decodes the field at the buffer head and reports bytes consumed.
22 *
23 * @author Douglas Quigg (dstroy0)
24 * @date 2026
25 */
26
27#ifndef DETERMINISTICESPASYNCWEBSERVER_PROTOBUF_H
28#define DETERMINISTICESPASYNCWEBSERVER_PROTOBUF_H
29
30#include "ServerConfig.h"
31
32#if DETWS_ENABLE_PROTOBUF
33
34#include <stddef.h>
35#include <stdint.h>
36
37// Wire types.
38#define PB_WT_VARINT 0
39#define PB_WT_I64 1
40#define PB_WT_LEN 2
41#define PB_WT_I32 5
42
43// ---- writer ----
44
45/** @brief Streaming encoder over a caller buffer. Treat the fields as opaque. */
46struct PbWriter
47{
48 uint8_t *buf;
49 size_t cap;
50 size_t pos;
51 bool error; ///< sticky overflow flag
52};
53
54void pb_writer_init(PbWriter *w, uint8_t *buf, size_t cap);
55
56/** @brief Write a raw varint (no tag). */
57bool pb_write_varint(PbWriter *w, uint64_t v);
58
59/** @brief Write a field tag `(field << 3) | wire_type`. */
60bool pb_write_tag(PbWriter *w, uint32_t field, uint8_t wire_type);
61
62bool pb_uint64(PbWriter *w, uint32_t field, uint64_t v); ///< varint (uint32/uint64/enum)
63bool pb_int64(PbWriter *w, uint32_t field, int64_t v); ///< varint, two's complement (int32/int64)
64bool pb_sint64(PbWriter *w, uint32_t field, int64_t v); ///< ZigZag varint (sint32/sint64)
65bool pb_bool(PbWriter *w, uint32_t field, bool v);
66bool pb_fixed32(PbWriter *w, uint32_t field, uint32_t v); ///< wire type 5
67bool pb_fixed64(PbWriter *w, uint32_t field, uint64_t v); ///< wire type 1
68bool pb_float(PbWriter *w, uint32_t field, float v);
69bool pb_double(PbWriter *w, uint32_t field, double v);
70bool pb_bytes(PbWriter *w, uint32_t field, const uint8_t *data, size_t len); ///< wire type 2
71bool pb_string(PbWriter *w, uint32_t field, const char *s);
72
73/** @brief Finish: returns the encoded byte count, or 0 if any write overflowed. */
74size_t pb_writer_finish(PbWriter *w);
75
76// ---- reader ----
77
78/** @brief One decoded field. For LEN, @ref data / @ref len point INTO the source buffer. */
79struct PbField
80{
81 uint32_t field_number;
82 uint8_t wire_type;
83 uint64_t value; ///< VARINT value, or the raw LE bits for I32 / I64
84 const uint8_t *data; ///< LEN payload (not copied)
85 size_t len; ///< LEN length
86};
87
88/** @brief Read a raw varint at [buf+*pos]; advances *pos. False on truncation / overlong (>10 bytes). */
89bool pb_read_varint(const uint8_t *buf, size_t len, size_t *pos, uint64_t *out);
90
91/**
92 * @brief Read one field at [buf+*pos]; advances *pos past it.
93 * @return true on a complete field; false at end-of-buffer or on a malformed / group field.
94 */
95bool pb_read_field(const uint8_t *buf, size_t len, size_t *pos, PbField *out);
96
97// Value decoders.
98int64_t pb_zigzag64(uint64_t v);
99int32_t pb_zigzag32(uint32_t v);
100float pb_float_bits(uint32_t bits);
101double pb_double_bits(uint64_t bits);
102
103#endif // DETWS_ENABLE_PROTOBUF
104
105#endif // DETERMINISTICESPASYNCWEBSERVER_PROTOBUF_H
User-facing configuration for DeterministicESPAsyncWebServer.