{"id":47704427,"url":"https://github.com/flaticols/resetgen","last_synced_at":"2026-04-02T17:50:26.709Z","repository":{"id":328872542,"uuid":"1116194333","full_name":"flaticols/resetgen","owner":"flaticols","description":"Go code generator for allocation-free Reset() methods, optimized for sync.Pool usage","archived":false,"fork":false,"pushed_at":"2025-12-15T22:56:16.000Z","size":47,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"latest","last_synced_at":"2025-12-19T07:11:26.311Z","etag":null,"topics":["code-generator","go","go-generate","golang","performance","sync-pool","zero-allocation"],"latest_commit_sha":null,"homepage":"","language":"Go","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/flaticols.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-14T11:46:45.000Z","updated_at":"2025-12-15T22:56:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/flaticols/resetgen","commit_stats":null,"previous_names":["flaticols/resetgen"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/flaticols/resetgen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flaticols%2Fresetgen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flaticols%2Fresetgen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flaticols%2Fresetgen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flaticols%2Fresetgen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flaticols","download_url":"https://codeload.github.com/flaticols/resetgen/tar.gz/refs/heads/latest","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flaticols%2Fresetgen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31312744,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["code-generator","go","go-generate","golang","performance","sync-pool","zero-allocation"],"created_at":"2026-04-02T17:50:24.837Z","updated_at":"2026-04-02T17:50:26.699Z","avatar_url":"https://github.com/flaticols.png","language":"Go","readme":"# resetgen\n\nGenerate allocation-free `Reset()` methods for your structs. Perfect for [`sync.Pool`](https://pkg.go.dev/sync) usage.\n\n## Tools\n\nThis project provides two tools:\n\n| Tool | Description |\n|------|-------------|\n| `resetgen` | Code generator — creates `Reset()` methods from struct tags |\n| `resetgen-analyzer` | Static analyzer — detects missing `Reset()` calls before `sync.Pool.Put()` |\n\n---\n\n## resetgen (Code Generator)\n\n### Installation\n\n```bash\ngo install github.com/flaticols/resetgen@latest\n```\n\nOr add as a tool dependency (Go 1.24+):\n\n```bash\ngo get -tool github.com/flaticols/resetgen@latest\n```\n\n### Go 1.24+ Tool Mechanism\n\nGo 1.24 introduced the ability to manage CLI tools as dependencies. You can declare tool requirements in `go.mod`:\n\n```go\ntool (\n    github.com/flaticols/resetgen\n)\n```\n\nRun with `go tool`:\n\n```bash\n# Generate from current package\ngo tool resetgen\n\n# Generate from specific packages\ngo tool resetgen ./...\ngo tool resetgen ./cmd ./internal\n\n# With flags\ngo tool resetgen -structs User,Order ./...\ngo tool resetgen -version\n```\n\nThis approach keeps your tool versions synchronized with your project, just like regular dependencies.\n\n### Usage\n\nAdd `reset` tags to your struct fields and run the generator:\n\n```go\n//go:generate resetgen\n\npackage main\n\ntype Request struct {\n    ID      string            `reset:\"\"`\n    Method  string            `reset:\"GET\"`\n    Headers map[string]string `reset:\"\"`\n    Body    []byte            `reset:\"\"`\n}\n```\n\nRun:\n\n```bash\ngo generate ./...\n```\n\nGenerated `request.gen.go`:\n\n```go\nfunc (s *Request) Reset() {\n    s.ID = \"\"\n    s.Method = \"GET\"\n    clear(s.Headers)      // preserves capacity\n    s.Body = s.Body[:0]   // preserves capacity\n}\n```\n\n## Tag Syntax\n\n| Tag | Behavior |\n|-----|----------|\n| `reset:\"\"` | Zero value |\n| `reset:\"value\"` | Default value |\n| `reset:\"-\"` | Skip field |\n\n## CLI Flag Syntax\n\n### `-structs` Flag\n\nSpecify which structs to generate using the `-structs` flag:\n\n```bash\n//go:generate resetgen -structs User,Order,Config\n\n# Or with multiple files\nresetgen -structs User,Order,Config ./...\n```\n\nWhen `-structs` is specified:\n- **ONLY** the listed structs are processed (tags and directives are ignored for struct selection)\n- All exported fields are reset to zero values\n- Field-level `reset` tags still work for custom values or to skip specific fields\n\n**Example:**\n```go\n//go:generate resetgen -structs User,Order\n\ntype User struct {\n    ID      int64\n    Name    string\n    Secret  string `reset:\"-\"` // Still respected - field will not be reset\n}\n\ntype Order struct {\n    ID    int64\n    Items []string\n    Total float64 `reset:\"0.0\"` // Custom value still works\n}\n\ntype Logger struct {\n    Level string  // Will NOT be generated (not in -structs list)\n}\n```\n\n### Package-Qualified Names\n\nWhen you have structs with the same name in different packages, use package-qualified names:\n\n```bash\n# Process User in models package only\nresetgen -structs models.User ./...\n\n# Process User in both models and api packages\nresetgen -structs models.User,api.User ./...\n\n# Mix simple and qualified names\nresetgen -structs Order,models.User ./...\n```\n\n**Rules:**\n- Simple name (`User`) → processes ALL User structs in all packages\n- Qualified name (`models.User`) → processes only User in models package\n- Package path uses Go import path format (lowercase with dots/slashes)\n\n**Example with multiple packages:**\n```go\n// models/user.go\n//go:generate resetgen -structs models.User,api.User\n\npackage models\n\ntype User struct {\n    ID    int64  `reset:\"\"`\n    Name  string `reset:\"\"`\n    Email string `reset:\"\"`\n}\n\n// api/user.go\n//go:generate resetgen -structs models.User,api.User\n\npackage api\n\ntype User struct {\n    ID       string `reset:\"\"`\n    Status   string `reset:\"active\"`\n}\n```\n\nBoth packages can use the same go:generate directive with package-qualified names, and each will generate only its own Reset() method.\n\n## Directive Syntax\n\nUse the `+resetgen` comment directive to mark structs for automatic `Reset()` generation without tagging every field:\n\n```go\n//go:generate resetgen\n\npackage main\n\n// +resetgen\ntype Request struct {\n    ID      string            // defaults to zero value\n    Method  string            // defaults to zero value\n    Headers map[string]string // defaults to zero value\n    Secret  string `reset:\"-\"` // skipped from reset\n}\n```\n\nGenerated `request.gen.go`:\n\n```go\nfunc (s *Request) Reset() {\n    s.ID = \"\"\n    s.Method = \"\"\n    clear(s.Headers)  // preserves capacity\n    // Secret is not reset (reset:\"-\")\n}\n```\n\n### How Directive Works\n\n- **Struct Selection**: Structs are processed if they have a `+resetgen` comment OR contain `reset` tags\n- **Field Processing**: All exported fields are reset to zero values\n- **Custom Values**: Fields with explicit `reset` tags use their specified values\n- **Skip Fields**: Use `reset:\"-\"` to exclude specific fields from reset\n- **Unexported Fields**: Private fields (lowercase) are automatically skipped for safety\n\n### Directive Formats\n\nAll of these are recognized:\n- `//+resetgen`\n- `// +resetgen`\n- `//  +resetgen`\n- `/* +resetgen */`\n\n## Features\n\n- **Allocation-free** — slices truncate (`s[:0]`), maps clear (`clear(m)`)\n- **Embedded structs** — calls `Reset()` recursively\n- **Selective** — only structs with `reset` tags are processed\n- **Fast** — single-pass AST, minimal allocations\n\n\u003e [!TIP]\n\u003e Structs without any `reset` tags are automatically ignored. You can have pooled and regular structs in the same file.\n\n## Resetter Interface\n\nDefine a common interface for pooled objects:\n\n```go\ntype Resetter interface {\n    Reset()\n}\n```\n\nAll generated `Reset()` methods satisfy this interface, enabling generic pool helpers.\n\n## sync.Pool Examples\n\n### Example 1: HTTP Request Pool\n\n```go\n//go:generate resetgen\n\npackage server\n\ntype Request struct {\n    Path    string            `reset:\"\"`\n    Method  string            `reset:\"GET\"`\n    Headers map[string]string `reset:\"\"`\n    Body    []byte            `reset:\"\"`\n    UserID  int               `reset:\"\"`\n}\n\nvar requestPool = sync.Pool{\n    New: func() any { return new(Request) },\n}\n\nfunc HandleRequest(path, method string, body []byte) {\n    req := requestPool.Get().(*Request)\n\n    req.Path = path\n    req.Method = method\n    req.Body = append(req.Body, body...)\n\n    process(req)\n\n    req.Reset()\n    requestPool.Put(req)\n}\n```\n\n### Example 2: Generic Pool with Resetter\n\n```go\n//go:generate resetgen\n\npackage pool\n\ntype Resetter interface {\n    Reset()\n}\n\n// Pool is a generic, allocation-free pool for any Resetter\ntype Pool[T Resetter] struct {\n    p sync.Pool\n}\n\nfunc NewPool[T Resetter](newFn func() T) *Pool[T] {\n    return \u0026Pool[T]{\n        p: sync.Pool{New: func() any { return newFn() }},\n    }\n}\n\nfunc (p *Pool[T]) Get() T      { return p.p.Get().(T) }\nfunc (p *Pool[T]) Put(v T)     { v.Reset(); p.p.Put(v) }\n```\n\nUsage with a buffer:\n\n```go\n//go:generate resetgen\n\npackage encoding\n\ntype Buffer struct {\n    data []byte `reset:\"\"`\n}\n\nvar bufPool = pool.NewPool(func() *Buffer { return new(Buffer) })\n\n// MarshalTo writes encoded data directly to dst — zero allocations\nfunc MarshalTo(dst io.Writer, v any) error {\n    buf := bufPool.Get()\n\n    buf.data = encodeJSON(buf.data, v)\n    _, err := dst.Write(buf.data)\n\n    bufPool.Put(buf)\n    return err\n}\n```\n\n\u003e [!NOTE]\n\u003e Both examples avoid defer closures and return values that reference pooled memory.\n\n---\n\n## resetgen-analyzer (Static Analyzer)\n\nDetects when `sync.Pool.Put()` is called without a preceding `Reset()` call.\n\n### Installation\n\n```bash\ngo install github.com/flaticols/resetgen/cmd/resetgen-analyzer@latest\n```\n\nOr add as a tool dependency (Go 1.24+):\n\n```bash\ngo get -tool github.com/flaticols/resetgen/cmd/resetgen-analyzer\n```\n\n### Usage\n\nRun standalone:\n\n```bash\nresetgen-analyzer ./...\n```\n\nRun with `go vet`:\n\n```bash\ngo vet -vettool=$(which resetgen-analyzer) ./...\n```\n\nAdd to your CI pipeline or Makefile:\n\n```makefile\n.PHONY: lint\nlint:\n\tgo vet -vettool=$(which resetgen-analyzer) ./...\n```\n\n### What it detects\n\n```go\nfunc BadUsage() {\n    buf := bufferPool.Get().(*Buffer)\n    buf.data = append(buf.data, \"hello\"...)\n    bufferPool.Put(buf) // ERROR: sync.Pool.Put() called without Reset() on buf\n}\n\nfunc GoodUsage() {\n    buf := bufferPool.Get().(*Buffer)\n    buf.data = append(buf.data, \"hello\"...)\n    buf.Reset()\n    bufferPool.Put(buf) // OK\n}\n```\n\n### Detected patterns\n\n| Pattern | Example |\n|---------|---------|\n| Global pool | `bufferPool.Put(buf)` without `buf.Reset()` |\n| Struct field pool | `s.pool.Put(buf)` without `buf.Reset()` |\n| Wrapped variable | `pool.Put(w.buf)` without `w.buf.Reset()` |\n| Pool wrapper | `p.p.Put(v)` without `v.Reset()` inside wrapper method |\n\n## Benchmarks\n\n```\nBenchmarkReset-8    1000000000    0.32 ns/op    0 B/op    0 allocs/op\n```\n\n## License\n\n[MIT](LICENSE)\n\n---\n\n\u003cp align=\"center\"\u003eMade with ❤️ by Denis\u003c/p\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflaticols%2Fresetgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflaticols%2Fresetgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflaticols%2Fresetgen/lists"}