mirror of
https://github.com/zigzap/zap.git
synced 2025-10-21 07:34:08 +00:00
Updated mustache.zig
to be more Zig like - mustache.zig
now returns a Mustache
struct. This allows functions to be called on the mustache instance, e.g. zap.mustacheFree(mustache)
-> mustache.free()
. - Updated mustache example. - Added doc strings to majority of mustache functions.
This commit is contained in:
parent
57370b4e31
commit
9c19038082
2 changed files with 250 additions and 223 deletions
|
@ -1,15 +1,26 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const zap = @import("zap");
|
const zap = @import("zap");
|
||||||
|
const Mustache = @import("zap").Mustache;
|
||||||
|
|
||||||
fn on_request(r: zap.SimpleRequest) void {
|
fn on_request(r: zap.SimpleRequest) void {
|
||||||
const template = "{{=<< >>=}}* Users:\r\n<<#users>><<id>>. <<& name>> (<<name>>)\r\n<</users>>\r\nNested: <<& nested.item >>.";
|
const template =
|
||||||
const p = zap.mustacheData(template) catch return;
|
\\ {{=<< >>=}}
|
||||||
defer zap.mustacheFree(p);
|
\\ * Users:
|
||||||
|
\\ <<#users>>
|
||||||
|
\\ <<id>>. <<& name>> (<<name>>)
|
||||||
|
\\ <</users>>
|
||||||
|
\\ Nested: <<& nested.item >>.
|
||||||
|
;
|
||||||
|
|
||||||
|
var mustache = Mustache.fromData(template) catch return;
|
||||||
|
defer mustache.deinit();
|
||||||
|
|
||||||
const User = struct {
|
const User = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
id: isize,
|
id: isize,
|
||||||
};
|
};
|
||||||
const ret = zap.mustacheBuild(p, .{
|
|
||||||
|
const ret = mustache.build(.{
|
||||||
.users = [_]User{
|
.users = [_]User{
|
||||||
.{
|
.{
|
||||||
.name = "Rene",
|
.name = "Rene",
|
||||||
|
@ -25,6 +36,7 @@ fn on_request(r: zap.SimpleRequest) void {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
defer ret.deinit();
|
defer ret.deinit();
|
||||||
|
|
||||||
if (r.setContentType(.TEXT)) {
|
if (r.setContentType(.TEXT)) {
|
||||||
if (ret.str()) |s| {
|
if (ret.str()) |s| {
|
||||||
r.sendBody(s) catch return;
|
r.sendBody(s) catch return;
|
||||||
|
|
113
src/mustache.zig
113
src/mustache.zig
|
@ -1,11 +1,14 @@
|
||||||
// supporting code to make using facilio's mustache stuff
|
|
||||||
// (see http://facil.io/0.7.x/fiobj_mustache)
|
|
||||||
// easier / possible / more zig-like
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const fio = @import("fio.zig");
|
const fio = @import("fio.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
|
/// A struct to handle Mustache templating.
|
||||||
|
///
|
||||||
|
/// This is a wrapper around fiobj's mustache template handling.
|
||||||
|
/// See http://facil.io/0.7.x/fiobj_mustache for more information.
|
||||||
|
pub const Mustache = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
pub const struct_mustache_s = opaque {};
|
pub const struct_mustache_s = opaque {};
|
||||||
pub const enum_mustache_error_en = c_uint;
|
pub const enum_mustache_error_en = c_uint;
|
||||||
pub const mustache_error_en = enum_mustache_error_en;
|
pub const mustache_error_en = enum_mustache_error_en;
|
||||||
|
@ -16,16 +19,17 @@ pub extern fn fiobj_mustache_build(mustache: ?*mustache_s, data: fio.FIOBJ) fio.
|
||||||
pub extern fn fiobj_mustache_build2(dest: fio.FIOBJ, mustache: ?*mustache_s, data: fio.FIOBJ) fio.FIOBJ;
|
pub extern fn fiobj_mustache_build2(dest: fio.FIOBJ, mustache: ?*mustache_s, data: fio.FIOBJ) fio.FIOBJ;
|
||||||
pub extern fn fiobj_mustache_free(mustache: ?*mustache_s) void;
|
pub extern fn fiobj_mustache_free(mustache: ?*mustache_s) void;
|
||||||
|
|
||||||
/// Mustache load args used in mustacheNew
|
/// Load arguments used when creating a new Mustache instance.
|
||||||
|
/// One source of data must be passed in, otherwise an error will occur.
|
||||||
pub const MustacheLoadArgs = struct {
|
pub const MustacheLoadArgs = struct {
|
||||||
/// optional filename, enables partial templates on filesystem
|
/// Filename. This enables partial templates on filesystem.
|
||||||
filename: ?[]const u8 = null,
|
filename: ?[]const u8 = null,
|
||||||
|
|
||||||
/// optional string data. should be used if no filename is specified.
|
/// String data. Should be used if no filename is specified.
|
||||||
data: ?[]const u8 = null,
|
data: ?[]const u8 = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// used internally for interfacing with fio
|
/// Internal struct used for interfacing with fio.
|
||||||
const MustacheLoadArgsFio = extern struct {
|
const MustacheLoadArgsFio = extern struct {
|
||||||
filename: [*c]const u8,
|
filename: [*c]const u8,
|
||||||
filename_len: usize,
|
filename_len: usize,
|
||||||
|
@ -34,11 +38,10 @@ const MustacheLoadArgsFio = extern struct {
|
||||||
err: [*c]mustache_error_en,
|
err: [*c]mustache_error_en,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Mustache = mustache_s;
|
handler: *mustache_s,
|
||||||
|
|
||||||
pub const MustacheStatus = enum(c_int) {};
|
pub const Status = enum(c_int) {};
|
||||||
|
pub const Error = error{
|
||||||
pub const MustacheError = error{
|
|
||||||
MUSTACHE_ERR_TOO_DEEP,
|
MUSTACHE_ERR_TOO_DEEP,
|
||||||
MUSTACHE_ERR_CLOSURE_MISMATCH,
|
MUSTACHE_ERR_CLOSURE_MISMATCH,
|
||||||
MUSTACHE_ERR_FILE_NOT_FOUND,
|
MUSTACHE_ERR_FILE_NOT_FOUND,
|
||||||
|
@ -52,12 +55,12 @@ pub const MustacheError = error{
|
||||||
MUSTACHE_ERR_USER_ERROR,
|
MUSTACHE_ERR_USER_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
// pub extern fn fiobj_mustache_build2(dest: FIOBJ, mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
|
/// Create a new `Mustache` instance; `deinit()` should be called to free
|
||||||
|
/// the object after usage.
|
||||||
pub fn mustacheNew(load_args: MustacheLoadArgs) MustacheError!*Mustache {
|
pub fn init(load_args: MustacheLoadArgs) Error!Self {
|
||||||
var err: mustache_error_en = undefined;
|
var err: mustache_error_en = undefined;
|
||||||
|
|
||||||
var args: MustacheLoadArgsFio = .{
|
const args: MustacheLoadArgsFio = .{
|
||||||
.filename = filn: {
|
.filename = filn: {
|
||||||
if (load_args.filename) |filn| break :filn filn.ptr else break :filn null;
|
if (load_args.filename) |filn| break :filn filn.ptr else break :filn null;
|
||||||
},
|
},
|
||||||
|
@ -73,58 +76,73 @@ pub fn mustacheNew(load_args: MustacheLoadArgs) MustacheError!*Mustache {
|
||||||
.err = &err,
|
.err = &err,
|
||||||
};
|
};
|
||||||
|
|
||||||
var ret = fiobj_mustache_new(args);
|
const ret = fiobj_mustache_new(args);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
0 => return ret.?,
|
0 => return Self{
|
||||||
1 => return MustacheError.MUSTACHE_ERR_TOO_DEEP,
|
.handler = ret.?,
|
||||||
2 => return MustacheError.MUSTACHE_ERR_CLOSURE_MISMATCH,
|
},
|
||||||
3 => return MustacheError.MUSTACHE_ERR_FILE_NOT_FOUND,
|
1 => return Error.MUSTACHE_ERR_TOO_DEEP,
|
||||||
4 => return MustacheError.MUSTACHE_ERR_FILE_TOO_BIG,
|
2 => return Error.MUSTACHE_ERR_CLOSURE_MISMATCH,
|
||||||
5 => return MustacheError.MUSTACHE_ERR_FILE_NAME_TOO_LONG,
|
3 => return Error.MUSTACHE_ERR_FILE_NOT_FOUND,
|
||||||
6 => return MustacheError.MUSTACHE_ERR_FILE_NAME_TOO_SHORT,
|
4 => return Error.MUSTACHE_ERR_FILE_TOO_BIG,
|
||||||
7 => return MustacheError.MUSTACHE_ERR_EMPTY_TEMPLATE,
|
5 => return Error.MUSTACHE_ERR_FILE_NAME_TOO_LONG,
|
||||||
8 => return MustacheError.MUSTACHE_ERR_DELIMITER_TOO_LONG,
|
6 => return Error.MUSTACHE_ERR_FILE_NAME_TOO_SHORT,
|
||||||
9 => return MustacheError.MUSTACHE_ERR_NAME_TOO_LONG,
|
7 => return Error.MUSTACHE_ERR_EMPTY_TEMPLATE,
|
||||||
10 => return MustacheError.MUSTACHE_ERR_UNKNOWN,
|
8 => return Error.MUSTACHE_ERR_DELIMITER_TOO_LONG,
|
||||||
11 => return MustacheError.MUSTACHE_ERR_USER_ERROR,
|
9 => return Error.MUSTACHE_ERR_NAME_TOO_LONG,
|
||||||
else => return MustacheError.MUSTACHE_ERR_UNKNOWN,
|
10 => return Error.MUSTACHE_ERR_UNKNOWN,
|
||||||
|
11 => return Error.MUSTACHE_ERR_USER_ERROR,
|
||||||
|
else => return Error.MUSTACHE_ERR_UNKNOWN,
|
||||||
}
|
}
|
||||||
return MustacheError.MUSTACHE_ERR_UNKNOWN;
|
return Error.MUSTACHE_ERR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function if you only want to use in-memory data (as opposed to file data)
|
/// Convenience function to create a new `Mustache` instance with in-memory data loaded;
|
||||||
pub fn mustacheData(data: []const u8) MustacheError!*Mustache {
|
/// `deinit()` should be called to free the object after usage..
|
||||||
return mustacheNew(.{ .data = data });
|
pub fn fromData(data: []const u8) Error!Mustache {
|
||||||
|
return Self.init(.{ .data = data });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function if you only want to use file-based data (as opposed to in-memory data)
|
/// Convenience function to create a new `Mustache` instance with file-based data loaded;
|
||||||
pub fn mustacheLoad(filename: []const u8) MustacheError!*Mustache {
|
/// `deinit()` should be called to free the object after usage..
|
||||||
return mustacheNew(.{ .filename = filename });
|
pub fn fromFile(filename: []const u8) Error!Mustache {
|
||||||
|
return Self.init(.{ .filename = filename });
|
||||||
}
|
}
|
||||||
|
|
||||||
// implement these: fiobj_mustache.c
|
/// Free the data backing a `Mustache` instance.
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
fiobj_mustache_free(self.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement these - fiobj_mustache.c
|
||||||
// pub extern fn fiobj_mustache_build(mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
|
// pub extern fn fiobj_mustache_build(mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
|
||||||
// pub extern fn fiobj_mustache_build2(dest: FIOBJ, mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
|
// pub extern fn fiobj_mustache_build2(dest: FIOBJ, mustache: ?*mustache_s, data: FIOBJ) FIOBJ;
|
||||||
|
|
||||||
|
/// The result from calling `build`.
|
||||||
const MustacheBuildResult = struct {
|
const MustacheBuildResult = struct {
|
||||||
fiobj_result: fio.FIOBJ = 0,
|
fiobj_result: fio.FIOBJ = 0,
|
||||||
|
|
||||||
/// holds the context converted into a fiobj, used in build
|
/// Holds the context converted into a fiobj.
|
||||||
|
/// This is used in `build`.
|
||||||
fiobj_context: fio.FIOBJ = 0,
|
fiobj_context: fio.FIOBJ = 0,
|
||||||
|
|
||||||
|
/// Free the data backing a `MustacheBuildResult` instance.
|
||||||
pub fn deinit(m: *const MustacheBuildResult) void {
|
pub fn deinit(m: *const MustacheBuildResult) void {
|
||||||
fio.fiobj_free_wrapped(m.fiobj_result);
|
fio.fiobj_free_wrapped(m.fiobj_result);
|
||||||
fio.fiobj_free_wrapped(m.fiobj_context);
|
fio.fiobj_free_wrapped(m.fiobj_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve a string representation of the built template.
|
||||||
pub fn str(m: *const MustacheBuildResult) ?[]const u8 {
|
pub fn str(m: *const MustacheBuildResult) ?[]const u8 {
|
||||||
return util.fio2str(m.fiobj_result);
|
return util.fio2str(m.fiobj_result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// this build is slow because it needs to translate to a FIOBJ data
|
/// Build the Mustache template; `deinit()` should be called on the build
|
||||||
// object FIOBJ_T_HASH
|
/// result to free the data.
|
||||||
pub fn mustacheBuild(mustache: *Mustache, data: anytype) MustacheBuildResult {
|
/// TODO: This build is slow because it needs to translate to a FIOBJ data
|
||||||
|
/// object - FIOBJ_T_HASH
|
||||||
|
pub fn build(self: *Self, data: anytype) MustacheBuildResult {
|
||||||
const T = @TypeOf(data);
|
const T = @TypeOf(data);
|
||||||
if (@typeInfo(T) != .Struct) {
|
if (@typeInfo(T) != .Struct) {
|
||||||
@compileError("No struct: '" ++ @typeName(T) ++ "'");
|
@compileError("No struct: '" ++ @typeName(T) ++ "'");
|
||||||
|
@ -133,7 +151,7 @@ pub fn mustacheBuild(mustache: *Mustache, data: anytype) MustacheBuildResult {
|
||||||
var result: MustacheBuildResult = .{};
|
var result: MustacheBuildResult = .{};
|
||||||
|
|
||||||
result.fiobj_context = fiobjectify(data);
|
result.fiobj_context = fiobjectify(data);
|
||||||
result.fiobj_result = fiobj_mustache_build(mustache, result.fiobj_context);
|
result.fiobj_result = fiobj_mustache_build(self.handler, result.fiobj_context);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +196,7 @@ pub fn fiobjectify(
|
||||||
},
|
},
|
||||||
.Struct => |S| {
|
.Struct => |S| {
|
||||||
// create a new fio hashmap
|
// create a new fio hashmap
|
||||||
var m = fio.fiobj_hash_new();
|
const m = fio.fiobj_hash_new();
|
||||||
// std.debug.print("new struct\n", .{});
|
// std.debug.print("new struct\n", .{});
|
||||||
inline for (S.fields) |Field| {
|
inline for (S.fields) |Field| {
|
||||||
// don't include void fields
|
// don't include void fields
|
||||||
|
@ -215,7 +233,7 @@ pub fn fiobjectify(
|
||||||
return fio.fiobj_str_new(util.toCharPtr(value), value.len);
|
return fio.fiobj_str_new(util.toCharPtr(value), value.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
var arr = fio.fiobj_ary_new2(value.len);
|
const arr = fio.fiobj_ary_new2(value.len);
|
||||||
for (value) |x| {
|
for (value) |x| {
|
||||||
const v = fiobjectify(x);
|
const v = fiobjectify(x);
|
||||||
fio.fiobj_ary_push(arr, v);
|
fio.fiobj_ary_push(arr, v);
|
||||||
|
@ -233,7 +251,4 @@ pub fn fiobjectify(
|
||||||
}
|
}
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
pub fn mustacheFree(m: ?*Mustache) void {
|
|
||||||
fiobj_mustache_free(m);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue