srctree

Gregory Mullen parent 2ade2fa6 897bc0e2
add nullable usize to templates

src/endpoints/gist.zig added: 128, removed: 92, total 36
@@ -98,10 +98,7 @@ fn new(ctx: *Context) Error!void {
fn edit(ctx: *Context, files: []const Template.Structs.GistFiles) Error!void {
// TODO move this back into context somehow
var btns = [1]Template.Structs.NavButtons{
.{
.name = "inbox",
.url = "/inbox",
},
.{ .name = "inbox", .extra = 0, .url = "/inbox" },
};
 
var page = GistNewPage.init(.{
@@ -135,7 +132,7 @@ fn toTemplate(a: Allocator, files: []const Gist.File) ![]Template.Structs.GistFi
 
fn view(ctx: *Context) Error!void {
// TODO move this back into context somehow
var btns = [1]Template.Structs.NavButtons{.{ .name = "inbox", .url = "/inbox" }};
var btns = [1]Template.Structs.NavButtons{.{ .name = "inbox", .extra = 0, .url = "/inbox" }};
 
if (ctx.uri.next()) |hash| {
if (hash.len != 64) return error.BadData;
 
src/endpoints/repos.zig added: 128, removed: 92, total 36
@@ -107,12 +107,12 @@ pub fn navButtons(ctx: *Context) ![2]Template.Structs.NavButtons {
const btns = [2]Template.Structs.NavButtons{
.{
.name = "issues",
.extra = try allocPrint(ctx.alloc, "{}", .{i_count}),
.extra = i_count,
.url = try allocPrint(ctx.alloc, "/repos/{s}/issues/", .{rd.name}),
},
.{
.name = "diffs",
.extra = try allocPrint(ctx.alloc, "{}", .{d_count}),
.extra = d_count,
.url = try allocPrint(ctx.alloc, "/repos/{s}/diffs/", .{rd.name}),
},
};
@@ -311,7 +311,7 @@ fn list(ctx: *Context) Error!void {
 
var btns = [1]Template.Structs.NavButtons{.{
.name = "inbox",
.extra = "0",
.extra = 0,
.url = "/inbox",
}};
 
 
src/template.zig added: 128, removed: 92, total 36
@@ -7,6 +7,7 @@ const indexOf = std.mem.indexOf;
const indexOfScalar = std.mem.indexOfScalar;
const indexOfPos = std.mem.indexOfPos;
const indexOfScalarPos = std.mem.indexOfScalarPos;
const indexOfAnyPos = std.mem.indexOfAnyPos;
const lastIndexOf = std.mem.lastIndexOf;
const startsWith = std.mem.startsWith;
const count = std.mem.count;
@@ -232,6 +233,7 @@ pub const Directive = struct {
pub const KnownType = enum {
usize,
isize,
@"?usize",
};
 
const Positions = struct {
@@ -332,54 +334,65 @@ pub const Directive = struct {
}
 
pub fn doTyped(self: Directive, T: type, ctx: anytype, out: anytype) anyerror!void {
//@compileLog(T);
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(self.noun, &local)];
inline for (std.meta.fields(T)) |field| {
if (field.type == []const u8 or
field.type == ?[]const u8) continue;
switch (@typeInfo(field.type)) {
.Pointer => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
for (child) |each| {
switch (field.type) {
[]const []const u8 => {
std.debug.assert(self.verb == .forrow);
try out.writeAll(each);
try out.writeAll(self.otherwise.blob.whitespace);
},
else => {
std.debug.assert(self.verb == .foreach);
try self.forEachTyped(@TypeOf(each), each, out);
},
switch (@typeInfo(T)) {
.Struct => {
inline for (std.meta.fields(T)) |field| {
if (field.type == []const u8 or
field.type == ?[]const u8) continue;
switch (@typeInfo(field.type)) {
.Pointer => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
for (child) |each| {
switch (field.type) {
[]const []const u8 => {
std.debug.assert(self.verb == .forrow);
try out.writeAll(each);
try out.writeAll(self.otherwise.blob.whitespace);
},
else => {
std.debug.assert(self.verb == .foreach);
try self.forEachTyped(@TypeOf(each), each, out);
},
}
}
}
}
},
.Optional => {
if (eql(u8, field.name, realname)) {
//@compileLog("optional for {s}\n", field.name, field.type, T);
const child = @field(ctx, field.name);
if (child) |exists| {
try self.doTyped(@TypeOf(exists), exists, out);
//try self.withTyped(@TypeOf(exists), exists, out);
}
}
},
.Struct => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
std.debug.assert(self.verb == .build);
try self.withTyped(@TypeOf(child), child, out);
}
},
.Int => |int| {
if (eql(u8, field.name, realname)) {
std.debug.assert(int.bits == 64);
try std.fmt.formatInt(@field(ctx, field.name), 10, .lower, .{}, out);
}
},
else => comptime unreachable,
}
},
.Optional => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
if (child) |exists| {
std.debug.assert(self.verb == .with);
try self.withTyped(@TypeOf(exists), exists, out);
}
}
},
.Struct => {
if (eql(u8, field.name, realname)) {
const child = @field(ctx, field.name);
std.debug.assert(self.verb == .build);
try self.withTyped(@TypeOf(child), child, out);
}
},
.Int => |int| {
if (eql(u8, field.name, realname)) {
std.debug.assert(int.bits == 64);
try std.fmt.formatInt(@field(ctx, field.name), 10, .lower, .{}, out);
}
},
else => comptime unreachable,
}
}
},
.Int => {
//std.debug.assert(int.bits == 64);
try std.fmt.formatInt(ctx, 10, .lower, .{}, out);
},
else => {},
}
}
 
@@ -492,13 +505,16 @@ pub const Directive = struct {
var known: ?KnownType = null;
if (indexOfScalar(u8, noun, '=')) |i| {
if (i >= 4 and eql(u8, noun[i - 4 .. i], "type")) {
const i_end = indexOfScalarPos(u8, noun, i, ' ') orelse end - 1;
const i_end = indexOfAnyPos(u8, noun, i, " /") orelse end - 1;
const requested_type = std.mem.trim(u8, noun[i..i_end], " ='\"");
inline for (std.meta.fields(KnownType)) |kt| {
if (eql(u8, requested_type, kt.name)) {
known = @enumFromInt(kt.value);
break;
}
} else {
std.debug.print("Unable to resolve requested type {s}\n", .{requested_type});
unreachable;
}
}
}
@@ -1243,6 +1259,40 @@ test "directive typed usize" {
try std.testing.expectEqualStrings(expected, build);
}
 
test "directive typed ?usize" {
var a = std.testing.allocator;
const blob = "<Number type=\"?usize\" />";
const expected: []const u8 = "420";
 
const FE = struct { number: ?usize };
 
const t = Template{ .name = "test", .blob = blob };
const page = Page(t, FE);
 
const slice = FE{ .number = 420 };
const p = page.init(slice);
const build = try p.build(a);
defer a.free(build);
try std.testing.expectEqualStrings(expected, build);
}
 
test "directive typed ?usize null" {
var a = std.testing.allocator;
const blob = "<Number type=\"?usize\" />";
const expected: []const u8 = "";
 
const FE = struct { number: ?usize };
 
const t = Template{ .name = "test", .blob = blob };
const page = Page(t, FE);
 
const slice = FE{ .number = null };
const p = page.init(slice);
const build = try p.build(a);
defer a.free(build);
try std.testing.expectEqualStrings(expected, build);
}
 
test "directive typed isize" {
var a = std.testing.allocator;
const blob = "<Number type=\"isize\" />";
 
src/template/page.zig added: 128, removed: 92, total 36
@@ -14,6 +14,24 @@ const findTemplate = Templates.findTemplate;
 
const DEBUG = false;
 
fn typeField(T: type, name: []const u8, data: T) ?[]const u8 {
if (@typeInfo(T) != .Struct) return null;
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(name, &local)];
inline for (std.meta.fields(T)) |field| {
if (eql(u8, field.name, realname)) {
switch (field.type) {
[]const u8,
?[]const u8,
=> return @field(data, field.name),
 
else => return null,
}
}
}
return null;
}
 
pub fn PageRuntime(comptime PageDataType: type) type {
return struct {
pub const Self = @This();
@@ -39,23 +57,6 @@ pub fn PageRuntime(comptime PageDataType: type) type {
return std.fmt.allocPrint(a, "{}", .{self});
}
 
fn typeField(name: []const u8, data: PageDataType) ?[]const u8 {
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(name, &local)];
inline for (std.meta.fields(PageDataType)) |field| {
if (eql(u8, field.name, realname)) {
switch (field.type) {
[]const u8,
?[]const u8,
=> return @field(data, field.name),
 
else => return null,
}
}
}
return null;
}
 
fn formatAny(
self: Self,
comptime fmts: []const u8,
@@ -105,7 +106,7 @@ pub fn PageRuntime(comptime PageDataType: type) type {
switch (drct.verb) {
.variable => {
const noun = drct.noun;
const var_name = typeField(noun, ctx);
const var_name = typeField(PageDataType, noun, ctx);
if (var_name) |data_blob| {
try out.writeAll(data_blob);
} else {
@@ -116,6 +117,7 @@ pub fn PageRuntime(comptime PageDataType: type) type {
.ign => return error.IgnoreDirective,
.del => {},
.template => |subt| {
if (PageDataType == usize) unreachable;
inline for (std.meta.fields(PageDataType)) |field|
switch (@typeInfo(field.type)) {
.Optional => |otype| {
@@ -150,6 +152,7 @@ pub fn PageRuntime(comptime PageDataType: type) type {
else => drct.doTyped(PageDataType, ctx, out) catch unreachable,
}
}
 
pub fn format(self: Self, comptime fmts: []const u8, _: std.fmt.FormatOptions, out: anytype) !void {
var ctx = self.data;
var blob = self.template.blob;
@@ -202,20 +205,6 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
return std.fmt.allocPrint(a, "{}", .{self});
}
 
fn typeField(name: []const u8, data: PageDataType) ?[]const u8 {
var local: [0xff]u8 = undefined;
const realname = local[0..makeFieldName(name, &local)];
inline for (std.meta.fields(PageDataType)) |field| {
if (std.mem.eql(u8, field.name, realname)) {
switch (field.type) {
[]const u8, ?[]const u8 => return @field(data, field.name),
else => return null,
}
}
}
return null;
}
 
fn formatAny(
self: Self,
comptime fmts: []const u8,
@@ -265,7 +254,7 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
switch (drct.verb) {
.variable => {
const noun = drct.noun;
const var_name = typeField(noun, ctx);
const var_name = typeField(PageDataType, noun, ctx);
if (var_name) |data_blob| {
try out.writeAll(data_blob);
} else {
 
templates/_nav.html added: 128, removed: 92, total 36
@@ -2,6 +2,6 @@
<li><a href="/user">owner</a></li>
<li><a href="/network">network</a></li>
<For NavButtons>
<li><a href="<Url>"><Name><sup><Extra ORNULL></sup></a></li>
<li><a href="<Url>"><Name /><sup><Extra type="?usize" /></sup></a></li>
</For>
<li><NavAuth></li>