From d0e08e4b04570afb3ae550391f9e8e0e35f6859e Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Sat, 26 Nov 2022 23:28:00 -0800 Subject: [PATCH] Fix parsing for enum and boolean values --- src/http/query.zig | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/http/query.zig b/src/http/query.zig index 1933429..35438f5 100644 --- a/src/http/query.zig +++ b/src/http/query.zig @@ -66,10 +66,6 @@ const QueryIter = @import("util").QueryIter; /// Would be used to parse a query string like /// `?foo.baz=12345` /// -/// Compound types cannot currently be nullable, and must be structs. -/// -/// TODO: values are currently case-sensitive, and are not url-decoded properly. -/// This should be fixed. pub fn parseQuery(alloc: std.mem.Allocator, comptime T: type, query: []const u8) !T { if (comptime !std.meta.trait.isContainer(T)) @compileError("T must be a struct"); var iter = QueryIter.from(query); @@ -88,7 +84,7 @@ pub fn parseQuery(alloc: std.mem.Allocator, comptime T: type, query: []const u8) return (try parse(alloc, T, "", "", fields)) orelse error.NoQuery; } -fn decodeString(alloc: std.mem.Allocator, val: []const u8) ![]const u8 { +fn decodeString(alloc: std.mem.Allocator, val: []const u8) ![]u8 { var list = try std.ArrayList(u8).initCapacity(alloc, val.len); errdefer list.deinit(); @@ -266,20 +262,23 @@ fn parseQueryValueNotNull(alloc: std.mem.Allocator, comptime T: type, value: []c if (comptime std.meta.trait.isZigString(T)) return decoded; + defer alloc.free(decoded); + const result = if (comptime std.meta.trait.isIntegral(T)) try std.fmt.parseInt(T, decoded, 0) else if (comptime std.meta.trait.isFloat(T)) try std.fmt.parseFloat(T, decoded) - else if (comptime std.meta.trait.is(.Enum)(T)) - std.meta.stringToEnum(T, decoded) orelse return error.InvalidEnumValue - else if (T == bool) - bool_map.get(value) orelse return error.InvalidBool - else if (comptime std.meta.trait.hasFn("parse")(T)) + else if (comptime std.meta.trait.is(.Enum)(T)) blk: { + _ = std.ascii.lowerString(decoded, decoded); + break :blk std.meta.stringToEnum(T, decoded) orelse return error.InvalidEnumValue; + } else if (T == bool) blk: { + _ = std.ascii.lowerString(decoded, decoded); + break :blk bool_map.get(decoded) orelse return error.InvalidBool; + } else if (comptime std.meta.trait.hasFn("parse")(T)) try T.parse(value) else @compileError("Invalid type " ++ @typeName(T)); - alloc.free(decoded); return result; } @@ -359,7 +358,7 @@ fn format(comptime prefix: []const u8, comptime name: []const u8, params: anytyp } } -test { +test "parseQuery" { const TestQuery = struct { int: usize = 3, boolean: bool = false, @@ -370,11 +369,11 @@ test { .int = 3, .boolean = false, .str_enum = null, - }, try parseQuery(TestQuery, "")); + }, try parseQuery(std.testing.allocator, TestQuery, "")); try std.testing.expectEqual(TestQuery{ .int = 5, .boolean = true, .str_enum = .foo, - }, try parseQuery(TestQuery, "?int=5&boolean=yes&str_enum=foo")); + }, try parseQuery(std.testing.allocator, TestQuery, "?int=5&boolean=yes&str_enum=foo")); }