18static bool put_len_prefix(
char *buf,
size_t cap,
size_t *pos,
char tag,
size_t n)
26 tmp[t++] = (char)(
'0' + (n % 10));
29 if (*pos + 1u + (
size_t)t + 2u >= cap)
33 buf[(*pos)++] = tmp[--t];
39size_t resp_encode_command(
char *buf,
size_t cap,
const char *
const *args,
const size_t *arg_lens,
size_t argc)
41 if (!buf || cap == 0 || !args || argc == 0)
44 if (!put_len_prefix(buf, cap, &pos,
'*', argc))
47 for (
size_t i = 0; i < argc; i++)
51 size_t alen = arg_lens ? arg_lens[i] : strnlen(args[i], cap);
52 if (!put_len_prefix(buf, cap, &pos,
'$', alen))
54 if (pos + alen + 2 >= cap)
56 memcpy(buf + pos, args[i], alen);
67static size_t find_crlf(
const uint8_t *buf,
size_t len,
size_t from)
69 for (
size_t i = from; i + 1 < len; i++)
70 if (buf[i] ==
'\r' && buf[i + 1] ==
'\n')
76static bool parse_int(
const uint8_t *buf,
size_t from,
size_t end, int64_t *out)
92 if (buf[i] <
'0' || buf[i] >
'9')
94 v = v * 10u + (uint64_t)(buf[i] -
'0');
96 *out = neg ? (int64_t)(0ULL - v) : (int64_t)v;
101static bool slice_ieq(
const uint8_t *buf,
size_t from,
size_t end,
const char *s)
103 for (
size_t i = from; i < end; i++, s++)
108 if (a >=
'A' && a <=
'Z')
109 a = (uint8_t)(a + 32);
111 if (b >=
'A' && b <=
'Z')
121static bool parse_double_special(
const uint8_t *buf,
size_t from,
size_t end,
double *out)
123 if (slice_ieq(buf, from, end,
"inf") || slice_ieq(buf, from, end,
"+inf"))
128 if (slice_ieq(buf, from, end,
"-inf"))
130 *out = -1e308 * 10.0;
133 if (slice_ieq(buf, from, end,
"nan"))
135 double inf = 1e308 * 10.0;
144static bool parse_exponent(
const uint8_t *buf,
size_t *i,
size_t end,
int *exp)
147 if (!(*i < end && (buf[*i] ==
'e' || buf[*i] ==
'E')))
151 if (*i < end && (buf[*i] ==
'+' || buf[*i] ==
'-'))
153 eneg = (buf[*i] ==
'-');
157 while (*i < end && buf[*i] >=
'0' && buf[*i] <=
'9')
160 *exp = *exp * 10 + (buf[*i] -
'0');
173static bool parse_double(
const uint8_t *buf,
size_t from,
size_t end,
double *out)
175 if (parse_double_special(buf, from, end, out))
180 if (i < end && (buf[i] ==
'+' || buf[i] ==
'-'))
182 neg = (buf[i] ==
'-');
187 for (; i < end && buf[i] >=
'0' && buf[i] <=
'9'; i++)
189 mant = mant * 10.0 + (buf[i] -
'0');
192 if (i < end && buf[i] ==
'.')
196 for (; i < end && buf[i] >=
'0' && buf[i] <=
'9'; i++)
198 mant += (buf[i] -
'0') * scale;
206 if (!parse_exponent(buf, &i, end, &exp))
211 int e = exp < 0 ? -exp : exp;
212 for (
int k = 0; k < e; k++)
214 mant = (exp < 0) ? (mant / scale) : (mant * scale);
215 *out = neg ? -mant : mant;
221static bool parse_bulk_body(
const uint8_t *buf,
size_t len, uint8_t type,
size_t header_from,
size_t header_to,
222 size_t after_header, RespReply *out,
size_t *consumed)
225 if (!parse_int(buf, header_from, header_to, &blen))
227 if (type ==
'$' && blen < 0)
229 out->type = RespType::RESP_NIL;
230 *consumed = after_header;
237 if (after_header + 2 > len || (uint64_t)blen > (uint64_t)(len - after_header - 2))
239 size_t need = after_header + (size_t)blen + 2;
240 if (buf[after_header + (
size_t)blen] !=
'\r' || buf[after_header + (size_t)blen + 1] !=
'\n')
243 out->type = RespType::RESP_BULK;
244 else if (type ==
'!')
245 out->type = RespType::RESP_BULK_ERROR;
247 out->type = RespType::RESP_VERBATIM;
248 out->str = (
const char *)(buf + after_header);
249 out->str_len = (size_t)blen;
256static bool parse_aggregate(
const uint8_t *buf, uint8_t type,
size_t header_from,
size_t header_to,
size_t after_header,
257 RespReply *out,
size_t *consumed)
260 if (!parse_int(buf, header_from, header_to, &n))
262 if (type ==
'*' && n < 0)
264 out->type = RespType::RESP_NIL;
265 *consumed = after_header;
271 out->type = RespType::RESP_ARRAY;
272 else if (type ==
'~')
273 out->type = RespType::RESP_SET;
275 out->type = RespType::RESP_PUSH;
278 *consumed = after_header;
282bool resp_parse(
const uint8_t *buf,
size_t len, RespReply *out,
size_t *consumed)
284 if (!buf || len < 3 || !out || !consumed)
287 size_t crlf = find_crlf(buf, len, 1);
290 size_t header_from = 1;
291 size_t header_to = crlf;
292 size_t after_header = crlf + 2;
304 out->type = (buf[0] ==
'+') ? RespType::RESP_SIMPLE : RespType::RESP_ERROR;
305 out->str = (
const char *)(buf + header_from);
306 out->str_len = header_to - header_from;
307 *consumed = after_header;
312 if (!parse_int(buf, header_from, header_to, &v))
314 out->type = RespType::RESP_INTEGER;
316 *consumed = after_header;
324 return parse_bulk_body(buf, len, buf[0], header_from, header_to, after_header, out, consumed);
330 return parse_aggregate(buf, buf[0], header_from, header_to, after_header, out, consumed);
334 if (!parse_int(buf, header_from, header_to, &n) || n < 0)
336 out->type = RespType::RESP_MAP;
339 *consumed = after_header;
344 out->type = RespType::RESP_NIL;
345 *consumed = after_header;
349 if (header_to - header_from != 1 || (buf[header_from] !=
't' && buf[header_from] !=
'f'))
351 out->type = RespType::RESP_BOOL;
352 out->ival = (buf[header_from] ==
't') ? 1 : 0;
353 *consumed = after_header;
358 out->type = RespType::RESP_DOUBLE;
359 out->str = (
const char *)(buf + header_from);
360 out->str_len = header_to - header_from;
361 parse_double(buf, header_from, header_to, &out->dval);
362 *consumed = after_header;
366 out->type = RespType::RESP_BIG_NUMBER;
367 out->str = (
const char *)(buf + header_from);
368 out->str_len = header_to - header_from;
369 *consumed = after_header;
Redis RESP2/RESP3 wire codec (DETWS_ENABLE_REDIS) - zero-heap command encoder + reply parser,...