Agent Context: xpool
May 25, 2026 · View on GitHub
This document provides an architectural overview, development workflows, and coding conventions for the xpool project, for any coding agent or contributor.
Project Overview
xpool is a tiny, type-safe generic wrapper around the standard library's
sync.Pool. It removes the interface{} /
any casting boilerplate of sync.Pool and adds first-class support for
resettable ("monadic") objects. It targets Go 1.18+ (generics) and has no
production dependencies beyond testify (used only in tests).
The library is organized in two layers: a niladic core (xpool, repo root)
and a monadic layer (monadic) that composes it for objects whose reset
takes an argument.
Core Package (xpool, repo root)
The foundation, in pool.go. It deals only with a generic type T and never
needs reflection.
Pool[T]: the central interface —Get() T/Put(T). For convenience, a*sync.Poolalready satisfiesPool[any](asserted atpool.go:22).New: plain pool with no reset behavior.NewWithResetter: constrainsTto theResetterinterface (Reset()) and calls it before eachPut.NewWithCustomResetter: takes an arbitraryfunc(T)reset callback (must be thread-safe; panics if nil). Useful for logging, tracing, or non-Resettertypes.NewWithFallibleResetter: takes afunc(T) errorreset callback plus an optionalfunc(err error, object T)error handler. If the reset fails onPut, the object is dropped (not pooled) and the handler is invoked. Panics if the resetter is nil.- Internals:
simplePool[T]wraps a*sync.Pool, storing values asanyand type-asserting onGetwith actor()fallback when the pool is empty.resettablePool[T]decorates anotherPool[T], running the reset callback before delegatingPut.fallibleResettablePool[T]is the error-aware variant.
Monadic Package (monadic)
For objects whose reset takes a value — e.g. bytes.Reader.Reset(b) or
gzip.Writer.Reset(w). In monadic/pool.go.
Pool[S, T]:Get(state S) T/Put(T).Getresets the object with the state;Putresets it back to the zero value of S (the unit of delivery returns clean).New: constrainsTtoResetter[S](Reset(state S)).NewWithCustomResetter: takes afunc(object T, state S)resetter, letting you adapt types whose reset signature differs (see theflate.Resetterexample inmonadic/pool_test.go).NewWithFallibleResetter: takes afunc(object T, state S) errorresetter plus an optional error handler. OnGetfailure the pooled object is discarded and rebuilt viactor(best effort); onPutfailure the object is dropped. Each failure is reported to the handler. Panics if the resetter is nil.- Internals: built on top of
xpool.NewWithCustomResetter— the monadic pool supplies the on-put resetter (zero value ofS) to the core pool and applies the on-get resetter itself inresettableMonadicPool.Get. The fallible variant (fallibleMonadicPool[S, T]) layers onxpool.NewWithFallibleResetter.
Key design point: a resetter is optional in xpool but mandatory in
monadic. If you don't want a resetter, use a plain xpool.Pool.
Building and Running
The project uses Task for workflow automation. A
Makefile is provided as a thin proxy to task.
| Command | Description |
|---|---|
task test | Runs all tests using gotestsum. |
task test:race | Runs tests with the race detector. |
task test:coverage | Runs tests with race + atomic coverage into coverage.txt. |
task lint | Executes golangci-lint with the project's configuration. |
task lint:fix | Runs golangci-lint run --fix. |
task format | Formats the codebase via golangci-lint fmt (gofumpt, goimports, gci). |
task consistent | Checks code-pattern consistency with go-consistent. |
task tidy | Runs go mod tidy. |
task tidy:check | Fails if go.mod/go.sum are not tidy. |
task ci | Full pre-push gate: tidy:check + lint + consistent + build + test. |
task changelog | Regenerates CHANGELOG.md using git-cliff. |
Prerequisites
- Go 1.18+ (CI tests every minor version from 1.18 through 1.25, plus
stable) task(Taskfile runner)golangci-lintv2 (CI pinsv2.12.2)gotestsum(used by the test tasks)go-consistent(go install github.com/quasilyte/go-consistent@latest)git-cliff(only for regenerating the changelog)
Development Conventions
Coding Style
- Follow standard Go idioms and effective Go practices.
- Formatting: Run
task format. The project usesgofumpt,goimports, andgcifor import ordering (Standard → Default →github.com/peczenyj/xpool). - Linting: Enforced via
.golangci.yml(golangci-lint v2 config). Always runtask lintbefore submitting changes. Enabled linters beyond the standard set includegocritic,revive,misspell,gocyclo,bodyclose,errorlint, andprealloc. - Go version floor: Do not use language or stdlib features newer than Go 1.18 — the CI matrix builds against it.
Testing Practices
- Tests live alongside the source in
*_test.gofiles; runnable examples (Example*) double as documentation and are verified by their// Output:. - Use
testifyfor assertions andtesting/quickfor property checks (seemonadic/pool_test.go). - Coverage is expected to stay at/near 100% (
.codecov.ymlsets a 90% floor).
Releases & Changelog
- Commit messages follow Conventional Commits;
git-cliff(cliff.toml) groups them intoCHANGELOG.md. Runtask changelogbefore tagging a release. - Tagging
v*triggers.github/workflows/release.yml, which publishes a source archive with SHA256 checksums and SLSA build provenance.