DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
redis_resp.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 redis_resp.h
6 * @brief Redis RESP2/RESP3 wire codec (DETWS_ENABLE_REDIS) - zero-heap command
7 * encoder + reply parser, so a device can talk to a Redis server with the
8 * shipped outbound client transport.
9 *
10 * RESP (https://redis.io/docs/latest/develop/reference/protocol-spec):
11 * - A command is an array of bulk strings: `*<n>\r\n$<len>\r\n<arg>\r\n...`.
12 * - A RESP2 reply is one of: simple string `+OK\r\n`, error `-ERR ...\r\n`,
13 * integer `:<n>\r\n`, bulk string `$<len>\r\n<bytes>\r\n` (`$-1\r\n` = nil), or
14 * array `*<n>\r\n<elements>` (`*-1\r\n` = nil).
15 * - RESP3 adds: null `_\r\n`, boolean `#t\r\n`/`#f\r\n`, double `,<x>\r\n`, big
16 * number `(<digits>\r\n`, bulk error `!<len>\r\n...`, verbatim string
17 * `=<len>\r\n<fmt>:<text>\r\n`, map `%<pairs>\r\n`, set `~<n>\r\n`, push `><n>\r\n`.
18 *
19 * The parser is a cursor: it decodes one value at the buffer head and reports how
20 * many bytes it consumed; for an aggregate (array / set / push / map) it reports
21 * the following child count and the caller parses each child from the remaining
22 * bytes (no recursion state, no heap). A map of N pairs reports count 2*N.
23 *
24 * @author Douglas Quigg (dstroy0)
25 * @date 2026
26 */
27
28#ifndef DETERMINISTICESPASYNCWEBSERVER_REDIS_RESP_H
29#define DETERMINISTICESPASYNCWEBSERVER_REDIS_RESP_H
30
31#include "ServerConfig.h"
32
33#if DETWS_ENABLE_REDIS
34
35#include <stddef.h>
36#include <stdint.h>
37
38/** @brief RESP2/RESP3 reply value types. */
39enum class RespType : uint8_t
40{
41 RESP_SIMPLE, ///< simple string (+); value in str/str_len
42 RESP_ERROR, ///< error (-); message in str/str_len
43 RESP_INTEGER, ///< integer (:); value in ival
44 RESP_BULK, ///< bulk string ($); bytes in str/str_len
45 RESP_ARRAY, ///< array (*); element count in count (parse each from the remainder)
46 RESP_NIL, ///< null bulk string ($-1), null array (*-1), or RESP3 null (_)
47 // RESP3 additions:
48 RESP_BOOL, ///< boolean (#); 0/1 in ival
49 RESP_DOUBLE, ///< double (,); value in dval, text in str/str_len
50 RESP_BIG_NUMBER, ///< big number ((); digits in str/str_len
51 RESP_BULK_ERROR, ///< bulk error (!); message in str/str_len
52 RESP_VERBATIM, ///< verbatim string (=); str includes the 3-char format + ':'
53 RESP_MAP, ///< map (%); count = 2 * pairs = following child count
54 RESP_SET, ///< set (~); element count in count
55 RESP_PUSH, ///< push (>); element count in count
56};
57
58/** @brief One decoded RESP value. String fields point INTO the source buffer (not copied). */
59struct RespReply
60{
61 RespType type;
62 int64_t ival; ///< value for RespType::RESP_INTEGER; 0/1 for RespType::RESP_BOOL; child count for aggregates
63 double dval; ///< value for RespType::RESP_DOUBLE (best-effort; str is authoritative)
64 const char *str; ///< bytes for simple/error/bulk/big-number/bulk-error/verbatim/double text
65 size_t str_len; ///< length of @ref str
66 int64_t count; ///< child count for RespType::RESP_ARRAY / RespType::RESP_SET / RespType::RESP_PUSH /
67 ///< RespType::RESP_MAP (map = 2*pairs)
68};
69
70/**
71 * @brief Encode a command (array of bulk strings) into @p buf.
72 *
73 * @param args argument byte pointers (argv).
74 * @param arg_lens per-arg byte lengths, or nullptr to measure each NUL-terminated arg.
75 * @param argc number of arguments.
76 * @return bytes written (excluding any NUL), or 0 on overflow / bad input.
77 */
78size_t resp_encode_command(char *buf, size_t cap, const char *const *args, const size_t *arg_lens, size_t argc);
79
80/**
81 * @brief Parse one RESP value at the head of [buf, buf+len).
82 *
83 * @param consumed receives the number of bytes the value occupied (so the caller
84 * can advance to the next value / array element).
85 * @return true on a complete value; false if the buffer holds an incomplete or
86 * malformed value (then @p out / @p consumed are unspecified).
87 */
88bool resp_parse(const uint8_t *buf, size_t len, RespReply *out, size_t *consumed);
89
90#endif // DETWS_ENABLE_REDIS
91
92#endif // DETERMINISTICESPASYNCWEBSERVER_REDIS_RESP_H
User-facing configuration for DeterministicESPAsyncWebServer.