mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
mustache rendering works - cleanup needed
This commit is contained in:
parent
8273b56f2f
commit
9557bebf0b
3 changed files with 189 additions and 5 deletions
60
examples/mustache/mustache.zig
Normal file
60
examples/mustache/mustache.zig
Normal file
|
@ -0,0 +1,60 @@
|
|||
const std = @import("std");
|
||||
const zap = @import("zap");
|
||||
|
||||
fn on_request_verbose(r: zap.SimpleRequest) void {
|
||||
if (r.path) |the_path| {
|
||||
std.debug.print("PATH: {s}\n", .{the_path});
|
||||
}
|
||||
|
||||
if (r.query) |the_query| {
|
||||
std.debug.print("QUERY: {s}\n", .{the_query});
|
||||
}
|
||||
const template = "{{=<< >>=}}* Users:\r\n<<#users>><<id>>. <<& name>> (<<name>>)\r\n<</users>>\r\nNested: <<& nested.item >>.";
|
||||
const p = zap.MustacheNew(template) catch return;
|
||||
const User = struct {
|
||||
name: []const u8,
|
||||
id: isize,
|
||||
};
|
||||
std.debug.print("{*}\n", .{p});
|
||||
if (zap.MustacheBuild(p, .{
|
||||
.users = [_]User{
|
||||
User{
|
||||
.name = "Rene",
|
||||
.id = 1,
|
||||
},
|
||||
User{
|
||||
.name = "Caro",
|
||||
.id = 6,
|
||||
},
|
||||
},
|
||||
.nested = .{
|
||||
.item = "nesting works",
|
||||
},
|
||||
})) |s| {
|
||||
std.debug.print("{s}\n", .{s});
|
||||
_ = r.sendBody(s);
|
||||
}
|
||||
_ = r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
}
|
||||
|
||||
fn on_request_minimal(r: zap.SimpleRequest) void {
|
||||
_ = r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>");
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
var listener = zap.SimpleHttpListener.init(.{
|
||||
.port = 3000,
|
||||
.on_request = on_request_verbose,
|
||||
.log = true,
|
||||
.max_clients = 100000,
|
||||
});
|
||||
try listener.listen();
|
||||
|
||||
std.debug.print("Listening on 0.0.0.0:3000\n", .{});
|
||||
|
||||
// start worker threads
|
||||
zap.start(.{
|
||||
.threads = 1,
|
||||
.workers = 1,
|
||||
});
|
||||
}
|
132
src/mustache.zig
132
src/mustache.zig
|
@ -7,6 +7,7 @@
|
|||
// @cInclude("fiobj_mustache.h");
|
||||
// });
|
||||
|
||||
const std = @import("std");
|
||||
const util = @import("util.zig");
|
||||
|
||||
pub const FIOBJ = usize;
|
||||
|
@ -87,11 +88,29 @@ pub fn MustacheNew(data: []const u8) MustacheError!*Mustache {
|
|||
// pub extern fn fiobj_mustache_build2(dest: FIOBJ, mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
|
||||
|
||||
pub extern fn fiobj_hash_new() FIOBJ;
|
||||
pub extern fn fiobj_free(arg_o: FIOBJ) callconv(.C) void;
|
||||
pub extern fn fiobj_hash_set(hash: FIOBJ, key: FIOBJ, obj: FIOBJ) c_int;
|
||||
pub extern fn fiobj_ary_push(ary: FIOBJ, obj: FIOBJ) void;
|
||||
pub extern fn fiobj_float_new(num: f64) FIOBJ;
|
||||
pub extern fn fiobj_num_new_bignum(num: isize) FIOBJ;
|
||||
|
||||
// pub extern fn fiobj_num_new(num: isize) callconv(.C) FIOBJ;
|
||||
|
||||
pub const FIOBJ_T_TRUE: c_int = 22;
|
||||
pub const FIOBJ_T_FALSE: c_int = 38;
|
||||
pub fn fiobj_true() callconv(.C) FIOBJ {
|
||||
return @bitCast(FIOBJ, @as(c_long, FIOBJ_T_TRUE));
|
||||
}
|
||||
pub fn fiobj_false() callconv(.C) FIOBJ {
|
||||
return @bitCast(FIOBJ, @as(c_long, FIOBJ_T_FALSE));
|
||||
}
|
||||
pub extern fn fiobj_ary_new2(capa: usize) FIOBJ;
|
||||
pub extern fn fiobj_str_new(str: [*c]const u8, len: usize) FIOBJ;
|
||||
pub extern fn fiobj_str_buf(capa: usize) FIOBJ;
|
||||
|
||||
// this build is slow because it needs to translate to a FIOBJ data
|
||||
// object FIOBJ_T_HASH
|
||||
pub fn MustacheBuild(mustache: *Mustache, data: ?FIOBJ) ?[]const u8 {
|
||||
_ = data;
|
||||
pub fn MustacheBuild(mustache: *Mustache, data: anytype) ?[]const u8 {
|
||||
|
||||
// FIOBJ data = fiobj_hash_new();
|
||||
// FIOBJ key = fiobj_str_new("users", 5);
|
||||
|
@ -121,11 +140,116 @@ pub fn MustacheBuild(mustache: *Mustache, data: ?FIOBJ) ?[]const u8 {
|
|||
// fiobj_hash_set(ary, key, fiobj_str_new("dot notation success", 20));
|
||||
// fiobj_free(key);
|
||||
|
||||
var empty = fiobj_hash_new();
|
||||
var ret = fiobj_mustache_build(mustache, empty);
|
||||
const T = @TypeOf(data);
|
||||
if (@typeInfo(T) != .Struct) {
|
||||
@compileError("No struct: '" ++ @typeName(T) ++ "'");
|
||||
}
|
||||
|
||||
// std.debug.print("data: ", .{});
|
||||
const fiobj_data = fiobjectify(data);
|
||||
// std.debug.print("{any}\n", .{fiobj_data});
|
||||
|
||||
// TODO: fiobj_free everything
|
||||
var ret = fiobj_mustache_build(mustache, fiobj_data);
|
||||
return util.fio2str(ret);
|
||||
}
|
||||
|
||||
pub fn fiobjectify(
|
||||
value: anytype,
|
||||
) FIOBJ {
|
||||
const T = @TypeOf(value);
|
||||
switch (@typeInfo(T)) {
|
||||
.Float, .ComptimeFloat => {
|
||||
return fiobj_float_new(value);
|
||||
},
|
||||
.Int, .ComptimeInt => {
|
||||
return fiobj_num_new_bignum(value);
|
||||
},
|
||||
.Bool => {
|
||||
return if (value) fiobj_true() else fiobj_false();
|
||||
},
|
||||
.Null => {
|
||||
return 0;
|
||||
},
|
||||
.Optional => {
|
||||
if (value) |payload| {
|
||||
return fiobjectify(payload);
|
||||
} else {
|
||||
return fiobjectify(null);
|
||||
}
|
||||
},
|
||||
.Enum => {
|
||||
return fiobj_num_new_bignum(@enumToInt(value));
|
||||
},
|
||||
.Union => {
|
||||
const info = @typeInfo(T).Union;
|
||||
if (info.tag_type) |UnionTagType| {
|
||||
inline for (info.fields) |u_field| {
|
||||
if (value == @field(UnionTagType, u_field.name)) {
|
||||
return fiobjectify(@field(value, u_field.name));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@compileError("Unable to fiobjectify untagged union '" ++ @typeName(T) ++ "'");
|
||||
}
|
||||
},
|
||||
.Struct => |S| {
|
||||
// create a new fio hashmap
|
||||
var m = fiobj_hash_new();
|
||||
// std.debug.print("new struct\n", .{});
|
||||
inline for (S.fields) |Field| {
|
||||
// don't include void fields
|
||||
if (Field.type == void) continue;
|
||||
|
||||
// std.debug.print(" new field: {s}\n", .{Field.name});
|
||||
const fname = fiobj_str_new(util.toCharPtr(Field.name), Field.name.len);
|
||||
// std.debug.print(" fiobj name : {any}\n", .{fname});
|
||||
const v = @field(value, Field.name);
|
||||
// std.debug.print(" value: {any}\n", .{v});
|
||||
const fvalue = fiobjectify(v);
|
||||
// std.debug.print(" fiobj value: {any}\n", .{fvalue});
|
||||
_ = fiobj_hash_set(m, fname, fvalue);
|
||||
}
|
||||
return m;
|
||||
},
|
||||
.ErrorSet => return fiobjectify(@as([]const u8, @errorName(value))),
|
||||
.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.One => switch (@typeInfo(ptr_info.child)) {
|
||||
.Array => {
|
||||
const Slice = []const std.meta.Elem(ptr_info.child);
|
||||
return fiobjectify(@as(Slice, value));
|
||||
},
|
||||
else => {
|
||||
// TODO: avoid loops?
|
||||
return fiobjectify(value.*);
|
||||
},
|
||||
},
|
||||
// TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
|
||||
.Slice => {
|
||||
// std.debug.print("new slice\n", .{});
|
||||
if (ptr_info.child == u8 and std.unicode.utf8ValidateSlice(value)) {
|
||||
return fiobj_str_new(util.toCharPtr(value), value.len);
|
||||
}
|
||||
|
||||
var arr = fiobj_ary_new2(value.len);
|
||||
for (value) |x| {
|
||||
const v = fiobjectify(x);
|
||||
fiobj_ary_push(arr, v);
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
else => @compileError("Unable to fiobjectify type '" ++ @typeName(T) ++ "'"),
|
||||
},
|
||||
.Array => return fiobjectify(&value),
|
||||
.Vector => |info| {
|
||||
const array: [info.len]info.child = value;
|
||||
return fiobjectify(&array);
|
||||
},
|
||||
else => @compileError("Unable to fiobjectify type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// pub extern fn fiobj_mustache_free(mustache: ?*mustache_s) void;
|
||||
pub fn MustacheFree(m: ?*Mustache) void {
|
||||
fiobj_mustache_free(m);
|
||||
|
|
|
@ -19,7 +19,7 @@ pub fn str2fio(s: []const u8) C.fio_str_info_s {
|
|||
};
|
||||
}
|
||||
|
||||
fn toCharPtr(s: []const u8) [*c]u8 {
|
||||
pub fn toCharPtr(s: []const u8) [*c]u8 {
|
||||
return @intToPtr([*c]u8, @ptrToInt(s.ptr));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue