Refactor
This commit is contained in:
parent
ba4f3a7bf4
commit
0b13f210c7
7 changed files with 112 additions and 42 deletions
|
@ -1,5 +1,60 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub const ParamIter = struct {
|
||||
str: []const u8,
|
||||
index: usize = 0,
|
||||
|
||||
const Param = struct {
|
||||
name: []const u8,
|
||||
value: []const u8,
|
||||
};
|
||||
|
||||
pub fn from(str: []const u8) ParamIter {
|
||||
return .{ .str = str, .index = std.mem.indexOfScalar(u8, str, ';') orelse str.len };
|
||||
}
|
||||
|
||||
pub fn fieldValue(self: *ParamIter) []const u8 {
|
||||
return std.mem.sliceTo(self.str, ';');
|
||||
}
|
||||
|
||||
pub fn next(self: *ParamIter) ?Param {
|
||||
if (self.index >= self.str.len) return null;
|
||||
|
||||
const start = self.index + 1;
|
||||
const new_start = std.mem.indexOfScalarPos(u8, self.str, start, ';') orelse self.str.len;
|
||||
self.index = new_start;
|
||||
|
||||
const param = std.mem.trim(u8, self.str[start..new_start], " \t");
|
||||
var split = std.mem.split(u8, param, "=");
|
||||
const name = split.first();
|
||||
const value = std.mem.trimLeft(u8, split.rest(), " \t");
|
||||
// TODO: handle quoted values
|
||||
// TODO: handle parse errors
|
||||
|
||||
return Param{
|
||||
.name = name,
|
||||
.value = value,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn getParam(field: []const u8, name: ?[]const u8) ?[]const u8 {
|
||||
var iter = ParamIter.from(field);
|
||||
|
||||
if (name) |param| {
|
||||
while (iter.next()) |p| {
|
||||
if (std.ascii.eqlIgnoreCase(param, p.name)) {
|
||||
const trimmed = std.mem.trim(u8, p.value, " \t");
|
||||
if (trimmed.len >= 2 and trimmed[0] == '"' and trimmed[trimmed.len - 1] == '"') {
|
||||
return trimmed[1 .. trimmed.len - 1];
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} else return iter.fieldValue();
|
||||
}
|
||||
|
||||
pub const Fields = struct {
|
||||
const HashContext = struct {
|
||||
const hash_seed = 1;
|
|
@ -5,6 +5,7 @@ const server = @import("./server.zig");
|
|||
pub const urlencode = @import("./urlencode.zig");
|
||||
pub const socket = @import("./socket.zig");
|
||||
const json = @import("./json.zig");
|
||||
pub const fields = @import("./fields.zig");
|
||||
|
||||
pub const Method = std.http.Method;
|
||||
pub const Status = std.http.Status;
|
||||
|
@ -16,7 +17,7 @@ pub const Server = server.Server;
|
|||
|
||||
pub const middleware = @import("./middleware.zig");
|
||||
|
||||
pub const Fields = @import("./headers.zig").Fields;
|
||||
pub const Fields = fields.Fields;
|
||||
|
||||
pub const Protocol = enum {
|
||||
http_1_0,
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
test {
|
||||
_ = @import("./request/test_parser.zig");
|
||||
_ = @import("./middleware.zig");
|
||||
_ = @import("./multipart.zig");
|
||||
_ = @import("./urlencode.zig");
|
||||
}
|
|
@ -144,42 +144,16 @@ fn fieldPtr(ptr: anytype, comptime names: []const []const u8) FieldPtr(@TypeOf(p
|
|||
return fieldPtr(&@field(ptr.*, names[0]), names[1..]);
|
||||
}
|
||||
|
||||
fn isScalar(comptime T: type) bool {
|
||||
if (comptime std.meta.trait.isZigString(T)) return true;
|
||||
if (comptime std.meta.trait.isIntegral(T)) return true;
|
||||
if (comptime std.meta.trait.isFloat(T)) return true;
|
||||
if (comptime std.meta.trait.is(.Enum)(T)) return true;
|
||||
if (T == bool) return true;
|
||||
if (comptime std.meta.trait.hasFn("parse")(T)) return true;
|
||||
|
||||
if (comptime std.meta.trait.is(.Optional)(T) and isScalar(std.meta.Child(T))) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn recursiveFieldPaths(comptime T: type, comptime prefix: []const []const u8) []const []const []const u8 {
|
||||
comptime {
|
||||
var fields: []const []const []const u8 = &.{};
|
||||
|
||||
for (std.meta.fields(T)) |f| {
|
||||
const full_name = prefix ++ [_][]const u8{f.name};
|
||||
if (isScalar(f.field_type)) {
|
||||
fields = fields ++ [_][]const []const u8{full_name};
|
||||
} else {
|
||||
fields = fields ++ recursiveFieldPaths(f.field_type, full_name);
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
||||
// Represents a set of results.
|
||||
// row() must be called until it returns null, or the query may not complete
|
||||
// Must be deallocated by a call to finish()
|
||||
pub fn Results(comptime T: type) type {
|
||||
// would normally make this a declaration of the struct, but it causes the compiler to crash
|
||||
const fields = if (T == void) .{} else recursiveFieldPaths(T, &.{});
|
||||
const fields = if (T == void) .{} else util.serialize.getRecursiveFieldList(
|
||||
T,
|
||||
&.{},
|
||||
util.serialize.default_options,
|
||||
);
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
|
|
|
@ -601,3 +601,20 @@ const ControlTokenIter = struct {
|
|||
self.peeked_token = token;
|
||||
}
|
||||
};
|
||||
|
||||
test "template" {
|
||||
const testCase = struct {
|
||||
fn case(comptime tmpl: []const u8, args: anytype, expected: []const u8) !void {
|
||||
var stream = std.io.changeDetectionStream(expected, std.io.null_writer);
|
||||
try execute(stream.writer(), tmpl, args);
|
||||
try std.testing.expect(!stream.changeDetected());
|
||||
}
|
||||
}.case;
|
||||
|
||||
try testCase("", .{}, "");
|
||||
try testCase("abcd", .{}, "abcd");
|
||||
try testCase("{.val}", .{ .val = 3 }, "3");
|
||||
try testCase("{#if .val}1{/if}", .{ .val = true }, "1");
|
||||
try testCase("{#for .vals |$v|}{$v}{/for}", .{ .vals = [_]u8{ 1, 2, 3 } }, "123");
|
||||
try testCase("{#for .vals |$v|=} {$v} {=/for}", .{ .vals = [_]u8{ 1, 2, 3 } }, "123");
|
||||
}
|
||||
|
|
|
@ -201,7 +201,7 @@ pub fn seedThreadPrng() !void {
|
|||
|
||||
pub fn comptimeToCrlf(comptime str: []const u8) []const u8 {
|
||||
comptime {
|
||||
@setEvalBranchQuota(str.len * 6);
|
||||
@setEvalBranchQuota(str.len * 10);
|
||||
const size = std.mem.replacementSize(u8, str, "\n", "\r\n");
|
||||
var buf: [size]u8 = undefined;
|
||||
_ = std.mem.replace(u8, str, "\n", "\r\n", &buf);
|
||||
|
|
|
@ -38,7 +38,7 @@ pub fn deserializeString(allocator: std.mem.Allocator, comptime T: type, value:
|
|||
@compileError("Invalid type " ++ @typeName(T));
|
||||
}
|
||||
|
||||
fn getRecursiveFieldList(comptime T: type, comptime prefix: FieldRef, comptime options: SerializationOptions) []const FieldRef {
|
||||
pub fn getRecursiveFieldList(comptime T: type, comptime prefix: FieldRef, comptime options: SerializationOptions) []const FieldRef {
|
||||
comptime {
|
||||
if (std.meta.trait.is(.Union)(T) and prefix.len == 0 and options.embed_unions) {
|
||||
@compileError("Cannot embed a union into nothing");
|
||||
|
@ -113,7 +113,7 @@ pub fn DeserializerContext(comptime Result: type, comptime From: type, comptime
|
|||
context: Context = .{},
|
||||
|
||||
pub fn setSerializedField(self: *@This(), key: []const u8, value: From) !void {
|
||||
const field = std.meta.stringToEnum(std.meta.FieldEnum(Data), key);
|
||||
const field = std.meta.stringToEnum(std.meta.FieldEnum(Data), key) orelse return error.UnknownField;
|
||||
inline for (comptime std.meta.fieldNames(Data)) |field_name| {
|
||||
@setEvalBranchQuota(10000);
|
||||
const f = comptime std.meta.stringToEnum(std.meta.FieldEnum(Data), field_name);
|
||||
|
@ -123,7 +123,36 @@ pub fn DeserializerContext(comptime Result: type, comptime From: type, comptime
|
|||
}
|
||||
}
|
||||
|
||||
return error.UnknownField;
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub const Iter = struct {
|
||||
data: *const Data,
|
||||
field_index: usize,
|
||||
|
||||
const Item = struct {
|
||||
key: []const u8,
|
||||
value: From,
|
||||
};
|
||||
|
||||
pub fn next(self: *Iter) ?Item {
|
||||
while (self.field_index < std.meta.fields(Data).len) {
|
||||
const idx = self.field_index;
|
||||
self.field_index += 1;
|
||||
inline for (comptime std.meta.fieldNames(Data)) |field, i| {
|
||||
if (i == idx) {
|
||||
const maybe_value = @field(self.data.*, field);
|
||||
if (maybe_value) |value| return Item{ .key = field, .value = value };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn iterator(self: *const @This()) Iter {
|
||||
return .{ .data = &self.data, .field_index = 0 };
|
||||
}
|
||||
|
||||
pub fn finishFree(_: *@This(), allocator: std.mem.Allocator, val: anytype) void {
|
||||
|
|
Loading…
Reference in a new issue