An HTTP/1.1 server for zig
0

Configure Feed

Select the types of activity you want to include in your feed.

http.zig / src / params.zig
2.9 kB 88 lines
1const std = @import("std"); 2 3const mem = std.mem; 4const Allocator = std.mem.Allocator; 5 6// Similar to KeyValue with two important differences 7// 1 - We don't need to normalize (i.e. lowercase) the names, because they're 8// statically defined in code, and presumably, if the param is called "id" 9// then the developer will also fetch it as "id" 10// 2 - This is populated from Router, and the way router works is that it knows 11// the values before it knows the names. The addValue and addNames 12// methods reflect how Router uses this. 13pub const Params = struct { 14 len: usize, 15 names: [][]const u8, 16 values: [][]const u8, 17 18 pub fn init(allocator: Allocator, max: usize) !Params { 19 const allocation = try allocator.alloc([]const u8, 2 * max); 20 return .{ 21 .len = 0, 22 .names = allocation[0..max], 23 .values = allocation[max..], 24 }; 25 } 26 27 pub fn deinit(self: *Params, allocator: Allocator) void { 28 allocator.free(self.names.ptr[0 .. 2 * self.names.len]); 29 } 30 31 pub fn addValue(self: *Params, value: []const u8) void { 32 if (self.len == self.names.len) { 33 return; 34 } 35 self.values[self.len] = value; 36 self.len += 1; 37 } 38 39 // It should be impossible for names.len != self.len at this point, but it's 40 // a bit dangerous to assume that since self.names is re-used between requests 41 // and we don't want to leak anything, so I think enforcing a len of names.len 42 // is safer, since names is generally statically defined based on routes setup. 43 // 44 // `noalias names` as `names` being a pointer inside self.names doesn't make sense, 45 // and memcpy needs this guarantee anyways. 46 pub fn addNames(self: *Params, noalias names: [][]const u8) void { 47 std.debug.assert(names.len == self.len); 48 @memcpy(self.names[0..self.len], names); 49 } 50 51 pub fn get(self: *const Params, needle: []const u8) ?[]const u8 { 52 const names = self.names[0..self.len]; 53 for (names, 0..) |name, i| { 54 if (mem.eql(u8, name, needle)) { 55 return self.values[i]; 56 } 57 } 58 59 return null; 60 } 61 62 pub fn reset(self: *Params) void { 63 self.len = 0; 64 } 65}; 66 67const t = @import("t.zig"); 68test "params: get" { 69 const allocator = t.allocator; 70 var params = try Params.init(allocator, 10); 71 var names = [_][]const u8{ "over", "duncan" }; 72 params.addValue("9000"); 73 params.addValue("idaho"); 74 params.addNames(names[0..]); 75 76 try t.expectEqual("9000", params.get("over").?); 77 try t.expectEqual("idaho", params.get("duncan").?); 78 79 params.reset(); 80 try t.expectEqual(null, params.get("over")); 81 try t.expectEqual(null, params.get("duncan")); 82 83 params.addValue("!9000!"); 84 params.addNames(names[0..1]); 85 try t.expectEqual("!9000!", params.get("over").?); 86 87 params.deinit(t.allocator); 88}