reduce boilerplate in main-lib
This commit is contained in:
parent
30edcdfb6a
commit
31bece93fc
|
@ -26,8 +26,8 @@ pub const Request = extern struct {
|
||||||
headers_len: usize,
|
headers_len: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn toHeaders(allocator: std.mem.Allocator, headers: std.StringHashMap([]const u8)) ![*]Header {
|
pub fn toHeaders(alloc: std.mem.Allocator, headers: std.StringHashMap([]const u8)) ![*]Header {
|
||||||
var header_array = try std.ArrayList(Header).initCapacity(allocator, headers.count());
|
var header_array = try std.ArrayList(Header).initCapacity(alloc, headers.count());
|
||||||
var iterator = headers.iterator();
|
var iterator = headers.iterator();
|
||||||
while (iterator.next()) |kv| {
|
while (iterator.next()) |kv| {
|
||||||
header_array.appendAssumeCapacity(.{
|
header_array.appendAssumeCapacity(.{
|
||||||
|
@ -40,3 +40,59 @@ pub fn toHeaders(allocator: std.mem.Allocator, headers: std.StringHashMap([]cons
|
||||||
}
|
}
|
||||||
return header_array.items.ptr;
|
return header_array.items.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var allocator: ?*std.mem.Allocator = null;
|
||||||
|
|
||||||
|
pub const ZigResponse = struct {
|
||||||
|
body: *std.ArrayList(u8),
|
||||||
|
headers: *std.StringHashMap([]const u8),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This function is optional and can be exported by zig libraries for
|
||||||
|
/// initialization. If exported, it will be called once in the beginning of
|
||||||
|
/// a request and will be provided a pointer to std.mem.Allocator, which is
|
||||||
|
/// useful for reusing the parent allocator
|
||||||
|
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;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.interface);
|
||||||
|
pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*Response {
|
||||||
|
// TODO: implement another library in C or Rust or something to show
|
||||||
|
// that anything using a C ABI can be successful
|
||||||
|
var alloc = if (allocator) |a| a.* else @panic("zigInit not called prior to handle_request. This is a coding error");
|
||||||
|
|
||||||
|
// setup response body
|
||||||
|
var response = std.ArrayList(u8).init(alloc);
|
||||||
|
|
||||||
|
// setup headers
|
||||||
|
var headers = std.StringHashMap([]const u8).init(alloc);
|
||||||
|
zigRequestHandler(alloc, request.*, .{
|
||||||
|
.body = &response,
|
||||||
|
.headers = &headers,
|
||||||
|
}) catch |e| {
|
||||||
|
log.err("Unexpected error processing request: {any}", .{e});
|
||||||
|
if (@errorReturnTrace()) |trace| {
|
||||||
|
std.debug.dumpStackTrace(trace.*);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
log.debug("response ptr: {*}", .{response.items.ptr});
|
||||||
|
// Marshall data back for handling by server
|
||||||
|
|
||||||
|
var rc = alloc.create(Response) catch @panic("OOM");
|
||||||
|
rc.ptr = response.items.ptr;
|
||||||
|
rc.len = response.items.len;
|
||||||
|
rc.headers = toHeaders(alloc, headers) catch |e| {
|
||||||
|
log.err("Unexpected error processing request: {any}", .{e});
|
||||||
|
if (@errorReturnTrace()) |trace| {
|
||||||
|
std.debug.dumpStackTrace(trace.*);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
rc.headers_len = headers.count();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
|
@ -4,61 +4,20 @@ const testing = std.testing;
|
||||||
|
|
||||||
const log = std.log.scoped(.@"main-lib");
|
const log = std.log.scoped(.@"main-lib");
|
||||||
|
|
||||||
var allocator: ?*std.mem.Allocator = null;
|
// request_deinit is an optional export and will be called a the end of the
|
||||||
const Response = struct {
|
// request. Useful for deallocating memory
|
||||||
body: *std.ArrayList(u8),
|
|
||||||
headers: *std.StringHashMap([]const u8),
|
|
||||||
};
|
|
||||||
|
|
||||||
/// This function is optional and can be exported by zig libraries for
|
|
||||||
/// initialization. If exported, it will be called once in the beginning of
|
|
||||||
/// a request and will be provided a pointer to std.mem.Allocator, which is
|
|
||||||
/// useful for reusing the parent allocator
|
|
||||||
export fn zigInit(parent_allocator: *anyopaque) void {
|
|
||||||
allocator = @ptrCast(*std.mem.Allocator, @alignCast(@alignOf(*std.mem.Allocator), parent_allocator));
|
|
||||||
}
|
|
||||||
export fn handle_request() ?*interface.Response {
|
|
||||||
// TODO: implement another library in C or Rust or something to show
|
|
||||||
// that anything using a C ABI can be successful
|
|
||||||
var alloc = if (allocator) |a| a.* else @panic("zigInit not called prior to handle_request. This is a coding error");
|
|
||||||
|
|
||||||
// setup response body
|
|
||||||
var response = std.ArrayList(u8).init(alloc);
|
|
||||||
|
|
||||||
// setup headers
|
|
||||||
var headers = std.StringHashMap([]const u8).init(alloc);
|
|
||||||
handleRequest(.{
|
|
||||||
.body = &response,
|
|
||||||
.headers = &headers,
|
|
||||||
}) catch |e| {
|
|
||||||
log.err("Unexpected error processing request: {any}", .{e});
|
|
||||||
if (@errorReturnTrace()) |trace| {
|
|
||||||
std.debug.dumpStackTrace(trace.*);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
log.debug("response ptr: {*}", .{response.items.ptr});
|
|
||||||
// Marshall data back for handling by server
|
|
||||||
|
|
||||||
var rc = alloc.create(interface.Response) catch @panic("OOM");
|
|
||||||
rc.ptr = response.items.ptr;
|
|
||||||
rc.len = response.items.len;
|
|
||||||
rc.headers = interface.toHeaders(alloc, headers) catch |e| {
|
|
||||||
log.err("Unexpected error processing request: {any}", .{e});
|
|
||||||
if (@errorReturnTrace()) |trace| {
|
|
||||||
std.debug.dumpStackTrace(trace.*);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
rc.headers_len = headers.count();
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// request_deinit is an optional export and will be called a the end of the
|
|
||||||
/// request. Useful for deallocating memory
|
|
||||||
// export fn request_deinit() void {
|
// export fn request_deinit() void {
|
||||||
// }
|
// }
|
||||||
|
export fn handle_request(request: *interface.Request) callconv(.C) ?*interface.Response {
|
||||||
|
return interface.handleRequest(request, handleRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
@export(
|
||||||
|
interface.zigInit,
|
||||||
|
.{ .name = "zigInit", .linkage = .Strong },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ************************************************************************
|
// ************************************************************************
|
||||||
// Boilerplate ^^, Custom code vv
|
// Boilerplate ^^, Custom code vv
|
||||||
|
@ -66,11 +25,12 @@ export fn handle_request() ?*interface.Response {
|
||||||
//
|
//
|
||||||
// handleRequest function here is the last line of boilerplate and the
|
// handleRequest function here is the last line of boilerplate and the
|
||||||
// entry to a request
|
// entry to a request
|
||||||
fn handleRequest(response: Response) !void {
|
fn handleRequest(allocator: std.mem.Allocator, request: interface.Request, response: interface.ZigResponse) !void {
|
||||||
|
_ = allocator;
|
||||||
// setup
|
// setup
|
||||||
var response_writer = response.body.writer();
|
var response_writer = response.body.writer();
|
||||||
// real work
|
// real work
|
||||||
response_writer.print(" 2.", .{}) catch unreachable;
|
response_writer.print(" {d}", .{request.headers_len}) catch unreachable;
|
||||||
try response.headers.put("X-custom-foo", "bar");
|
try response.headers.put("X-custom-foo", "bar");
|
||||||
log.info("handlerequest header count {d}", .{response.headers.count()});
|
log.info("handlerequest header count {d}", .{response.headers.count()});
|
||||||
}
|
}
|
||||||
|
@ -79,9 +39,23 @@ test "handle_request" {
|
||||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
var aa = arena.allocator();
|
var aa = arena.allocator();
|
||||||
allocator = &aa;
|
interface.zigInit(&aa);
|
||||||
const response = handle_request().?;
|
var headers: []interface.Header = @constCast(&[_]interface.Header{.{
|
||||||
try testing.expectEqualStrings(" 2.", response.ptr[0..response.len]);
|
.name_ptr = @ptrCast([*:0]u8, @constCast("GET".ptr)),
|
||||||
|
.name_len = 3,
|
||||||
|
.value_ptr = @ptrCast([*:0]u8, @constCast("GET".ptr)),
|
||||||
|
.value_len = 3,
|
||||||
|
}});
|
||||||
|
var req = interface.Request{
|
||||||
|
.method = @ptrCast([*:0]u8, @constCast("GET".ptr)),
|
||||||
|
.method_len = 3,
|
||||||
|
.content = @ptrCast([*:0]u8, @constCast("GET".ptr)),
|
||||||
|
.content_len = 3,
|
||||||
|
.headers = headers.ptr,
|
||||||
|
.headers_len = 1,
|
||||||
|
};
|
||||||
|
const response = handle_request(&req).?;
|
||||||
|
try testing.expectEqualStrings(" 1", response.ptr[0..response.len]);
|
||||||
try testing.expectEqualStrings("X-custom-foo", response.headers[0].name_ptr[0..response.headers[0].name_len]);
|
try testing.expectEqualStrings("X-custom-foo", response.headers[0].name_ptr[0..response.headers[0].name_len]);
|
||||||
try testing.expectEqualStrings("bar", response.headers[0].value_ptr[0..response.headers[0].value_len]);
|
try testing.expectEqualStrings("bar", response.headers[0].value_ptr[0..response.headers[0].value_len]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -477,6 +477,6 @@ test "root path get" {
|
||||||
std.testing.log_level = .debug;
|
std.testing.log_level = .debug;
|
||||||
log.debug("", .{});
|
log.debug("", .{});
|
||||||
try testGet("/");
|
try testGet("/");
|
||||||
try std.testing.expectEqual(@as(usize, 3), test_resp_buf_len);
|
try std.testing.expectEqual(@as(usize, 2), test_resp_buf_len);
|
||||||
try std.testing.expectEqualStrings(" 2.", test_resp_buf[0..test_resp_buf_len]);
|
try std.testing.expectEqualStrings(" 1", test_resp_buf[0..test_resp_buf_len]);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user