aboutsummaryrefslogtreecommitdiff
path: root/src/routes/root.zig
blob: c43889343e722b07ffa51a383acd0cf0fa12e10b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const std = @import("std");

pub const HandlerInfo = @import("handler-info.zig");

pub const api = @import("api/root.zig");
pub const static: HandlerInfo = .from_type(@import("static.zig"));

const routes = (Routes {})
    .with("", static)
    .with_module("/api", api);

pub const handlers = std.StaticStringMap(HandlerInfo).initComptime(routes.items);

pub fn get(path: []const u8) HandlerInfo {
    return (handlers.getLongestPrefix(std.mem.trimEnd(u8, path, "/")) orelse unreachable).value;
}

const Routes = struct {
    const Self = @This();

    const Route = struct{ []const u8, HandlerInfo };

    items: []const Route = &[0]Route{},

    pub fn with(self: Self, comptime route: []const u8, handler: HandlerInfo) Self {
        var next = self;
        const tail: []const Route = &[1]Route { .{ route, handler } };
        next.items = self.items ++ tail;
        return next;
    }

    pub fn with_module(self: Self, comptime prefix: []const u8, module: type) Self {
        var next = self;

        if (@typeInfo(module) != .@"struct") return self;

        inline for (@typeInfo(module).@"struct".decls) |decl| {
            const field = @field(module, decl.name);
            const route = prefix ++ "/" ++ decl.name;
            switch (@TypeOf(field)) {
                type => next = next.with_module(route, field),
                HandlerInfo => next = next.with(route, field),
                else => {},
            }
        }

        return next;
    }
};