{"id":13805518,"url":"https://github.com/batiati/mustache-zig","last_synced_at":"2025-04-05T02:04:57.492Z","repository":{"id":42536697,"uuid":"459577284","full_name":"batiati/mustache-zig","owner":"batiati","description":"Logic-less templates for Zig","archived":false,"fork":false,"pushed_at":"2025-03-05T19:45:39.000Z","size":1129,"stargazers_count":137,"open_issues_count":11,"forks_count":23,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T01:04:07.450Z","etag":null,"topics":["mustache","mustache-templating","zig-package","ziglang"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/batiati.png","metadata":{"files":{"readme":"ReadMe.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-15T12:52:35.000Z","updated_at":"2025-03-15T21:28:58.000Z","dependencies_parsed_at":"2023-12-25T23:31:44.747Z","dependency_job_id":"47723639-83fb-40bc-9170-5d2d9211b415","html_url":"https://github.com/batiati/mustache-zig","commit_stats":{"total_commits":388,"total_committers":5,"mean_commits":77.6,"dds":"0.046391752577319534","last_synced_commit":"5f609d0158f6c5635328ae603b38c351aa15b121"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batiati%2Fmustache-zig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batiati%2Fmustache-zig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batiati%2Fmustache-zig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batiati%2Fmustache-zig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/batiati","download_url":"https://codeload.github.com/batiati/mustache-zig/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247276163,"owners_count":20912288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mustache","mustache-templating","zig-package","ziglang"],"created_at":"2024-08-04T01:01:01.952Z","updated_at":"2025-04-05T02:04:57.469Z","avatar_url":"https://github.com/batiati.png","language":"Zig","funding_links":[],"categories":["Zig"],"sub_categories":[],"readme":"# MUSTACHE-ZIG\r\n# [{{mustache}}](https://mustache.github.io/) templates for [Zig](https://ziglang.org/).\r\n\r\n[![made with Zig](https://img.shields.io/badge/made%20with%20%E2%9D%A4%20-Zig-orange)](https://ziglang.org/)\r\n[![Matrix Build](https://github.com/batiati/mustache-zig/actions/workflows/build.yml/badge.svg)](https://github.com/batiati/mustache-zig/actions/workflows/build.yml)\r\n[![codecov](https://codecov.io/gh/batiati/mustache-zig/branch/master/graph/badge.svg)](https://codecov.io/gh/batiati/mustache-zig)\r\n[![license mit](https://img.shields.io/github/license/batiati/mustache-zig)](https://github.com/batiati/mustache-zig/blob/master/LICENSE.txt)\r\n\r\n![logo](mustache.png)\r\n\r\n# ! Under development !\r\n\r\n## [Read more on Zig News](https://zig.news/batiati/growing-a-mustache-with-zig-di4)\r\n\r\n# \r\n## Features\r\n\r\n✓ [Comments](https://github.com/mustache/spec/blob/master/specs/comments.yml) `{{! Mustache is awesome }}`.\r\n\r\n✓ Custom [delimiters](https://github.com/mustache/spec/blob/master/specs/delimiters.yml) `{{=[ ]=}}`.\r\n\r\n✓ [Interpolation](https://github.com/mustache/spec/blob/master/specs/interpolation.yml) of common types, such as strings, enums, bools, optionals, pointers, integers, floats and JSON objects into `{{variables}`.\r\n\r\n✓ [Unescaped interpolation](https://github.com/mustache/spec/blob/b2aeb3c283de931a7004b5f7a2cb394b89382369/specs/interpolation.yml#L52) with `{{{tripple-mustache}}}` or `{{\u0026ampersant}}`.\r\n\r\n✓ Rendering [sections](https://github.com/mustache/spec/blob/master/specs/sections.yml) `{{#foo}} ... {{/foo}}`.\r\n\r\n✓ [Section iterator](https://github.com/mustache/spec/blob/b2aeb3c283de931a7004b5f7a2cb394b89382369/specs/sections.yml#L133) over slices, arrays and tuples `{{slice}} ... {{/slice}}`.\r\n\r\n✓ Rendering [inverted sections](https://github.com/mustache/spec/blob/master/specs/inverted.yml) `{{^foo}} ... {{/foo}}`.\r\n\r\n✓ [Lambdas](https://github.com/mustache/spec/blob/master/specs/~lambdas.yml) expansion.\r\n\r\n✓ Rendering [partials](https://github.com/mustache/spec/blob/master/specs/partials.yml) `{{\u003efile.html}}`.\r\n\r\n☐ Rendering [parents and blocks](https://github.com/mustache/spec/blob/master/specs/~inheritance.yml) `{{\u003cfile.html}}` and `{{$block}}`.\r\n\r\n## Full spec compliant\r\n\r\n✓ All implemented features passes the tests from [mustache spec](https://github.com/mustache/spec).\r\n\r\n## Examples\r\n\r\nRender from strings, files and pre-loaded templates.\r\nSee the [source code](https://github.com/batiati/mustache-zig/blob/master/samples/zig/src/main.zig) for more details.\r\n\r\n### Runtime parser\r\n\r\n```Zig\r\n\r\nconst std = @import(\"std\");\r\nconst mustache = @import(\"mustache\");\r\n\r\npub fn main() !void {\r\n    const template =\r\n        \\\\Hello {{name}} from Zig\r\n        \\\\Supported features:\r\n        \\\\{{#features}}\r\n        \\\\  - {{name}}\r\n        \\\\{{/features}}\r\n    ;\r\n\r\n    const data = .{\r\n        .name = \"friends\",\r\n        .features = .{\r\n            .{ .name = \"interpolation\" },\r\n            .{ .name = \"sections\" },\r\n            .{ .name = \"delimiters\" },\r\n            .{ .name = \"partials\" },\r\n        },\r\n    };\r\n\r\n    const allocator = std.testing.allocator;\r\n    const result = try mustache.allocRenderText(allocator, template, data);\r\n    defer allocator.free(result);\r\n\r\n    try std.testing.expectEqualStrings(\r\n        \\\\Hello friends from Zig\r\n        \\\\Supported features:\r\n        \\\\  - interpolation\r\n        \\\\  - sections\r\n        \\\\  - delimiters\r\n        \\\\  - partials\r\n        \\\\\r\n    , result);\r\n}\r\n\r\n```\r\n\r\n### Comptime parser\r\n\r\n```Zig\r\n\r\nconst std = @import(\"std\");\r\nconst mustache = @import(\"mustache\");\r\n\r\npub fn main() !void {\r\n    const template_text = \"It's a comptime loaded template, with a {{value}}\";\r\n    const comptime_template = comptime mustache.parseComptime(template_text, .{}, .{});\r\n    \r\n    const Data = struct { value: []const u8 };\r\n    const data: Data = .{\r\n        .value = \"runtime value\"\r\n    };\r\n\r\n    const allocator = std.testing.allocator;\r\n    const result = try mustache.allocRender(comptime_template, data);\r\n    defer allocator.free(result);\r\n\r\n    try std.testing.expectEqualStrings(\r\n        \"It's a comptime loaded template, with a runtime value\", \r\n        result,\r\n    );\r\n}\r\n\r\n```\r\n\r\n\r\n### JSON support\r\n\r\n```Zig\r\n\r\nconst std = @import(\"std\");\r\nconst mustache = @import(\"mustache\");\r\n\r\npub fn main() !void {\r\n    const allocator = std.testing.allocator;\r\n\r\n    // Parsing an arbitrary (dynamic) json string:\r\n    const json_source =\r\n        \\\\{\r\n        \\\\   \"name\": \"friends\"\r\n        \\\\}\r\n    ;    \r\n    var json = try std.json.parseFromSlice(\r\n        std.json.Value,\r\n        allocator,\r\n        json_source,\r\n        .{},\r\n    );\r\n    defer json.deinit();\r\n\r\n    const template = \"Hello {{name}} from Zig\";\r\n    const result = try mustache.allocRenderText(allocator, template, json);\r\n    defer allocator.free(result);\r\n\r\n    try std.testing.expectEqualStrings(\"Hello friends from Zig\" , result);\r\n}\r\n\r\n```\r\n\r\n### FFI Interface\r\n\r\nMustache-zig exports a FFI interface to be consumed by other languages\r\n\r\nFor more details: \r\n\r\n- [C sample](samples/c/sample.c)\r\n\r\n- [C# sample](samples/dotnet/mustache.samples/Program.cs)\r\n\r\n## Customizable use\r\n\r\nThere is no \"one size fits all\", but the mustache-zig API is intended to provide great flexibility to cover many use cases.\r\n \r\n[![diagram](docs/diagram.svg)](https://raw.githubusercontent.com/batiati/mustache-zig/master/docs/diagram.svg)\r\n\r\n## Benchmarks.\r\n\r\nThere are [some benchmark tests](benchmark/src/ramhorns_bench.zig) inspired by the excellent [Ramhorns](https://github.com/maciejhirsz/ramhorns)'s benchmarks, comparing the performance of most popular **Rust** template engines.\r\n\r\n1. Rendering to a new allocated string 1 million times\r\n\r\n    |                                                               | Total time | ns/iter  | MB/s      \r\n    ----------------------------------------------------------------|------------|----------|-----------\r\n    |[Ramhorns 0.14.0](https://crates.io/crates/ramhorns)           | 0,040s     |    40 ns | 2425 MB/s\r\n    |[Askama 0.9](https://crates.io/crates/askama)                  | 0,136s     |   136 ns |  713 MB/s\r\n    |[Tera 1.2.0](https://crates.io/crates/tera)                    | 0,308s     |   308 ns |  314 MB/s\r\n    |[Mustache 0.9](https://crates.io/crates/mustache)              | 0,363s     |   363 ns |  267 MB/s\r\n    |[Handlebars 3.1.0-beta.2](https://crates.io/crates/handlebars) | 1,833s     | 1,833 ns |   52 MB/s\r\n\r\n2. Parsing a template 1 million times\r\n\r\n    |                                                               | Total time | ns/iter   | MB/s      \r\n    ----------------------------------------------------------------|------------|-----------|-----------\r\n    |[Ramhorns 0.14.0](https://crates.io/crates/ramhorns)           |  0,317s    |    317 ns |  492 MB/s\r\n    |[Mustache 0.9](https://crates.io/crates/mustache)              |  5,863s    |  5,863 ns |   26 MB/s\r\n    |[Handlebars 3.1.0-beta.2](https://crates.io/crates/handlebars) | 11,797s    | 11,797 ns |   13 MB/s\r\n\r\n\r\n_*All benchmarks were executed using `cargo bench` on a Intel i7-1185G7 @ 3.00GHz, Linux kernel 5.17_\r\n\r\n\u003eFor comparision with mustache-zig, refer to \"Rendering to a new allocated string 1 million times\" and \"Parsing a template 1 million times\" sections bellow.\r\n### Mustache vs Zig's fmt\r\n\r\nThe same benchmark was implemented in Zig for both mustache-zig and Zig's `std.fmt`.\r\n\r\nWe can assume that Zig's `std.fmt` is the **fastest** possible way to render a simple string using Zig. [This benchmark](benchmark/src/ramhorns_bench.zig) shows how much **slower** a mustache template is rendered when compared with the same template rendered by Zig's `std.fmt`.\r\n\r\n1. Rendering to a pre-allocated buffer 1 million times\r\n\r\n    |               | Total time | ns/iter | MB/s      | Penality\r\n    ----------------|------------|---------|-----------|-------\r\n    |Zig fmt        | 0.042s     | 42 ns   | 2596 MB/s | -- \r\n    |mustache-zig   | 0.094s     | 94 ns   | 1149 MB/s | 2.260x slower\r\n\r\n\r\n2. Rendering to a new allocated string 1 million times\r\n\r\n    |               | Total time | ns/iter | MB/s      | Penality\r\n    ----------------|------------|---------|-----------|-------\r\n    |Zig fmt        | 0.058s     |  58 ns  | 1869 MB/s | -- \r\n    |mustache-zig   | 0.167s     | 167 ns  |  645 MB/s | 2.897x slower\r\n\r\n\r\n3. Rendering to a local file 1 million times\r\n\r\n    |               | Total time | ns/iter | MB/s      | Penality\r\n    ----------------|------------|---------|-----------|-------\r\n    |Zig fmt        | 0.079s     |  79 ns  | 1367 MB/s | -- \r\n    |mustache-zig   | 0.125s     | 125 ns  |  862 MB/s | 1.586x slower\r\n\r\n\r\n4. Parsing a template 1 million times\r\n\r\n    |               | Total time | ns/iter  | MB/s      \r\n    ----------------|------------|----------|-----------\r\n    |mustache-zig   | 1.380s     | 1,380 ns |  182 MB/s \r\n\r\n\r\n_*All benchmarks were compiled as ReleaseSafe, and executed on a Intel i7-1185G7 @ 3.00GHz, Linux kernel 5.17_\r\n\r\n### Memory benchmarks\r\n\r\nMustache templates are well known for HTML templating, but it's useful to render any kind of dynamic document, and potentially load templates from untrusted or user-defined sources.\r\n\r\nSo, it's also important to be able to deal with multi-megabyte inputs without eating all your RAM.\r\n\r\n```Zig\r\n\r\n    // 32KB should be enough memory for this job\r\n    // 16KB if we don't need to support lambdas 😅\r\n    var plenty_of_memory = std.heap.GeneralPurposeAllocator(.{ .enable_memory_limit = true }){\r\n        .requested_memory_limit = 32 * 1024,\r\n    };\r\n    defer _ = plenty_of_memory.deinit();\r\n\r\n    try mustache.renderFile(plenty_of_memory.allocator(), \"10MB_file.mustache\", ctx, out_writer);\r\n\r\n```\r\n\r\n## Licensing\r\n\r\n- MIT\r\n\r\n- Mustache is Copyright (C) 2009 Chris Wanstrath\r\nOriginal CTemplate by Google","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbatiati%2Fmustache-zig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbatiati%2Fmustache-zig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbatiati%2Fmustache-zig/lists"}