feat: std.http handler carries an opaque ctx word (PLAN-HTTPZ A1 prep)

Server.init(cfg, handler, ctx); the handler signature gains a usize
third argument delivered verbatim per dispatch — typically a pointer
to the app's own state, since the server owns the call site. A bare
(req, resp) handler had no way to reach app state without globals.
examples/1633 pins the round trip.
This commit is contained in:
agra
2026-06-12 21:22:42 +03:00
parent 721793b4bf
commit 3a97019aa7
39 changed files with 10032 additions and 9872 deletions

View File

@@ -145,9 +145,13 @@ Server :: struct {
lfd: i32 = -1;
conns: [*]Conn = null;
own_alloc: Allocator;
handler: (*Request, *Response) -> void;
// The handler's third argument is `ctx`, an opaque word the app
// gave init — typically a pointer to its own state (store handle,
// config), since the server owns the call site.
handler: (*Request, *Response, usize) -> void;
ctx: usize = 0;
init :: (cfg: Config, handler: (*Request, *Response) -> void) -> (Server, !HttpErr) {
init :: (cfg: Config, handler: (*Request, *Response, usize) -> void, ctx: usize) -> (Server, !HttpErr) {
lfd := socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
if lfd < 0 { raise error.Bind; }
one : i32 = 1;
@@ -175,7 +179,7 @@ Server :: struct {
}
return Server.{
cfg = cfg, loop = lp, lfd = lfd, conns = slots,
own_alloc = oa, handler = handler,
own_alloc = oa, handler = handler, ctx = ctx,
};
}
@@ -401,7 +405,7 @@ Server :: struct {
// be parsed as a dot-call on a function named `handler`)
h := self.handler;
resp : Response = .{};
h(@req, @resp);
h(@req, @resp, self.ctx);
c.served += 1;
keep := req.keep_alive and c.served < self.cfg.request_count;