typedef struct { const char *p; size_t len; } ioxd_slice;
A slice: pointer + length, the C span. Not NUL-terminated.
ioxd/slice.h - a slice, bytes with a length, and a key/value pair of them: what every request carries. Compare and convert them without copying; parse a query string or a form body.
#include <ioxd.h> typedef struct { const char *p; size_t len; } ioxd_slice; typedef struct { ioxd_slice key, value; } ioxd_kv; bool ioxd_slice_eq (ioxd_slice s, const char *cstr); bool ioxd_slice_eq_ci (ioxd_slice s, const char *cstr); bool ioxd_slice_starts_with(ioxd_slice s, const char *prefix); bool ioxd_slice_ends_with (ioxd_slice s, const char *suffix); ioxd_slice ioxd_slice_trim (ioxd_slice s); bool ioxd_cstr(ioxd_slice s, char *buf, size_t cap); bool ioxd_to_int (ioxd_slice s, int *out); bool ioxd_to_i64 (ioxd_slice s, int64_t *out); bool ioxd_to_u64 (ioxd_slice s, uint64_t *out); bool ioxd_to_double(ioxd_slice s, double *out); bool ioxd_to_bool (ioxd_slice s, bool *out); size_t ioxd_kv_parse(const char *text, size_t len, ioxd_kv *out, size_t cap, char *arena, size_t arena_cap, bool *truncated);
typedef struct { const char *p; size_t len; } ioxd_slice;
A slice: pointer + length, the C span. Not NUL-terminated.
typedef struct { ioxd_slice key, value; } ioxd_kv;
One key/value pair of slices: a header, a query parameter, a route parameter.
bool ioxd_slice_eq (ioxd_slice s, const char *cstr); bool ioxd_slice_eq_ci (ioxd_slice s, const char *cstr); bool ioxd_slice_starts_with(ioxd_slice s, const char *prefix); bool ioxd_slice_ends_with (ioxd_slice s, const char *suffix); ioxd_slice ioxd_slice_trim (ioxd_slice s);
Everything a request carries is a slice: bytes with a length, not NUL-terminated, valid until the handler returns. These compare and convert one without copying it.
bool ioxd_cstr(ioxd_slice s, char *buf, size_t cap);
A NUL-terminated copy in buf, for whatever wants a C string. False when it did not fit: buf then holds what fit, still terminated (cap 0 writes nothing) - and false when the slice holds a NUL of its own, which would end the C string early ("secret.txt%00.png" is not a PNG).
bool ioxd_to_int (ioxd_slice s, int *out); bool ioxd_to_i64 (ioxd_slice s, int64_t *out); bool ioxd_to_u64 (ioxd_slice s, uint64_t *out); bool ioxd_to_double(ioxd_slice s, double *out); bool ioxd_to_bool (ioxd_slice s, bool *out);
Conversions. The whole slice must be the value - nothing around it, nothing after it - and a number that does not fit the type fails. On failure *out is left alone and false comes back, so "0" and "not a number" cannot be confused. Integers: an optional '-' and decimal digits. Doubles: also a fraction and an exponent ("2.5", ".5", "1e-3"); never inf, nan or hex; too large fails, too small rounds towards zero. Booleans: true/false, 1/0, yes/no, on/off, any case.
size_t ioxd_kv_parse(const char *text, size_t len, ioxd_kv *out, size_t cap, char *arena, size_t arena_cap, bool *truncated);
Parse "k=v&k2=v2" - a query string, a form body - into out, up to cap pairs. Keys and values that need it ('+', %XX) are decoded into arena and point there; the rest are views of s. A malformed %XX and %00 stay as written. Returns the pair count; *truncated (may be NULL) is set when a pair was left out - past cap, or not fitting the arena - so the caller can refuse the request rather than act on part of it. Every pair is returned, duplicates included, in order: pick a policy (first or last) and keep to it.
Strict conversions: the whole slice is the value, or the call fails and *out is untouched:
int64_t id; double price; bool on; if (!ioxd_to_i64(ctx->req.route_params[0].value, &id)) /* "42", "-7"; not "42x", not " 42" */ ... if (ioxd_to_double(v, &price) && ioxd_to_bool(w, &on)) /* "2.5", "1e-3"; "yes", "off" */ ...
A form body parsed like a query string:
ioxd_slice body = ioxd_body_all(ctx); ioxd_kv form[8]; char arena[512]; bool truncated; size_t n = ioxd_kv_parse(body.p, body.len, form, 8, arena, sizeof arena, &truncated); if (truncated) { ctx->res.status = 400; return; } /* never act on part of it */ for (size_t i = 0; i < n; i++) if (ioxd_slice_eq(form[i].key, "name")) ioxd_printf(ctx, "hello %.*s\n", (int)form[i].value.len, form[i].value.p);
ioxd_config(3), ioxd_http(3), ioxd_router(3), ioxd_json(3), ioxd_pipe(3), ioxd_tls(3), ioxd_examples(7), ioxd(7)