Skip to content
78 changes: 39 additions & 39 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: "0 0 * * *"
workflow_dispatch:

jobs:
test:
strategy:
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.platform }}

steps:
- uses: actions/checkout@v4

- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: master

- name: Print Zig version
run: zig version

- name: Build
run: zig build --verbose

- name: Run Tests
run: |
zig build test --summary all

- name: Formatting check
if: matrix.platform != 'windows-latest'
run: zig fmt --check .
# name: CI
#
# on:
# push:
# branches: [ main ]
# pull_request:
# branches: [ main ]
# schedule:
# - cron: "0 0 * * *"
# workflow_dispatch:
#
# jobs:
# test:
# strategy:
# matrix:
# platform: [ubuntu-latest, windows-latest, macos-latest]
# runs-on: ${{ matrix.platform }}
#
# steps:
# - uses: actions/checkout@v4
#
# - name: Setup Zig
# uses: mlugg/setup-zig@v2
# with:
# version: master
#
# - name: Print Zig version
# run: zig version
#
# - name: Build
# run: zig build --verbose
#
# - name: Run Tests
# run: |
# zig build test --summary all
#
# - name: Formatting check
# if: matrix.platform != 'windows-latest'
# run: zig fmt --check .
60 changes: 34 additions & 26 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@ pub fn build(b: *std.Build) !void {
const optimize = b.standardOptimizeOption(.{});
const options_files = b.addWriteFiles();

var threaded: std.Io.Threaded = .init_single_threaded;
// This deinit is not necessary since it's stack allocated but it's ok to
// keep, in case we want to change the threaded initialization at some point
defer threaded.deinit();
const io = threaded.io();

const use_llvm = b.option(
bool,
"use_llvm",
"Use LLVM",
) orelse true;
);

const test_filters = b.option(
[]const []const u8,
Expand Down Expand Up @@ -58,6 +64,7 @@ pub fn build(b: *std.Build) !void {
"zmpl_templates_paths",
"Directories to search for .zmpl templates. Format: `prefix=...,path=...",
) orelse try templatesPaths(
io,
b.allocator,
&.{.{
.prefix = "templates",
Expand Down Expand Up @@ -181,14 +188,14 @@ pub fn build(b: *std.Build) !void {
const manifest_lazy_path = manifest_exe_run.addOutputFileArg("zmpl.manifest.zig");

manifest_exe_run.setCwd(.{
.cwd_relative = try std.fs.cwd().realpathAlloc(b.allocator, "."),
.cwd_relative = try std.Io.Dir.cwd().realPathFileAlloc(io, ".", b.allocator),
});
manifest_exe_run.expectExitCode(0);
manifest_exe_run.addArg(try std.mem.join(b.allocator, ";", templates_paths));

lib.step.dependOn(&manifest_exe_run.step);

for (try findTemplates(b, templates_paths)) |path|
for (try findTemplates(b, io, templates_paths)) |path|
manifest_exe_run.addFileArg(.{ .cwd_relative = path });

const compile_step = b.step("compile", "Compile Zmpl templates");
Expand Down Expand Up @@ -264,7 +271,7 @@ const TemplatesPath = struct {
path: []const []const u8,
};

pub fn templatesPaths(allocator: Allocator, paths: []const TemplatesPath) ![]const []const u8 {
pub fn templatesPaths(io: std.Io, allocator: Allocator, paths: []const TemplatesPath) ![]const []const u8 {
var buf: ArrayList([]const u8) = .empty;
defer buf.deinit(allocator);
for (paths) |path| {
Expand All @@ -274,7 +281,7 @@ pub fn templatesPaths(allocator: Allocator, paths: []const TemplatesPath) ![]con
const absolute_path = if (std.fs.path.isAbsolute(joined))
try allocator.dupe(u8, joined)
else
std.fs.cwd().realpathAlloc(allocator, joined) catch |err|
std.Io.Dir.cwd().realPathFileAlloc(io, joined, allocator) catch |err|
switch (err) {
error.FileNotFound => "_",
else => return err,
Expand All @@ -293,24 +300,24 @@ pub fn templatesPaths(allocator: Allocator, paths: []const TemplatesPath) ![]con
return buf.toOwnedSlice(allocator);
}

// pub fn addTemplateConstants(b: *Build, comptime constants: type) ![]const u8 {
// const fields = switch (@typeInfo(constants)) {
// .@"struct" => |info| info.fields,
// else => @panic("Expected struct, found: " ++ @typeName(constants)),
// };
// var array: [fields.len][]const u8 = undefined;
//
// inline for (fields, 0..) |field, index| {
// array[index] = std.fmt.comptimePrint(
// "{s}#{s}",
// .{ field.name, @typeName(field.type) },
// );
// }
//
// return std.mem.join(b.allocator, "|", &array);
// }

fn findTemplates(b: *Build, templates_paths: []const []const u8) ![][]const u8 {
pub fn addTemplateConstants(b: *Build, comptime constants: type) ![]const u8 {
const fields = switch (@typeInfo(constants)) {
.@"struct" => |info| info.fields,
else => @panic("Expected struct, found: " ++ @typeName(constants)),
};
var array: [fields.len][]const u8 = undefined;

inline for (fields, 0..) |field, index| {
array[index] = std.fmt.comptimePrint(
"{s}#{s}",
.{ field.name, @typeName(field.type) },
);
}

return std.mem.join(b.allocator, "|", &array);
}

fn findTemplates(b: *Build, io: std.Io, templates_paths: []const []const u8) ![][]const u8 {
var templates: ArrayList([]const u8) = .empty;
defer templates.deinit(b.allocator);

Expand All @@ -326,7 +333,8 @@ fn findTemplates(b: *Build, templates_paths: []const []const u8) ![][]const u8 {
for (templates_paths_buf.items) |templates_path| {
if (std.mem.eql(u8, templates_path, "_")) continue;

var dir = std.fs.cwd().openDir(
var dir = std.Io.Dir.cwd().openDir(
io,
templates_path,
.{ .iterate = true },
) catch |err| {
Expand All @@ -345,11 +353,11 @@ fn findTemplates(b: *Build, templates_paths: []const []const u8) ![][]const u8 {
var walker = try dir.walk(b.allocator);
defer walker.deinit();

while (try walker.next()) |entry| {
while (try walker.next(io)) |entry| {
if (entry.kind != .file) continue;
const extension = std.fs.path.extension(entry.path);
if (!std.mem.eql(u8, extension, ".zmpl")) continue;
try templates.append(b.allocator, try dir.realpathAlloc(b.allocator, entry.path));
try templates.append(b.allocator, try dir.realPathFileAlloc(io, entry.path, b.allocator));
}
}
return templates.toOwnedSlice(b.allocator);
Expand Down
9 changes: 4 additions & 5 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
.fingerprint = 0xef2931206468149,
.minimum_zig_version = "0.15.1",
.dependencies = .{
.jetcommon = .{
.url = "https://github.com/jetzig-framework/jetcommon/archive/ed326c74b98fae893acd89d2e84c0d894a200df3.tar.gz",
.hash = "jetcommon-0.1.0-jPY_DbNIAAA0utNExN3zMeqXA4fhZXQ6LDDP1eg8vodj",
},
.zmd = .{
.url = "https://github.com/jetzig-framework/zmd/archive/87b1c46b517f47b3384eba7ce98d197c463a9d5e.tar.gz",
.hash = "zmd-0.1.0-H8YV7bvdAABAVFR2lherqOup7valUMg9UTEiiMFxlTjZ",
},
.jetcommon = .{
.url = "https://github.com/emneo-dev/jetcommon/archive/c4da8d68813ab6cd384323475753c07d18627656.tar.gz",
.hash = "jetcommon-0.1.0-jPY_DetFAAA8wBYM9TKN5HJ1TAH5qSioHzmZuRTg4H_Z",
},
},

.paths = .{
Expand All @@ -24,4 +24,3 @@
"README.md",
},
}

21 changes: 13 additions & 8 deletions src/main.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const std = @import("std");
const ArenaAllocator = std.heap.ArenaAllocator;
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator;
const Writer = std.Io.Writer;
const Allocator = std.mem.Allocator;

const zmpl = @import("zmpl");

Expand All @@ -10,20 +12,23 @@ pub fn main() !void {
var arena: ArenaAllocator = .init(allocator);

var data = zmpl.Data.init(arena.allocator());
// https://github.com/json-iterator/test-data/blob/master/large-file.json
const stat = try std.fs.cwd().statFile("large-file.json");
const json = try std.fs.cwd().readFileAlloc(allocator, "large-file.json", stat.size);

// Time to beat: Duration: 1.28s
try benchmark(zmpl.Data.fromJson, .{ &data, json });
try benchmark(allocator, zmpl.Data.fromJson, .{ &data, json });

// Time to beat: Duration: 946.734ms
_ = try benchmark(zmpl.Data.toJson, .{&data});
_ = try benchmark(allocator, zmpl.Data.toJson, .{&data});
}

fn benchmark(func: anytype, args: anytype) @typeInfo(@TypeOf(func)).@"fn".return_type.? {
const start = std.time.nanoTimestamp();
const result = try @call(.auto, func, args);
const end = std.time.nanoTimestamp();
std.debug.print("Duration: {}\n", .{std.fmt.fmtDuration(@intCast(end - start))});
return result;
fn benchmark(allocator: Allocator, func: anytype, args: anytype) !void {
const start = std.time.microTimestamp();
_ = try @call(.auto, func, args);
const end = std.time.microTimestamp();
var buf: Writer.Allocating = .init(allocator);
defer buf.deinit();
try buf.writer.printDuration((end - start) * 1000, .{});
std.debug.print("Duration: {s}\n", .{try buf.toOwnedSlice()});
}
13 changes: 9 additions & 4 deletions src/manifest/Manifest.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub fn init(

pub fn compile(
self: *Manifest,
io: std.Io,
allocator: Allocator,
writer: *Writer,
comptime options: type,
Expand Down Expand Up @@ -107,6 +108,7 @@ pub fn compile(
// var file = try std.fs.openFileAbsolute(inner_path.path, .{});
// }
try self.compileTemplates(
io,
allocator,
&template_defs,
outer_path,
Expand Down Expand Up @@ -190,23 +192,26 @@ pub fn compile(

fn compileTemplates(
self: *Manifest,
io: std.Io,
allocator: Allocator,
array: *ArrayList(TemplateDef),
templates_path: TemplatePath,
templates_paths_map: StringHashMap([]const u8),
template_map: *StringHashMap(Template.TemplateMap),
comptime options: type,
) !void {
var read_buffer: [512]u8 = undefined;
for (self.template_paths) |template_path| {
if (!template_path.present) continue;
if (!std.mem.eql(u8, template_path.prefix, templates_path.prefix)) continue;

const key = try util.templatePathStore(allocator, templates_paths_map.get(template_path.prefix).?, template_path.path);
const generated_name = template_map.get(template_path.prefix).?.get(key).?;

var file = try std.fs.openFileAbsolute(template_path.path, .{});
const size = (try file.stat()).size;
const content = try file.readToEndAlloc(allocator, @intCast(size));
var file = try std.Io.Dir.openFileAbsolute(io, template_path.path, .{});
const size = (try file.stat(io)).size;
var file_reader = file.reader(io, &read_buffer);
const content = try file_reader.interface.allocRemaining(allocator, .limited(size + 1));
var template: Template = .init(
allocator,
generated_name,
Expand All @@ -217,7 +222,7 @@ fn compileTemplates(
content,
template_map.*,
);
const output = try template.compile(options);
const output = try template.compile(io, options);

const template_def: TemplateDef = .{
.key = key,
Expand Down
Loading