Refactor
This commit is contained in:
parent
ba4f3a7bf4
commit
0b13f210c7
|
@ -1,5 +1,60 @@
|
||||||
const std = @import("std");
|
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 {
|
pub const Fields = struct {
|
||||||
const HashContext = struct {
|
const HashContext = struct {
|
||||||
const hash_seed = 1;
|
const hash_seed = 1;
|
|
@ -5,6 +5,7 @@ const server = @import("./server.zig");
|
||||||
pub const urlencode = @import("./urlencode.zig");
|
pub const urlencode = @import("./urlencode.zig");
|
||||||
pub const socket = @import("./socket.zig");
|
pub const socket = @import("./socket.zig");
|
||||||
const json = @import("./json.zig");
|
const json = @import("./json.zig");
|
||||||
|
pub const fields = @import("./fields.zig");
|
||||||
|
|
||||||
pub const Method = std.http.Method;
|
pub const Method = std.http.Method;
|
||||||
pub const Status = std.http.Status;
|
pub const Status = std.http.Status;
|
||||||
|
@ -16,7 +17,7 @@ pub const Server = server.Server;
|
||||||
|
|
||||||
pub const middleware = @import("./middleware.zig");
|
pub const middleware = @import("./middleware.zig");
|
||||||
|
|
||||||
pub const Fields = @import("./headers.zig").Fields;
|
pub const Fields = fields.Fields;
|
||||||
|
|
||||||
pub const Protocol = enum {
|
pub const Protocol = enum {
|
||||||
http_1_0,
|
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..]);
|
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.
|
// Represents a set of results.
|
||||||
// row() must be called until it returns null, or the query may not complete
|
// row() must be called until it returns null, or the query may not complete
|
||||||
// Must be deallocated by a call to finish()
|
// Must be deallocated by a call to finish()
|
||||||
pub fn Results(comptime T: type) type {
|
pub fn Results(comptime T: type) type {
|
||||||
// would normally make this a declaration of the struct, but it causes the compiler to crash
|
// 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 {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
|
|
@ -601,3 +601,20 @@ const ControlTokenIter = struct {
|
||||||
self.peeked_token = token;
|
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 {
|
pub fn comptimeToCrlf(comptime str: []const u8) []const u8 {
|
||||||
comptime {
|
comptime {
|
||||||
@setEvalBranchQuota(str.len * 6);
|
@setEvalBranchQuota(str.len * 10);
|
||||||
const size = std.mem.replacementSize(u8, str, "\n", "\r\n");
|
const size = std.mem.replacementSize(u8, str, "\n", "\r\n");
|
||||||
var buf: [size]u8 = undefined;
|
var buf: [size]u8 = undefined;
|
||||||
_ = std.mem.replace(u8, str, "\n", "\r\n", &buf);
|
_ = 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));
|
@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 {
|
comptime {
|
||||||
if (std.meta.trait.is(.Union)(T) and prefix.len == 0 and options.embed_unions) {
|
if (std.meta.trait.is(.Union)(T) and prefix.len == 0 and options.embed_unions) {
|
||||||
@compileError("Cannot embed a union into nothing");
|
@compileError("Cannot embed a union into nothing");
|
||||||
|
@ -113,7 +113,7 @@ pub fn DeserializerContext(comptime Result: type, comptime From: type, comptime
|
||||||
context: Context = .{},
|
context: Context = .{},
|
||||||
|
|
||||||
pub fn setSerializedField(self: *@This(), key: []const u8, value: From) !void {
|
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| {
|
inline for (comptime std.meta.fieldNames(Data)) |field_name| {
|
||||||
@setEvalBranchQuota(10000);
|
@setEvalBranchQuota(10000);
|
||||||
const f = comptime std.meta.stringToEnum(std.meta.FieldEnum(Data), field_name);
|
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 {
|
pub fn finishFree(_: *@This(), allocator: std.mem.Allocator, val: anytype) void {
|
||||||
|
|
Loading…
Reference in New Issue