diff --git a/src/http/middleware.zig b/src/http/middleware.zig index f4b4630..ddb88c3 100644 --- a/src/http/middleware.zig +++ b/src/http/middleware.zig @@ -20,6 +20,8 @@ const urlencode = @import("./urlencode.zig"); const json_utils = @import("./json.zig"); const fields = @import("./fields.zig"); +const PathIter = util.PathIter; + /// Takes an iterable of middlewares and chains them together. pub fn apply(middlewares: anytype) Apply(@TypeOf(middlewares)) { return applyInternal(middlewares, std.meta.fields(@TypeOf(middlewares))); @@ -350,58 +352,6 @@ pub fn router(routes: anytype) Router(@TypeOf(routes)) { return Router(@TypeOf(routes)){ .routes = routes }; } -pub const PathIter = struct { - is_first: bool, - iter: std.mem.SplitIterator(u8), - - pub fn from(path: []const u8) PathIter { - return .{ .is_first = true, .iter = std.mem.split(u8, path, "/") }; - } - - pub fn next(self: *PathIter) ?[]const u8 { - defer self.is_first = false; - while (self.iter.next()) |it| if (it.len != 0) { - return it; - }; - - if (self.is_first) return self.iter.rest(); - - return null; - } - - pub fn first(self: *PathIter) []const u8 { - std.debug.assert(self.is_first); - return self.next().?; - } - - pub fn rest(self: *PathIter) []const u8 { - return self.iter.rest(); - } -}; - -test "PathIter" { - const testCase = struct { - fn case(path: []const u8, segments: []const []const u8) !void { - var iter = PathIter.from(path); - for (segments) |s| { - try std.testing.expectEqualStrings(s, iter.next() orelse return error.TestExpectedEqual); - } - try std.testing.expect(iter.next() == null); - } - }.case; - - try testCase("", &.{""}); - try testCase("*", &.{"*"}); - try testCase("/", &.{""}); - try testCase("/ab/cd", &.{ "ab", "cd" }); - try testCase("/ab/cd/", &.{ "ab", "cd" }); - try testCase("/ab/cd//", &.{ "ab", "cd" }); - try testCase("ab", &.{"ab"}); - try testCase("/ab", &.{"ab"}); - try testCase("ab/", &.{"ab"}); - try testCase("ab//ab//", &.{ "ab", "ab" }); -} - // helper function for doing route analysis fn pathMatches(route: []const u8, path: []const u8) bool { var path_iter = PathIter.from(path); diff --git a/src/util/lib.zig b/src/util/lib.zig index 02bde83..2780330 100644 --- a/src/util/lib.zig +++ b/src/util/lib.zig @@ -219,6 +219,58 @@ pub fn comptimeToCrlf(comptime str: []const u8) []const u8 { } } +pub const PathIter = struct { + is_first: bool, + iter: std.mem.SplitIterator(u8), + + pub fn from(path: []const u8) PathIter { + return .{ .is_first = true, .iter = std.mem.split(u8, path, "/") }; + } + + pub fn next(self: *PathIter) ?[]const u8 { + defer self.is_first = false; + while (self.iter.next()) |it| if (it.len != 0) { + return it; + }; + + if (self.is_first) return self.iter.rest(); + + return null; + } + + pub fn first(self: *PathIter) []const u8 { + std.debug.assert(self.is_first); + return self.next().?; + } + + pub fn rest(self: *PathIter) []const u8 { + return self.iter.rest(); + } +}; + +test "PathIter" { + const testCase = struct { + fn case(path: []const u8, segments: []const []const u8) !void { + var iter = PathIter.from(path); + for (segments) |s| { + try std.testing.expectEqualStrings(s, iter.next() orelse return error.TestExpectedEqual); + } + try std.testing.expect(iter.next() == null); + } + }.case; + + try testCase("", &.{""}); + try testCase("*", &.{"*"}); + try testCase("/", &.{""}); + try testCase("/ab/cd", &.{ "ab", "cd" }); + try testCase("/ab/cd/", &.{ "ab", "cd" }); + try testCase("/ab/cd//", &.{ "ab", "cd" }); + try testCase("ab", &.{"ab"}); + try testCase("/ab", &.{"ab"}); + try testCase("ab/", &.{"ab"}); + try testCase("ab//ab//", &.{ "ab", "ab" }); +} + pub const testing = struct { pub fn expectDeepEqual(expected: anytype, actual: @TypeOf(expected)) !void { const T = @TypeOf(expected);