diff options
Diffstat (limited to 'src/http/Parameter.zig')
| -rw-r--r-- | src/http/Parameter.zig | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/http/Parameter.zig b/src/http/Parameter.zig new file mode 100644 index 0000000..03260b2 --- /dev/null +++ b/src/http/Parameter.zig @@ -0,0 +1,71 @@ +const std = @import("std"); +const Route = @import("Route.zig"); + +repr: []const u8, + +pub fn as(self: @This(), T: type) (if (T == []const u8) T else anyerror!T) { + if (T == []const u8) { + return self.repr; + } else if (@typeInfo(T) == .int) { + return std.fmt.parseInt(T, self.repr, 10); + } + + @compileError(std.fmt.comptimePrint("unsupported default type '{}'", .{T})); +} + +pub fn convert(self: @This(), func: anytype) (@typeInfo(@TypeOf(func)).@"fn".return_type orelse void) { + return func(self.repr); +} + +pub fn Struct(comptime route: Route) type { + var names: []const []const u8 = &.{}; + + inline for (route.segments) |segment| { + switch (segment) { + .literal => {}, + .identifier => |id| { + const name: []const []const u8 = &.{id}; + names = names ++ name; + }, + } + } + + var types: [names.len]type = undefined; + var attrs: [names.len]std.builtin.Type.StructField.Attributes = undefined; + + @memset(&types, @This()); + @memset(&attrs, std.builtin.Type.StructField.Attributes{}); + + return @Struct(.auto, null, names, &types, &attrs); +} + +pub fn parse(P: type, comptime route: *const Route, url: []const u8) P { + var params: P = undefined; + var buffer = url; + + inline for (route.segments) |segment| { + buffer = std.mem.trimStart(u8, buffer, "/"); + const index = std.mem.indexOfScalar(u8, buffer, '/') orelse buffer.len; + const value = buffer[0..index]; + buffer = buffer[index..]; + + switch (segment) { + .literal => {}, + .identifier => |id| { + @field(params, id) = .{ .repr = value }; + }, + } + } + + return params; +} + +test "parse" { + const route: Route = comptime .fromAny(.{ "api", "users", .name, "settings", .id }); + const Params = Struct(route); + const url = "/api/users/nathan.reiner/settings/123456789"; + + const params = parse(Params, &route, url); + try std.testing.expectEqualStrings("nathan.reiner", params.name.as([]const u8)); + try std.testing.expectEqual(123456789, try params.id.as(usize)); +} |