{"id":24493354,"url":"https://github.com/peczenyj/xpool","last_synced_at":"2025-04-14T02:07:30.333Z","repository":{"id":245843207,"uuid":"819334791","full_name":"peczenyj/xpool","owner":"peczenyj","description":"Yet another golang type safe object pool using generics","archived":false,"fork":false,"pushed_at":"2025-03-24T15:28:31.000Z","size":96,"stargazers_count":4,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-14T02:07:24.556Z","etag":null,"topics":["generics","go","golang","object-pool","type-safety"],"latest_commit_sha":null,"homepage":"https://github.com/peczenyj/xpool","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/peczenyj.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-24T09:50:18.000Z","updated_at":"2025-03-24T15:19:03.000Z","dependencies_parsed_at":"2025-03-24T16:36:10.411Z","dependency_job_id":null,"html_url":"https://github.com/peczenyj/xpool","commit_stats":null,"previous_names":["peczenyj/xpool"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peczenyj%2Fxpool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peczenyj%2Fxpool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peczenyj%2Fxpool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peczenyj%2Fxpool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peczenyj","download_url":"https://codeload.github.com/peczenyj/xpool/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248809044,"owners_count":21164896,"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":["generics","go","golang","object-pool","type-safety"],"created_at":"2025-01-21T19:39:23.827Z","updated_at":"2025-04-14T02:07:30.309Z","avatar_url":"https://github.com/peczenyj.png","language":"Go","readme":"# xpool\n\n[![tag](https://img.shields.io/github/tag/peczenyj/xpool.svg)](https://github.com/peczenyj/xpool/releases)\n![Go Version](https://img.shields.io/badge/Go-%3E%3D%201.18-%23007d9c)\n[![GoDoc](https://pkg.go.dev/badge/github.com/peczenyj/xpool)](http://pkg.go.dev/github.com/peczenyj/xpool)\n[![Go](https://github.com/peczenyj/xpool/actions/workflows/go.yml/badge.svg)](https://github.com/peczenyj/xpool/actions/workflows/go.yml)\n[![Lint](https://github.com/peczenyj/xpool/actions/workflows/lint.yml/badge.svg)](https://github.com/peczenyj/xpool/actions/workflows/lint.yml)\n[![codecov](https://codecov.io/gh/peczenyj/xpool/graph/badge.svg?token=9y6f3vGgpr)](https://codecov.io/gh/peczenyj/xpool)\n[![Report card](https://goreportcard.com/badge/github.com/peczenyj/xpool)](https://goreportcard.com/report/github.com/peczenyj/xpool)\n[![CodeQL](https://github.com/peczenyj/xpool/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/peczenyj/xpool/actions/workflows/github-code-scanning/codeql)\n[![Dependency Review](https://github.com/peczenyj/xpool/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/peczenyj/xpool/actions/workflows/dependency-review.yml)\n[![License](https://img.shields.io/github/license/peczenyj/xpool)](./LICENSE)\n[![Latest release](https://img.shields.io/github/release/peczenyj/xpool.svg)](https://github.com/peczenyj/xpool/releases/latest)\n[![GitHub Release Date](https://img.shields.io/github/release-date/peczenyj/xpool.svg)](https://github.com/peczenyj/xpool/releases/latest)\n[![Last commit](https://img.shields.io/github/last-commit/peczenyj/xpool.svg)](https://github.com/peczenyj/xpool/commit/HEAD)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/peczenyj/xpool/blob/main/CONTRIBUTING.md#pull-request-process)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#utilities)\n\nThe xpool is a user-friendly, type-safe version of [sync.Pool](https://pkg.go.dev/sync#Pool).\n\nInspired by [xpool](https://pkg.go.dev/go.unistack.org/micro/v3/util/xpool)\n\n## Definition\n\nThis package defines an interface `Pool[T any]`\n\n```go\n// Pool is a type-safe object pool interface.\n// for convenience, *sync.Pool is a Pool[any]\ntype Pool[T any] interface {\n    // Get fetch one item from object pool\n    // If needed, will create another object.\n    Get() T\n\n    // Put return the object to the pull.\n    // It may reset the object before put it back to sync pool.\n    Put(object T)\n}\n```\n\nIn such way that `*sync.Pool` is a `Pool[any]`\n\n## Usage\n\nImagine you need a pool of [io.ReadWrite](https://pkg.go.dev/io#ReadWriter) interfaces implemented by [bytes.Buffer](https://pkg.go.dev/bytes#Buffer). You don't need to cast from `interface{}` `any`more, just do:\n\n```go\n    pool := xpool.New(func() io.ReadWriter {\n        return new(bytes.Buffer)\n    })\n\n    rw := pool.Get()\n    defer pool.Put(rw)\n\n    // now you can use a new io.ReadWrite instance\n```\n\ninstead using pure go\n\n```go\n    pool := \u0026sync.Pool{\n        New: func() any {\n            return new(bytes.Buffer)\n        },\n    }\n\n    rw, _ := pool.Get().(io.ReadWriter)\n    defer pool.Put(rw)\n\n    // now you can use a new io.ReadWrite instance\n```\n\nObject pools are perfect for that are simple to create, like the ones that have a constructor with no parameters. If we need to specify parameters to create one object, then each combination of parameters may create a different object and they are not easy to use from an object pool.\n\nThere are two possible approaches:\n\n* map all possible parameters and create one object pool for combination.\n* create monadic object that can be easily created and a particular state can be set via some methods.\n\nThe second approach we call \"Resettable Objects\".\n\n## Dealing with monadic Resettable Objects\n\nObject pools are perfect for stateless objects, however when dealing with monadic objects we need to be extra careful with the object state. Fortunately, we have some objects that we can easily reset the state before reuse.\n\nSome classes of objects like [hash.Hash](https://pkg.go.dev/hash#Hash) and [bytes.Buffer](https://pkg.go.dev/bytes#Buffer) we can call a method `Reset()` to return the object to his initial state. Others such [bytes.Reader](https://pkg.go.dev/bytes#Reader) and [gzip.Writer](https://pkg.go.dev/compress/gzip#Writer) have a special meaning for a `Reset(state S)` to be possible reuse the same object instead create a new one.\n\nWe define two forms of Reset:\n\nThe Niladic interface, where `Reset()` receives no arguments (for instance, the `hash.Hash` case) to be executed before put the object back to the pool.\n\n```go\n// Resetter interface.\ntype Resetter interface {\n    Reset()\n}\n```\n\nAnd the Monadic interface, where `Reset(S)` receives one single argument (for instance, the `gzip.Writer` case) to be executed when we fetch an object from the pool and initialize with a value of type S, and will be resetted back to a zero value of S before put the object back to the pool.\n\n```go\n// Resetter interface.\ntype Resetter[S any] interface {\n    Reset(state S)\n}\n```\n\nMonadic resetters are handling by package [xpool/monadic](https://pkg.go.dev/github.com/peczenyj/xpool/monadic).\n\nImportant: you may not want to expose objects with a `Reset` method, the xpool will not ensure that the type `T` is a `Resetter[S]` unless you use the `NewWithResetter` constructor.\n\n### Examples\n\nCalling `Reset()` before put it back to the pool of objects, on [xpool](https://pkg.go.dev/github.com/peczenyj/xpool) package:\n\n```go\n    var pool xpool.Pool[hash.Hash] = xpool.NewWithResetter(func() hash.Hash {\n        return sha256.New()\n    })\n\n    hasher := pool.Get()   // get a new hash.Hash interface\n    defer pool.Put(hasher) // reset it with nil before put back to sync pool.\n\n    _, _ = hasher.Write(p)\n\n    value := hasher.Sum(nil)\n```\n\nCalling `Reset(v)` with some value when acquire the instance and `Reset( \u003czero value\u003e )` before put it back to the pool of objects, on [xpool/monadic](https://pkg.go.dev/github.com/peczenyj/xpool/monadic) package:\n\n```go\n    // this constructor can't infer type S, so you should be explicit!\n    var pool monadic.Pool[[]byte,*bytes.Reader] = monadic.New[[]byte](\n        func() *bytes.Reader {\n            return bytes.NewReader(nil)\n        },\n    )\n\n    reader := pool.Get([]byte(`payload`)) // reset the bytes.Reader with payload\n    defer pool.Put(reader)                // reset the bytes.Reader with nil\n\n    content, err := io.ReadAll(reader)\n```\n\n### Custom Resetters\n\nIt is possible set a custom thread-safe Resetter, instead just call `Reset()` or `Reset(v)`, via a custom resette, instead use the default one.\n\non [xpool](https://pkg.go.dev/github.com/peczenyj/xpool) package:\n\n```go\n    //besides the log, both calls are equivalent\n\n    pool:= xpool.NewWithCustomResetter(sha256.New, \n        func(h hash.Hash) {\n            h.Reset()\n\n            log.Println(\"just reset the hash.Hash\")\n        },\n    ),\n\n    // the default resetter try to call `Reset()` method.\n    pool:=  xpool.NewWithDefaultResetter(sha256.New),\n```\n\non [xpool/monadic](https://pkg.go.dev/github.com/peczenyj/xpool/monadic) package:\n\n```go\n    // besides the log, both calls are equivalent\n    \n    // the monadic pool will try to call `Reset([]byte)` method by default.\n    pool:= monadic.New[[]byte](func() *bytes.Reader {\n        return bytes.NewReader(nil)\n    })\n\n    // the monadic pool will try to call the specific resetter callback.\n    pool:= monadic.NewWithCustomResetter(func() *bytes.Reader {\n        return bytes.NewReader(nil)\n    }, func(object *bytes.Reader, state []byte) {\n        object.Reset(state)\n\n        log.Println(\"just reset the *bytes.Buffer\")\n    })\n```\n\nYou can use custom resetters to handle more complex types of Reset. For instance, the [flate.NewReader](https://pkg.go.dev/compress/flate#NewReader) returns an [io.ReadCloser](https://pkg.go.dev/io#ReadCloser) that also implements [flate.Resetter](https://pkg.go.dev/compress/flate#Resetter) that supports a different kind of `Reset()` that expect two arguments and also returns an error.\n\nIf we can discard the error and set the second parameter a constant value like nil, we can:\n\n```go\n    // can infer types from resetter\n    poolReader := monadic.NewWithCustomResetter(func() io.ReadCloser {\n        return flate.NewReader(nil)\n    }, func(object io.ReadCloser, state io.Reader) {\n        if resetter, ok := any(object).(flate.Resetter); ok {\n            _ = resetter.Reset(state, nil)\n        }\n    })\n```\n\nAn alternative can be create an object to hold different arguments like in the example below:\n\n```go\n    type flateResetterArgs struct {\n        r    io.Reader\n        dict []byte\n    }\n    // can infer type S from resetter\n    poolReader := monadic.NewWithCustomResetter(func() io.ReadCloser {\n        return flate.NewReader(nil)\n    }, func(object io.ReadCloser, state *flateResetterArgs) {\n        if resetter, ok := any(object).(flate.Resetter); ok {\n            _ = resetter.Reset(state.r, state.dict)\n        }\n    })\n```\n\nCustom resetters can do more than just set the status of the object, they can be used to log, trace and extract metrics.\n\n## Important\n\nOn [xpool](https://pkg.go.dev/github.com/peczenyj/xpool) the resetter is optional, while on [xpool/monadic](https://pkg.go.dev/github.com/peczenyj/xpool/monadic) this is mandatory. If you don't want to have resetters on a monadic xpool, please create a regular `xpool.Pool`.\n","funding_links":[],"categories":["Utilities","公用事业公司"],"sub_categories":["Utility/Miscellaneous","实用程序/Miscellaneous"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeczenyj%2Fxpool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeczenyj%2Fxpool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeczenyj%2Fxpool/lists"}