lithos-gotmpl-rs
A Rust implementation for go template and related libraries. The core surface is split into:
lithos-gotmpl-engine: hand-rolled lexer/parser/runtime that evaluates Go text/template syntax. Apps inject function registries when building templates.lithos-gotmpl-core: default helper pack that mirrors the stock Go text/template built-ins (e.g.eq,printf,index,default).lithos-sprig: a Rust-friendly slice of thesprigfunction library sogitmpland similar engines can avoid cgo while staying behaviourally aligned with upstream Sprig.
Project layout
crates/lithos-gotmpl-engine/src/– core parser/evaluator.Templateinstances accept aFunctionRegistryand execute pipelines by delegating to registered helpers. Action nodes expose parsedPipeline/Commandstructures, so constructs like{{ .name | default "foo" | upper }}surface as three distinct commands in the AST (field lookup,default, thenupper). Branching forms such asif/range/withmaterialise as dedicated AST nodes with nested blocks, matching the shape of Go'sparsepackage. The engine honours Go-style whitespace trim markers ({{-/-}}) and pipeline variable bindings like{{$val := .item}}with lexical scoping across control structures.crates/lithos-gotmpl-core/src/– base helper bundle that registers the canonical Go text/template built-ins atop the engine.crates/lithos-sprig/src/– sprig-style helpers layered on top of the engine/core crates.test-cases/lithos-sprig.json– shared test vectors describing calls that mirror Go sprig behaviour. Each entry captures both function arguments and a template snippet with its expected rendering.test-cases/lithos-gotmpl-core.json– vectors harvested from Go'stext/templatetests to validate our built-in helper semantics.go-sanity/– shared Go runner used to sanity-check test cases against the real Go implementation.crates/lithos-sprig/tests/compat.rs– integration test that drives the go-sanity runner and asserts the Rust implementations stay in lock-step.justfile– light CLI automation for common tasks.
Development
You can work either inside the provided dev container or with a native toolchain:
- Dev container – use the Dev Containers specification. For example,
with the
devcontainerCLI:
Editors such as VS Code or GitHub Codespaces can also consume the same definition. The container installs Rust (stable + nightly), Go 1.25.1, Python 3.12, and all required CLI tools via.devcontainer/postCreate.sh. - Native setup – install the prerequisites manually and run
just install-ci-toolsto pull in the cargo utilities and linters we use in CI.
just go-sanity # runs the shared Go sanity harness against sprig test cases
just test # runs the Rust unit + integration tests
just verify # executes both
just ci-test # matches the GitHub Actions test job locally
just ci-behavior # runs compat + optional property/contract suites
just ci-quality # fmt + clippy gate
just ci-security # cargo audit / cargo deny (requires tools installed)
just ci-mutation # cargo-mutants sweep (requires `cargo install cargo-mutants`)
just mutation # alias for ci-mutation
just ci-fuzz # smoke-tests the fuzz harnesses (requires nightly + cargo-fuzz)
just fuzz # alias for ci-fuzz
just ci-release # dry-run release-plz workflow
just release # alias for ci-release
just install-ci-tools # installs cargo-audit, cargo-deny, cargo-tarpaulin, cargo-mutants, cargo-fuzz, actionlint, yamllint, release-plz
just install-cargo-audit|deny|tarpaulin|cargo-mutants|cargo-fuzz|actionlint|yamllint|release-plz # install individual extras
The integration test will skip itself gracefully if Go is missing. Keep the
cases in test-cases/lithos-sprig.json aligned with the functions implemented in Rust
for deterministic comparisons. When scenarios get more complex, add subdirectories under
test-cases/ containing input.tmpl, input.json, and expected.* assets that both the
Rust harness and Go oracle can consume (see test-cases/sprig/nested-default/ for an
example covering nested pipelines).
Rust toolchain: the workspace targets the 2021 edition. The minimum supported Rust version (MSRV) is 1.70.0; CI should exercise the latest stable release as well as MSRV once it is wired up.
Automation
- GitHub Actions CI (
.github/workflows/ci.yml) fan-outs into dedicated jobs: the core unit test suite, behavioural validation (including the Go-backed compatibility harness), code quality (fmt, Clippy, actionlint, yamllint, optional Sonar scan), and security scans (cargo audit+cargo deny). - Deep Testing (
.github/workflows/deep-testing.yml) is scheduled weekly to run the fuzz harnesses (requires the Rust nightly toolchain) and, on the first of each month, mutation tests. - SonarQube / SonarCloud (
.github/workflows/sonar.yml) is ready to analyse the workspace. Provide aSONAR_TOKENrepository secret and, if needed,SONAR_HOST_URLbefore enabling the workflow; adjustsonar-project.propertieswith your actual organisation/project keys. - Renovate Bot (
renovate.json) is configured to group weekly Rust and Go dependency updates. Install the Renovate GitHub App (or hook through GitHub Actions) to activate automated PRs. - CodeRabbit (
.coderabbit.yaml) supplies default review hints for pull requests. Once the CodeRabbit GitHub App is installed, it will auto-review changes that touch the Rust crates or the Go oracle code.
Using the helper crates
A typical integration wires the engine, default Go helpers, and Sprig helpers together before parsing templates:
use ;
use install_sprig_functions;
let mut builder = new;
install_text_template_functions; // Go defaults (`eq`, `printf`, ...)
install_sprig_functions; // Sprig helpers (flow, strings, lists)
let registry = builder.build;
let tmpl = parse_with_functions?;
let rendered = tmpl.render?;
assert_eq!;
Run the ready-made example to see a fuller template in action:
cargo run --example flow_and_lists --package lithos-sprig
When you need a read-only view of helper usage, call Template::analyze() and
inspect the returned TemplateAnalysis. It reports function invocations,
variable paths, template calls, and control structures, allowing downstream
systems to reason about dynamic helper requirements without executing the
template.
The Sprig layer is organised the same way as the upstream documentation:
- Flow control:
default,coalesce,ternary,empty,fail, and JSON helpers (fromJson,toJson, plus themust*variants). - Strings: case conversion, trim/affix helpers,
contains,replace,substr,trunc,wrap,indent/nindent,nospace, andrepeat. - String slices:
splitList,split,splitn,join, andsortAlpha. - Lists:
list,first/last/rest/initial,append/prepend/concat,reverse,compact,uniq,without, andhas. - Maps:
dict,merge,set,unset,hasKey,keys, andvalues. Our implementation sorts the outputs ofkeysandvaluesto guarantee deterministic results, deviating from Go’s unspecified map iteration order.
We intentionally omit Sprig helpers that rely on randomness, regular expressions, or pluralisation until downstream demand materialises.
See docs/function-coverage.md for the full helper matrix, including the Go
defaults handled by lithos-gotmpl-core.
Compatibility & Limitations
- Behaviour is intentionally focused on the subset of Go templates that our
downstream tooling depends on. We do not support every construct that
text/templateprovides (for exampleelse if,define/template, or keyword helpers such asbreak). Seedocs/template-syntax-coverage.mdfor the current status. - The project is not affiliated with or endorsed by the Go project or by the Masterminds/sprig maintainers. Compatibility tests rely on their public implementations for reference only.
- The Go-based
go-sanityrunner is an optional development aid. It requires a local Go toolchain and honours the upstream sprig licence. CI and local workflows should treat it as a verification step rather than a runtime dependency of the crates.
Roadmap
- Flesh out additional helpers based on the needs of downstream consumers. Each new helper should add test cases and assertions to keep the Go sanity checks in sync.
- Explore publishing the helper registry as a trait or adapter
- Eventually wire in property tests for string/collection helpers once coverage expands.
Attribution & Notices
This workspace includes test materials derived from the Go programming language
(text/template) and uses Masterminds' sprig library inside the go-sanity
tool. Full attribution details are recorded in NOTICE.
License
All crates in this workspace are dual-licensed under either the Apache License
2.0 or the MIT License. You may choose either licence to use the code. Copies of
both licences are provided in LICENSE-APACHE and
LICENSE-MIT. Unless otherwise stated, contributions are
accepted under the same dual-licence terms.