diff --git a/src/interface.zig b/src/interface.zig index 820c874..6893b4f 100644 --- a/src/interface.zig +++ b/src/interface.zig @@ -1,5 +1,6 @@ const std = @import("std"); +// C interfaces between main and libraries pub const Header = extern struct { name_ptr: [*]u8, name_len: usize, @@ -26,6 +27,13 @@ pub const Request = extern struct { headers_len: usize, }; +// If the library is Zig, we can use these helpers +pub const ZigRequest = struct { + method: [:0]u8, + content: []u8, + headers: []Header, +}; + pub fn toHeaders(alloc: std.mem.Allocator, headers: std.StringHashMap([]const u8)) ![*]Header { var header_array = try std.ArrayList(Header).initCapacity(alloc, headers.count()); var iterator = headers.iterator(); @@ -56,7 +64,7 @@ pub fn zigInit(parent_allocator: *anyopaque) callconv(.C) void { allocator = @ptrCast(*std.mem.Allocator, @alignCast(@alignOf(*std.mem.Allocator), parent_allocator)); } -pub const ZigRequestHandler = *const fn (std.mem.Allocator, Request, ZigResponse) anyerror!void; +pub const ZigRequestHandler = *const fn (std.mem.Allocator, ZigRequest, ZigResponse) anyerror!void; const log = std.log.scoped(.interface); pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*Response { @@ -69,10 +77,18 @@ pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?* // setup headers var headers = std.StringHashMap([]const u8).init(alloc); - zigRequestHandler(alloc, request.*, .{ - .body = &response, - .headers = &headers, - }) catch |e| { + zigRequestHandler( + alloc, + .{ + .method = request.method[0..request.method_len :0], + .content = request.content[0..request.content_len], + .headers = request.headers[0..request.headers_len], + }, + .{ + .body = &response, + .headers = &headers, + }, + ) catch |e| { log.err("Unexpected error processing request: {any}", .{e}); if (@errorReturnTrace()) |trace| { std.debug.dumpStackTrace(trace.*); diff --git a/src/main-lib.zig b/src/main-lib.zig index e2948c3..2d63bb6 100644 --- a/src/main-lib.zig +++ b/src/main-lib.zig @@ -8,10 +8,20 @@ const log = std.log.scoped(.@"main-lib"); // request. Useful for deallocating memory // export fn request_deinit() void { // } + +/// handle_request will be called on a single request, but due to the preservation +/// of restrictions imposed by the calling interface, it should generally be more +/// useful to call into the interface library to let it do the conversion work +/// on your behalf export fn handle_request(request: *interface.Request) callconv(.C) ?*interface.Response { return interface.handleRequest(request, handleRequest); } +// zigInit is an optional export called at the beginning of a request. It will +// be passed an allocator (which...shh...is an arena allocator). Since the +// interface library provides a request handler that requires a built-in allocator, +// if you are using the interface library, you will need to also include this +// export comptime { @export( interface.zigInit, @@ -25,12 +35,12 @@ comptime { // // handleRequest function here is the last line of boilerplate and the // entry to a request -fn handleRequest(allocator: std.mem.Allocator, request: interface.Request, response: interface.ZigResponse) !void { +fn handleRequest(allocator: std.mem.Allocator, request: interface.ZigRequest, response: interface.ZigResponse) !void { _ = allocator; // setup var response_writer = response.body.writer(); // real work - response_writer.print(" {d}", .{request.headers_len}) catch unreachable; + response_writer.print(" {d}", .{request.headers.len}) catch unreachable; try response.headers.put("X-custom-foo", "bar"); log.info("handlerequest header count {d}", .{response.headers.count()}); }