18static bool put_len_prefix(
char *buf,
size_t cap,
size_t *pos,
char tag,
size_t n)
28 tmp[t++] = (char)(
'0' + (n % 10));
31 if (*pos + 1u + (
size_t)t + 2u >= cap)
38 buf[(*pos)++] = tmp[--t];
45size_t pc_resp_encode_command(
char *buf,
size_t cap,
const char *
const *args,
const size_t *arg_lens,
size_t argc)
47 if (!buf || cap == 0 || !args || argc == 0)
52 if (!put_len_prefix(buf, cap, &pos,
'*', argc))
57 for (
size_t i = 0; i < argc; i++)
63 size_t alen = arg_lens ? arg_lens[i] : strnlen(args[i], cap);
64 if (!put_len_prefix(buf, cap, &pos,
'$', alen))
68 if (pos + alen + 2 >= cap)
72 memcpy(buf + pos, args[i], alen);
83static size_t find_crlf(
const uint8_t *buf,
size_t len,
size_t from)
85 for (
size_t i = from; i + 1 < len; i++)
87 if (buf[i] ==
'\r' && buf[i + 1] ==
'\n')
96static bool parse_int(
const uint8_t *buf,
size_t from,
size_t end, int64_t *out)
116 if (buf[i] <
'0' || buf[i] >
'9')
120 v = v * 10u + (uint64_t)(buf[i] -
'0');
122 *out = neg ? (int64_t)(0ULL - v) : (int64_t)v;
127static bool slice_ieq(
const uint8_t *buf,
size_t from,
size_t end,
const char *s)
129 for (
size_t i = from; i < end; i++, s++)
136 if (a >=
'A' && a <=
'Z')
138 a = (uint8_t)(a + 32);
141 if (b >=
'A' && b <=
'Z')
157static bool parse_double_special(
const uint8_t *buf,
size_t from,
size_t end,
double *out)
159 if (slice_ieq(buf, from, end,
"inf") || slice_ieq(buf, from, end,
"+inf"))
164 if (slice_ieq(buf, from, end,
"-inf"))
166 *out = -1e308 * 10.0;
169 if (slice_ieq(buf, from, end,
"nan"))
171 double inf = 1e308 * 10.0;
180static bool parse_exponent(
const uint8_t *buf,
size_t *i,
size_t end,
int *exp)
183 if (!(*i < end && (buf[*i] ==
'e' || buf[*i] ==
'E')))
189 if (*i < end && (buf[*i] ==
'+' || buf[*i] ==
'-'))
191 eneg = (buf[*i] ==
'-');
195 while (*i < end && buf[*i] >=
'0' && buf[*i] <=
'9')
199 *exp = *exp * 10 + (buf[*i] -
'0');
217static bool parse_double(
const uint8_t *buf,
size_t from,
size_t end,
double *out)
219 if (parse_double_special(buf, from, end, out))
226 if (i < end && (buf[i] ==
'+' || buf[i] ==
'-'))
228 neg = (buf[i] ==
'-');
233 for (; i < end && buf[i] >=
'0' && buf[i] <=
'9'; i++)
235 mant = mant * 10.0 + (buf[i] -
'0');
238 if (i < end && buf[i] ==
'.')
242 for (; i < end && buf[i] >=
'0' && buf[i] <=
'9'; i++)
244 mant += (buf[i] -
'0') * scale;
254 if (!parse_exponent(buf, &i, end, &exp))
263 int e = exp < 0 ? -exp : exp;
264 for (
int k = 0; k < e; k++)
268 mant = (exp < 0) ? (mant / scale) : (mant * scale);
269 *out = neg ? -mant : mant;
275static bool parse_bulk_body(
const uint8_t *buf,
size_t len, uint8_t type,
size_t header_from,
size_t header_to,
276 size_t after_header, RespReply *out,
size_t *consumed)
279 if (!parse_int(buf, header_from, header_to, &blen))
283 if (type ==
'$' && blen < 0)
285 out->type = RespType::RESP_NIL;
286 *consumed = after_header;
295 if (after_header + 2 > len || (uint64_t)blen > (uint64_t)(len - after_header - 2))
299 size_t need = after_header + (size_t)blen + 2;
300 if (buf[after_header + (
size_t)blen] !=
'\r' || buf[after_header + (size_t)blen + 1] !=
'\n')
306 out->type = RespType::RESP_BULK;
308 else if (type ==
'!')
310 out->type = RespType::RESP_BULK_ERROR;
314 out->type = RespType::RESP_VERBATIM;
316 out->str = (
const char *)(buf + after_header);
317 out->str_len = (size_t)blen;
324static bool parse_aggregate(
const uint8_t *buf, uint8_t type,
size_t header_from,
size_t header_to,
size_t after_header,
325 RespReply *out,
size_t *consumed)
328 if (!parse_int(buf, header_from, header_to, &n))
332 if (type ==
'*' && n < 0)
334 out->type = RespType::RESP_NIL;
335 *consumed = after_header;
344 out->type = RespType::RESP_ARRAY;
346 else if (type ==
'~')
348 out->type = RespType::RESP_SET;
352 out->type = RespType::RESP_PUSH;
356 *consumed = after_header;
360bool pc_resp_parse(
const uint8_t *buf,
size_t len, RespReply *out,
size_t *consumed)
362 if (!buf || len < 3 || !out || !consumed)
367 size_t crlf = find_crlf(buf, len, 1);
372 size_t header_from = 1;
373 size_t header_to = crlf;
374 size_t after_header = crlf + 2;
386 out->type = (buf[0] ==
'+') ? RespType::RESP_SIMPLE : RespType::RESP_ERROR;
387 out->str = (
const char *)(buf + header_from);
388 out->str_len = header_to - header_from;
389 *consumed = after_header;
394 if (!parse_int(buf, header_from, header_to, &v))
398 out->type = RespType::RESP_INTEGER;
400 *consumed = after_header;
408 return parse_bulk_body(buf, len, buf[0], header_from, header_to, after_header, out, consumed);
414 return parse_aggregate(buf, buf[0], header_from, header_to, after_header, out, consumed);
418 if (!parse_int(buf, header_from, header_to, &n) || n < 0)
422 out->type = RespType::RESP_MAP;
425 *consumed = after_header;
430 out->type = RespType::RESP_NIL;
431 *consumed = after_header;
435 if (header_to - header_from != 1 || (buf[header_from] !=
't' && buf[header_from] !=
'f'))
439 out->type = RespType::RESP_BOOL;
440 out->ival = (buf[header_from] ==
't') ? 1 : 0;
441 *consumed = after_header;
446 out->type = RespType::RESP_DOUBLE;
447 out->str = (
const char *)(buf + header_from);
448 out->str_len = header_to - header_from;
449 parse_double(buf, header_from, header_to, &out->dval);
450 *consumed = after_header;
454 out->type = RespType::RESP_BIG_NUMBER;
455 out->str = (
const char *)(buf + header_from);
456 out->str_len = header_to - header_from;
457 *consumed = after_header;
Redis RESP2/RESP3 wire codec (PC_ENABLE_REDIS) - zero-heap command encoder + reply parser,...