From 943590ae463ef78bc096afbeaeb269b3a1bc08e7 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 21 Dec 2025 19:09:31 +1030 Subject: [PATCH 1/7] Port to .16 Io interface --- build.zig.zon | 2 +- demo/url_buffer.zig | 8 ++++---- src/event/url.zig | 8 ++++---- src/runtime/api.zig | 2 +- src/runtime/handle.zig | 4 ++-- src/runtime/serve.zig | 8 ++++---- src/utils/Http.zig | 18 +++++++++++------- src/utils/environ.zig | 2 +- 8 files changed, 28 insertions(+), 24 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 3fcf39a..d2d6e1d 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,7 +3,7 @@ .version = "0.4.0", .fingerprint = 0xdc70f8287a69c300, - .minimum_zig_version = "0.15.0", + .minimum_zig_version = "0.16.0-dev.1484+d0ba6642b", .dependencies = .{}, diff --git a/demo/url_buffer.zig b/demo/url_buffer.zig index e338fc8..de41980 100644 --- a/demo/url_buffer.zig +++ b/demo/url_buffer.zig @@ -90,7 +90,7 @@ fn homePage(ctx: lambda.Context) ![]const u8 { /// The `url.Request` contains both the HTTP request and additional AWS metadata. fn ipAddrPage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { // Generate dynamic HTML content, note the usage of an arena allocator. - var html: std.io.Writer.Allocating = .init(ctx.arena); + var html: std.Io.Writer.Allocating = .init(ctx.arena); try html.writer.writeAll(global_nav); if (req.request_context.http.source_ip) |addr| { @@ -110,7 +110,7 @@ fn ipAddrPage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { /// Use a parsed query parameter provided by the decoded request to greet the user. fn greetPage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { - var html: std.io.Writer.Allocating = .init(ctx.arena); + var html: std.Io.Writer.Allocating = .init(ctx.arena); try html.writer.writeAll(global_nav); @@ -165,7 +165,7 @@ fn storagePage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { } // Encode the cookie value - var new_cookie: std.io.Writer.Allocating = .init(ctx.arena); + var new_cookie: std.Io.Writer.Allocating = .init(ctx.arena); errdefer new_cookie.deinit(); try new_cookie.writer.writeAll("store="); try std.base64.standard.Encoder.encodeWriter(&new_cookie.writer, value); @@ -176,7 +176,7 @@ fn storagePage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { } // Render a form to display and update the stored value. - var html: std.io.Writer.Allocating = .init(ctx.arena); + var html: std.Io.Writer.Allocating = .init(ctx.arena); try html.writer.writeAll(global_nav); try html.writer.print( \\
diff --git a/src/event/url.zig b/src/event/url.zig index eb0b7b7..36e5df5 100644 --- a/src/event/url.zig +++ b/src/event/url.zig @@ -46,7 +46,7 @@ pub const Response = struct { pub const internal_server_error = "{\"statusCode\":500,body:\"Internal Server Error\"}"; pub fn encode(self: Response, gpa: Allocator) ![]const u8 { - var buffer: std.io.Writer.Allocating = .init(gpa); + var buffer: std.Io.Writer.Allocating = .init(gpa); errdefer buffer.deinit(); try buffer.writer.writeByte('{'); @@ -156,7 +156,7 @@ test Response { /// .body = .{ .textual = "

Incoming...

" }, /// }); /// ``` -pub fn openStream(ctx: hdl.Context, stream: hdl.Stream, response: Response) !*std.io.Writer { +pub fn openStream(ctx: hdl.Context, stream: hdl.Stream, response: Response) !*std.Io.Writer { // https://github.com/awslabs/aws-lambda-rust-runtime/blob/main/lambda-runtime/src/requests.rs // https://aws.amazon.com/blogs/compute/using-response-streaming-with-aws-lambda-web-adapter-to-optimize-performance const writer = try stream.openPrint(INTEGRATION_CONTENT_TYPE, "{f}", .{StreamingResponse{ @@ -183,12 +183,12 @@ const StreamingResponse = struct { arena: Allocator, response: Response, - pub fn format(self: @This(), writer: *std.io.Writer) !void { + pub fn format(self: @This(), writer: *std.Io.Writer) !void { var response = self.response; response.body = .{ .textual = "" }; const prelude = response.encode(self.arena) catch { - return std.io.Writer.Error.WriteFailed; + return std.Io.Writer.Error.WriteFailed; }; try writer.writeAll(prelude); } diff --git a/src/runtime/api.zig b/src/runtime/api.zig index b12ea34..167e6a7 100644 --- a/src/runtime/api.zig +++ b/src/runtime/api.zig @@ -205,7 +205,7 @@ fn sendRequest(arena: Allocator, client: *Client, path: []const u8, payload: ?[] } fn formatError(arena: Allocator, err_category: []const u8, err: ErrorRequest) ![]const u8 { - var buffer: std.io.Writer.Allocating = .init(arena); + var buffer: std.Io.Writer.Allocating = .init(arena); try buffer.writer.print( \\{{"errorType":"{s}. diff --git a/src/runtime/handle.zig b/src/runtime/handle.zig index 82a3318..34368f6 100644 --- a/src/runtime/handle.zig +++ b/src/runtime/handle.zig @@ -98,7 +98,7 @@ pub const Stream = struct { }; /// Start streaming a response of a specified content type. - pub fn open(self: @This(), content_type: []const u8) !*std.io.Writer { + pub fn open(self: @This(), content_type: []const u8) !*std.Io.Writer { return self.openPrint(content_type, "", {}); } @@ -111,7 +111,7 @@ pub const Stream = struct { content_type: []const u8, comptime prelude_fmt: []const u8, prelude_args: anytype, - ) !*std.io.Writer { + ) !*std.Io.Writer { if (self.state.* != .pending) return error.ReopeningStream; std.debug.assert(content_type.len > 0); diff --git a/src/runtime/serve.zig b/src/runtime/serve.zig index 76450e1..43316a1 100644 --- a/src/runtime/serve.zig +++ b/src/runtime/serve.zig @@ -48,7 +48,7 @@ pub const Server = struct { return initFailed(arena_alloc, null, error.MissingRuntimeOrigin, "Missing the runtime’s API origin URL"); }; - self.http = HttpClient.init(gpa_alloc, api_origin) catch |err| { + HttpClient.init(&self.http, gpa_alloc, api_origin) catch |err| { return initFailed(arena_alloc, null, err, "Creating a HTTP client failed"); }; } @@ -134,8 +134,8 @@ pub const Server = struct { } pub fn respondFailure(self: *Server, err: anyerror, trace: ?*std.builtin.StackTrace) !void { - if (trace) |t| { - log.err("The handler returned an error `{s}`.{f}", .{ @errorName(err), t }); + if (trace) |_| { + log.err("The handler returned an error `{s}`.", .{@errorName(err)}); } else { log.err("The handler returned an error `{s}`.", .{@errorName(err)}); } @@ -203,7 +203,7 @@ pub const Server = struct { body: std.http.BodyWriter, arena: std.mem.Allocator, - pub fn writer(self: *Stream) *std.io.Writer { + pub fn writer(self: *Stream) *std.Io.Writer { return &self.body.writer; } diff --git a/src/utils/Http.zig b/src/utils/Http.zig index f60e2b2..44a0a01 100644 --- a/src/utils/Http.zig +++ b/src/utils/Http.zig @@ -2,6 +2,7 @@ const std = @import("std"); const testing = std.testing; const Client = std.http.Client; +const Threaded = std.Io.Threaded; const Allocator = std.mem.Allocator; const builtin = @import("builtin"); const package_version = @import("meta.zig").package_version; @@ -17,12 +18,13 @@ const USER_AGENT = std.fmt.comptimePrint( .{ package_version, builtin.zig_version_string }, ); +threaded: Threaded, client: Client, uri: std.Uri, -pub fn init(gpa: Allocator, origin: []const u8) !Self { +pub fn init(self: *Self, gpa: Allocator, origin: []const u8) !void { const idx = std.mem.indexOfScalar(u8, origin, ':'); - const uri = std.Uri{ + self.uri = std.Uri{ .path = .{ .percent_encoded = "" }, .scheme = "http", .host = .{ .raw = if (idx) |i| origin[0..i] else origin }, @@ -32,14 +34,16 @@ pub fn init(gpa: Allocator, origin: []const u8) !Self { null, }; - return .{ - .client = Client{ .allocator = gpa }, - .uri = uri, - }; + self.threaded = Threaded.init(gpa); + errdefer self.threaded.deinit(); + + const io = self.threaded.io(); + self.client = Client{ .allocator = gpa, .io = io }; } pub fn deinit(self: *Self) void { self.client.deinit(); + self.threaded.deinit(); self.* = undefined; } @@ -137,7 +141,7 @@ fn parseResponse(arena: Allocator, res: *Client.Response) !Result { var transfer_buffer: [64]u8 = undefined; const reader = res.reader(&transfer_buffer); - var buffer: std.io.Writer.Allocating = .init(arena); + var buffer: std.Io.Writer.Allocating = .init(arena); _ = reader.streamRemaining(&buffer.writer) catch |err| switch (err) { error.ReadFailed => return res.bodyErr().?, else => |e| return e, diff --git a/src/utils/environ.zig b/src/utils/environ.zig index 62769da..891299b 100644 --- a/src/utils/environ.zig +++ b/src/utils/environ.zig @@ -21,5 +21,5 @@ fn parseAndPutVar(map: *std.process.EnvMap, line: [*]u8) !void { while (line[end_i] != 0) : (end_i += 1) {} const value = line[line_i + 1 .. end_i]; - try map.putMove(key, value); + try map.put(key, value); } From 31f6cd3afbebdf3bfd150d535ea09b726be07367 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 21 Dec 2025 20:54:47 +1030 Subject: [PATCH 2/7] Add Io field to context to access from handler --- src/runtime/context.zig | 2 +- src/runtime/serve.zig | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/context.zig b/src/runtime/context.zig index 1110c73..30fe7e5 100644 --- a/src/runtime/context.zig +++ b/src/runtime/context.zig @@ -19,7 +19,7 @@ pub const Context = struct { config: ConfigMeta = .{}, /// Request metadata of the invocation. request: RequestMeta = .{}, - + io: *const std.Io, _force_destroy: *bool, _kv: *const std.process.EnvMap = undefined, diff --git a/src/runtime/serve.zig b/src/runtime/serve.zig index 43316a1..55e5711 100644 --- a/src/runtime/serve.zig +++ b/src/runtime/serve.zig @@ -98,6 +98,7 @@ pub const Server = struct { .gpa = self.gpa.allocator(), .arena = self.arena.allocator(), ._force_destroy = &force_terminate, + .io = &self.http.threaded.io(), }; ctx.loadMeta(&context, &self.env); From 3ce568db1a9a1a5d2429903e3fc5864c14e518a4 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 22 Dec 2025 15:01:28 +1030 Subject: [PATCH 3/7] Update demo to use new Io --- demo/debug.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/debug.zig b/demo/debug.zig index eeda369..b55e44c 100644 --- a/demo/debug.zig +++ b/demo/debug.zig @@ -9,7 +9,7 @@ pub fn main() void { } fn handler(ctx: lambda.Context, event: []const u8) ![]const u8 { - var str: std.io.Writer.Allocating = try .initCapacity(ctx.arena, 1024); + var str: std.Io.Writer.Allocating = try .initCapacity(ctx.arena, 1024); const cfg = ctx.config; try str.writer.print( From f33b67d6015708dc0337e4bce622bb30a461ed18 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 22 Dec 2025 18:36:00 +1030 Subject: [PATCH 4/7] Store and initialize Io in Server --- src/runtime/serve.zig | 13 +++++++++++-- src/utils/Http.zig | 9 ++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/runtime/serve.zig b/src/runtime/serve.zig index 55e5711..09927a0 100644 --- a/src/runtime/serve.zig +++ b/src/runtime/serve.zig @@ -20,6 +20,8 @@ pub const Options = struct {}; pub const Server = struct { gpa: std.heap.GeneralPurposeAllocator(.{}), arena: std.heap.ArenaAllocator, + threaded: std.Io.Threaded, + io: std.Io, http: HttpClient, env: std.process.EnvMap, request_id: []const u8 = "", @@ -48,7 +50,13 @@ pub const Server = struct { return initFailed(arena_alloc, null, error.MissingRuntimeOrigin, "Missing the runtime’s API origin URL"); }; - HttpClient.init(&self.http, gpa_alloc, api_origin) catch |err| { + // Initialize threaded IO - owned by Server + self.threaded = std.Io.Threaded.init(gpa_alloc); + errdefer self.threaded.deinit(); + + self.io = self.threaded.io(); + + HttpClient.init(&self.http, gpa_alloc, api_origin, self.io) catch |err| { return initFailed(arena_alloc, null, err, "Creating a HTTP client failed"); }; } @@ -57,6 +65,7 @@ pub const Server = struct { self.http.deinit(); self.env.deinit(); self.arena.deinit(); + self.threaded.deinit(); switch (self.gpa.deinit()) { .ok => {}, @@ -98,7 +107,7 @@ pub const Server = struct { .gpa = self.gpa.allocator(), .arena = self.arena.allocator(), ._force_destroy = &force_terminate, - .io = &self.http.threaded.io(), + .io = &self.io, }; ctx.loadMeta(&context, &self.env); diff --git a/src/utils/Http.zig b/src/utils/Http.zig index 44a0a01..3895b07 100644 --- a/src/utils/Http.zig +++ b/src/utils/Http.zig @@ -2,6 +2,7 @@ const std = @import("std"); const testing = std.testing; const Client = std.http.Client; +const Io = std.Io; const Threaded = std.Io.Threaded; const Allocator = std.mem.Allocator; const builtin = @import("builtin"); @@ -18,11 +19,10 @@ const USER_AGENT = std.fmt.comptimePrint( .{ package_version, builtin.zig_version_string }, ); -threaded: Threaded, client: Client, uri: std.Uri, -pub fn init(self: *Self, gpa: Allocator, origin: []const u8) !void { +pub fn init(self: *Self, gpa: Allocator, origin: []const u8, io: Io) !void { const idx = std.mem.indexOfScalar(u8, origin, ':'); self.uri = std.Uri{ .path = .{ .percent_encoded = "" }, @@ -34,16 +34,11 @@ pub fn init(self: *Self, gpa: Allocator, origin: []const u8) !void { null, }; - self.threaded = Threaded.init(gpa); - errdefer self.threaded.deinit(); - - const io = self.threaded.io(); self.client = Client{ .allocator = gpa, .io = io }; } pub fn deinit(self: *Self) void { self.client.deinit(); - self.threaded.deinit(); self.* = undefined; } From 2261debf460d6faf3836d22270aa55b7c2c60ae6 Mon Sep 17 00:00:00 2001 From: frettedfeline Date: Sat, 3 Jan 2026 12:56:35 +1030 Subject: [PATCH 5/7] Update minimum zig --- build.zig.zon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig.zon b/build.zig.zon index d2d6e1d..09f70a0 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,7 +3,7 @@ .version = "0.4.0", .fingerprint = 0xdc70f8287a69c300, - .minimum_zig_version = "0.16.0-dev.1484+d0ba6642b", + .minimum_zig_version = "0.16.0-dev.1859+212968c57", .dependencies = .{}, From d82263fc2f2541371587e7e558a1449470d626f2 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 3 Jan 2026 19:43:07 +1030 Subject: [PATCH 6/7] Update threaded runtime initialiation --- src/runtime/serve.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/serve.zig b/src/runtime/serve.zig index 09927a0..5bac1ff 100644 --- a/src/runtime/serve.zig +++ b/src/runtime/serve.zig @@ -51,7 +51,7 @@ pub const Server = struct { }; // Initialize threaded IO - owned by Server - self.threaded = std.Io.Threaded.init(gpa_alloc); + self.threaded = std.Io.Threaded.init(gpa_alloc, .{}); errdefer self.threaded.deinit(); self.io = self.threaded.io(); From 9517539896943359e24d89167f8d398e83ee79df Mon Sep 17 00:00:00 2001 From: frettedfeline Date: Mon, 12 Jan 2026 19:38:35 +1030 Subject: [PATCH 7/7] Bump zig --- build.zig.zon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig.zon b/build.zig.zon index 09f70a0..de5eaae 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,7 +3,7 @@ .version = "0.4.0", .fingerprint = 0xdc70f8287a69c300, - .minimum_zig_version = "0.16.0-dev.1859+212968c57", + .minimum_zig_version = "0.16.0-dev.2145+ec25b1384", .dependencies = .{},