aboutsummaryrefslogtreecommitdiff
path: root/src/http/Parameter.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/http/Parameter.zig')
-rw-r--r--src/http/Parameter.zig71
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));
+}