mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-28 23:52:25 -05:00
[chore] update dependencies (#4386)
- codeberg.org/gruf/go-bytesize v1.0.3 -> v1.0.4 - codeberg.org/gruf/go-kv/v2 v2.0.6 -> v2.0.7 - codeberg.org/gruf/go-mutexes v1.5.2 -> v1.5.3 - codeberg.org/gruf/go-structr v0.9.7 -> v0.9.8 - codeberg.org/gruf/go-ffmpreg v0.6.8 -> v0.6.9 - github.com/tomnomnom/linkheader HEAD@2018 -> HEAD@2025 all of the above codeberg.org/gruf updates are in preparation for Go1.25, except for bytesize, and also ffmpreg which is a rebuild with the latest version of ffmpeg (v5.1.7) Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4386 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
8c619d51b5
commit
a79f83cbde
38 changed files with 1246 additions and 964 deletions
16
go.mod
16
go.mod
|
|
@ -14,24 +14,25 @@ require (
|
|||
code.superseriousbusiness.org/httpsig v1.4.0
|
||||
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384
|
||||
codeberg.org/gruf/go-bitutil v1.1.0
|
||||
codeberg.org/gruf/go-bytesize v1.0.3
|
||||
codeberg.org/gruf/go-bytesize v1.0.4
|
||||
codeberg.org/gruf/go-byteutil v1.3.0
|
||||
codeberg.org/gruf/go-cache/v3 v3.6.1
|
||||
codeberg.org/gruf/go-caller v0.0.0-20250806133437-db8d0b1f71cf
|
||||
codeberg.org/gruf/go-debug v1.3.0
|
||||
codeberg.org/gruf/go-errors/v2 v2.3.2
|
||||
codeberg.org/gruf/go-fastcopy v1.1.3
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.8
|
||||
codeberg.org/gruf/go-fastpath/v2 v2.0.0
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.9
|
||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
||||
codeberg.org/gruf/go-kv/v2 v2.0.6
|
||||
codeberg.org/gruf/go-kv/v2 v2.0.7
|
||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
||||
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
|
||||
codeberg.org/gruf/go-mutexes v1.5.2
|
||||
codeberg.org/gruf/go-mutexes v1.5.3
|
||||
codeberg.org/gruf/go-runners v1.6.3
|
||||
codeberg.org/gruf/go-sched v1.2.4
|
||||
codeberg.org/gruf/go-split v1.2.0
|
||||
codeberg.org/gruf/go-storage v0.3.1
|
||||
codeberg.org/gruf/go-structr v0.9.7
|
||||
codeberg.org/gruf/go-structr v0.9.8
|
||||
github.com/DmitriyVTitov/size v1.5.0
|
||||
github.com/KimMachineGun/automemlimit v0.7.4
|
||||
github.com/SherClockHolmes/webpush-go v1.4.0
|
||||
|
|
@ -66,7 +67,7 @@ require (
|
|||
github.com/technologize/otel-go-contrib v1.1.1
|
||||
github.com/temoto/robotstxt v1.1.2
|
||||
github.com/tetratelabs/wazero v1.9.0
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||
github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e
|
||||
github.com/ulule/limiter/v3 v3.11.2
|
||||
github.com/uptrace/bun v1.2.15
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.2.15
|
||||
|
|
@ -97,9 +98,8 @@ require (
|
|||
require (
|
||||
code.superseriousbusiness.org/go-jpeg-image-structure/v2 v2.3.0 // indirect
|
||||
code.superseriousbusiness.org/go-png-image-structure/v2 v2.3.0 // indirect
|
||||
codeberg.org/gruf/go-fastpath/v2 v2.0.0 // indirect
|
||||
codeberg.org/gruf/go-kv v1.6.5 // indirect
|
||||
codeberg.org/gruf/go-mangler v1.4.4 // indirect
|
||||
codeberg.org/gruf/go-mangler/v2 v2.0.6 // indirect
|
||||
codeberg.org/gruf/go-maps v1.0.4 // indirect
|
||||
codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
|
|
|
|||
28
go.sum
generated
28
go.sum
generated
|
|
@ -12,8 +12,8 @@ code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384 h1:
|
|||
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384/go.mod h1:4x61i4C725jkXOpnUPFNfmiEthF6FZc/byADbalp+F8=
|
||||
codeberg.org/gruf/go-bitutil v1.1.0 h1:U1Q+A1mtnPk+npqYrlRBc9ar2C5hYiBd17l1Wrp2Bt8=
|
||||
codeberg.org/gruf/go-bitutil v1.1.0/go.mod h1:rGibFevYTQfYKcPv0Df5KpG8n5xC3AfD4d/UgYeoNy0=
|
||||
codeberg.org/gruf/go-bytesize v1.0.3 h1:Tz8tCxhPLeyM5VryuBNjUHgKmLj4Bx9RbPaUSA3qg6g=
|
||||
codeberg.org/gruf/go-bytesize v1.0.3/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacpp0OHfkvLPs=
|
||||
codeberg.org/gruf/go-bytesize v1.0.4 h1:LEojK46lUoE748Om7yldx6kLe6jCCuiytz5IZ8vH35g=
|
||||
codeberg.org/gruf/go-bytesize v1.0.4/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacpp0OHfkvLPs=
|
||||
codeberg.org/gruf/go-byteutil v1.3.0 h1:nRqJnCcRQ7xbfU6azw7zOzJrSMDIJHBqX6FL9vEMYmU=
|
||||
codeberg.org/gruf/go-byteutil v1.3.0/go.mod h1:chgnZz1LUcfaObaIFglxF5MRYQkJGjQf4WwVz95ccCM=
|
||||
codeberg.org/gruf/go-cache/v3 v3.6.1 h1:sY1XhYeskjZAuYeMm5R0o4Qymru5taNbzmZPSn1oXLE=
|
||||
|
|
@ -28,26 +28,26 @@ codeberg.org/gruf/go-fastcopy v1.1.3 h1:Jo9VTQjI6KYimlw25PPc7YLA3Xm+XMQhaHwKnM7x
|
|||
codeberg.org/gruf/go-fastcopy v1.1.3/go.mod h1:GDDYR0Cnb3U/AIfGM3983V/L+GN+vuwVMvrmVABo21s=
|
||||
codeberg.org/gruf/go-fastpath/v2 v2.0.0 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0=
|
||||
codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q=
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.8 h1:WkChcYFa8KjLyStoi5CYxldvOCeIG93BVn0tyn7MVo4=
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.8/go.mod h1:tGqIMh/I2cizqauxxNAN+WGkICI0j5G3xwF1uBkyw1E=
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.9 h1:EbadyKAekYwwUlKC+4VBZhhN0iPm2uP3T1nPFSWkFb4=
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.9/go.mod h1:tGqIMh/I2cizqauxxNAN+WGkICI0j5G3xwF1uBkyw1E=
|
||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=
|
||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
|
||||
codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=
|
||||
codeberg.org/gruf/go-kv v1.6.5/go.mod h1:c4PsGqw05bDScvISpK+d31SiDEpBorweCL50hsiK3dc=
|
||||
codeberg.org/gruf/go-kv/v2 v2.0.6 h1:X4NEiTn6b17kJmfrVd+5tuo3owHUGKTha9GsSkqvNZ8=
|
||||
codeberg.org/gruf/go-kv/v2 v2.0.6/go.mod h1:uo6rPR14/ll+SDSU3K7DfINNmWD5NJ0EiahPayOguy0=
|
||||
codeberg.org/gruf/go-kv/v2 v2.0.7 h1:RdTY28NX1N/lc3/ivuasnyqnMdQKwV0es3iqSM/DG44=
|
||||
codeberg.org/gruf/go-kv/v2 v2.0.7/go.mod h1:uo6rPR14/ll+SDSU3K7DfINNmWD5NJ0EiahPayOguy0=
|
||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f h1:Ss6Z+vygy+jOGhj96d/GwsYYDd22QmIcH74zM7/nQkw=
|
||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f/go.mod h1:F9pl4h34iuVN7kucKam9fLwsItTc+9mmaKt7pNXRd/4=
|
||||
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4 h1:IXwfoU7f2whT6+JKIKskNl/hBlmWmnF1vZd84Eb3cyA=
|
||||
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4/go.mod h1:fiO8HE1wjZCephcYmRRsVnNI/i0+mhy44Z5dQalS0rM=
|
||||
codeberg.org/gruf/go-mangler v1.4.4 h1:moQl7FSSLLaByS7w5UP7b3Z7r2ex/F4IpvSp+PyRWK4=
|
||||
codeberg.org/gruf/go-mangler v1.4.4/go.mod h1:mDmW8Ia352RvNFaXoP9K60TgcmCZJtX0j6wm3vjAsJE=
|
||||
codeberg.org/gruf/go-mangler/v2 v2.0.6 h1:c3cwnI6Mi17EAwGSYGNMN6+9PMzaIj2GLAKx9DKZwoI=
|
||||
codeberg.org/gruf/go-mangler/v2 v2.0.6/go.mod h1:CXIm7zAWPdNmZVAGM1NRiF/ekJTPE7YTb8kiRxiEFaQ=
|
||||
codeberg.org/gruf/go-maps v1.0.4 h1:K+Ww4vvR3TZqm5jqrKVirmguZwa3v1VUvmig2SE8uxY=
|
||||
codeberg.org/gruf/go-maps v1.0.4/go.mod h1:ASX7osM7kFwt5O8GfGflcFjrwYGD8eIuRLl/oMjhEi8=
|
||||
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760 h1:m2/UCRXhjDwAg4vyji6iKCpomKw6P4PmBOUi5DvAMH4=
|
||||
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760/go.mod h1:E3RcaCFNq4zXpvaJb8lfpPqdUAmSkP5F1VmMiEUYTEk=
|
||||
codeberg.org/gruf/go-mutexes v1.5.2 h1:rp2o774ApGUVtOHDksqtBiqIcvniVfgFWSazszDluy0=
|
||||
codeberg.org/gruf/go-mutexes v1.5.2/go.mod h1:AnhagsMzUISL/nBVwhnHwDwTZOAxMILwCOG8/wKOblg=
|
||||
codeberg.org/gruf/go-mutexes v1.5.3 h1:RIEy1UuDxKgAiINRMrPxTUWSGW6pFx9DzeJN4WPqra8=
|
||||
codeberg.org/gruf/go-mutexes v1.5.3/go.mod h1:AnhagsMzUISL/nBVwhnHwDwTZOAxMILwCOG8/wKOblg=
|
||||
codeberg.org/gruf/go-runners v1.6.3 h1:To/AX7eTrWuXrTkA3RA01YTP5zha1VZ68LQ+0D4RY7E=
|
||||
codeberg.org/gruf/go-runners v1.6.3/go.mod h1:oXAaUmG2VxoKttpCqZGv5nQBeSvZSR2BzIk7h1yTRlU=
|
||||
codeberg.org/gruf/go-sched v1.2.4 h1:ddBB9o0D/2oU8NbQ0ldN5aWxogpXPRBATWi58+p++Hw=
|
||||
|
|
@ -56,8 +56,8 @@ codeberg.org/gruf/go-split v1.2.0 h1:PmzL23nVEVHm8VxjsJmv4m4wGQz2bGgQw52dgSSj65c
|
|||
codeberg.org/gruf/go-split v1.2.0/go.mod h1:0rejWJpqvOoFAd7nwm5tIXYKaAqjtFGOXmTqQV+VO38=
|
||||
codeberg.org/gruf/go-storage v0.3.1 h1:g66UIM/xXnEk9ejT+W0T9s/PODBZhXa/8ajzeY/MELI=
|
||||
codeberg.org/gruf/go-storage v0.3.1/go.mod h1:r43n/zi7YGOCl2iSl7AMI27D1zcWS65Bi2+5xDzypeo=
|
||||
codeberg.org/gruf/go-structr v0.9.7 h1:yQeIxTjYb6reNdgESk915twyjolydYBqat/mlZrP7bg=
|
||||
codeberg.org/gruf/go-structr v0.9.7/go.mod h1:9k5hYztZ4PsBS+m1v5hUTeFiVUBTLF5VA7d9cd1OEMs=
|
||||
codeberg.org/gruf/go-structr v0.9.8 h1:IouxZ+HPJznegpBmqsJmTu+7ZURwUbnwby/VO6PMaAs=
|
||||
codeberg.org/gruf/go-structr v0.9.8/go.mod h1:5dsazOsIeJyV8Dl2DdSXqCDEZUx3e3dc41N6f2mPtgw=
|
||||
codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73 h1:pRaOwIOS1WSZoPCAvE0H1zpv+D4gF37OVppybffqdI8=
|
||||
codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73/go.mod h1:9wkq+dmHjUhB/0ZxDUWAwsWuXwwGyx5N1dDCB9hpWs8=
|
||||
codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix h1:k76/Th+bruqU/d+dB0Ru466ctTF2aVjKpisy/471ILE=
|
||||
|
|
@ -463,8 +463,8 @@ github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
|||
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
|
||||
github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e h1:tD38/4xg4nuQCASJ/JxcvCHNb46w0cdAaJfkzQOO1bA=
|
||||
github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e/go.mod h1:krvJ5AY/MjdPkTeRgMYbIDhbbbVvnPQPzsIsDJO8xrY=
|
||||
github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
|
||||
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
|
|
|
|||
37
internal/cache/timeline/status.go
vendored
37
internal/cache/timeline/status.go
vendored
|
|
@ -586,6 +586,9 @@ func (t *StatusTimeline) InsertOne(status *gtsmodel.Status, prepared *apimodel.S
|
|||
// status ID, including those that may be a boost of the given status.
|
||||
func (t *StatusTimeline) RemoveByStatusIDs(statusIDs ...string) {
|
||||
keys := make([]structr.Key, len(statusIDs))
|
||||
if len(keys) != len(statusIDs) {
|
||||
panic(gtserror.New("BCE"))
|
||||
}
|
||||
|
||||
// Nil check indices outside loops.
|
||||
if t.idx_ID == nil ||
|
||||
|
|
@ -595,17 +598,12 @@ func (t *StatusTimeline) RemoveByStatusIDs(statusIDs ...string) {
|
|||
|
||||
// Convert statusIDs to index keys.
|
||||
for i, id := range statusIDs {
|
||||
keys[i] = t.idx_ID.Key(id)
|
||||
keys[i] = structr.MakeKey(id)
|
||||
}
|
||||
|
||||
// Invalidate all cached entries with IDs.
|
||||
t.cache.Invalidate(t.idx_ID, keys...)
|
||||
|
||||
// Convert statusIDs to index keys.
|
||||
for i, id := range statusIDs {
|
||||
keys[i] = t.idx_BoostOfID.Key(id)
|
||||
}
|
||||
|
||||
// Invalidate all cached entries as boost of IDs.
|
||||
t.cache.Invalidate(t.idx_BoostOfID, keys...)
|
||||
}
|
||||
|
|
@ -614,6 +612,9 @@ func (t *StatusTimeline) RemoveByStatusIDs(statusIDs ...string) {
|
|||
// account ID, including those that may be boosted by account ID.
|
||||
func (t *StatusTimeline) RemoveByAccountIDs(accountIDs ...string) {
|
||||
keys := make([]structr.Key, len(accountIDs))
|
||||
if len(keys) != len(accountIDs) {
|
||||
panic(gtserror.New("BCE"))
|
||||
}
|
||||
|
||||
// Nil check indices outside loops.
|
||||
if t.idx_AccountID == nil ||
|
||||
|
|
@ -623,17 +624,12 @@ func (t *StatusTimeline) RemoveByAccountIDs(accountIDs ...string) {
|
|||
|
||||
// Convert accountIDs to index keys.
|
||||
for i, id := range accountIDs {
|
||||
keys[i] = t.idx_AccountID.Key(id)
|
||||
keys[i] = structr.MakeKey(id)
|
||||
}
|
||||
|
||||
// Invalidate all cached entries as by IDs.
|
||||
t.cache.Invalidate(t.idx_AccountID, keys...)
|
||||
|
||||
// Convert accountIDs to index keys.
|
||||
for i, id := range accountIDs {
|
||||
keys[i] = t.idx_BoostOfAccountID.Key(id)
|
||||
}
|
||||
|
||||
// Invalidate all cached entries as boosted by IDs.
|
||||
t.cache.Invalidate(t.idx_BoostOfAccountID, keys...)
|
||||
}
|
||||
|
|
@ -642,6 +638,9 @@ func (t *StatusTimeline) RemoveByAccountIDs(accountIDs ...string) {
|
|||
// timeline entries pertaining to status ID, including boosts of given status.
|
||||
func (t *StatusTimeline) UnprepareByStatusIDs(statusIDs ...string) {
|
||||
keys := make([]structr.Key, len(statusIDs))
|
||||
if len(keys) != len(statusIDs) {
|
||||
panic(gtserror.New("BCE"))
|
||||
}
|
||||
|
||||
// Nil check indices outside loops.
|
||||
if t.idx_ID == nil ||
|
||||
|
|
@ -651,7 +650,7 @@ func (t *StatusTimeline) UnprepareByStatusIDs(statusIDs ...string) {
|
|||
|
||||
// Convert statusIDs to index keys.
|
||||
for i, id := range statusIDs {
|
||||
keys[i] = t.idx_ID.Key(id)
|
||||
keys[i] = structr.MakeKey(id)
|
||||
}
|
||||
|
||||
// Unprepare all statuses stored under StatusMeta.ID.
|
||||
|
|
@ -659,11 +658,6 @@ func (t *StatusTimeline) UnprepareByStatusIDs(statusIDs ...string) {
|
|||
meta.prepared = nil
|
||||
}
|
||||
|
||||
// Convert statusIDs to index keys.
|
||||
for i, id := range statusIDs {
|
||||
keys[i] = t.idx_BoostOfID.Key(id)
|
||||
}
|
||||
|
||||
// Unprepare all statuses stored under StatusMeta.BoostOfID.
|
||||
for meta := range t.cache.RangeKeysUnsafe(t.idx_BoostOfID, keys...) {
|
||||
meta.prepared = nil
|
||||
|
|
@ -683,7 +677,7 @@ func (t *StatusTimeline) UnprepareByAccountIDs(accountIDs ...string) {
|
|||
|
||||
// Convert accountIDs to index keys.
|
||||
for i, id := range accountIDs {
|
||||
keys[i] = t.idx_AccountID.Key(id)
|
||||
keys[i] = structr.MakeKey(id)
|
||||
}
|
||||
|
||||
// Unprepare all statuses stored under StatusMeta.AccountID.
|
||||
|
|
@ -691,11 +685,6 @@ func (t *StatusTimeline) UnprepareByAccountIDs(accountIDs ...string) {
|
|||
meta.prepared = nil
|
||||
}
|
||||
|
||||
// Convert accountIDs to index keys.
|
||||
for i, id := range accountIDs {
|
||||
keys[i] = t.idx_BoostOfAccountID.Key(id)
|
||||
}
|
||||
|
||||
// Unprepare all statuses stored under StatusMeta.BoostOfAccountID.
|
||||
for meta := range t.cache.RangeKeysUnsafe(t.idx_BoostOfAccountID, keys...) {
|
||||
meta.prepared = nil
|
||||
|
|
|
|||
63
internal/cache/wrappers.go
vendored
63
internal/cache/wrappers.go
vendored
|
|
@ -20,6 +20,7 @@ package cache
|
|||
import (
|
||||
"slices"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"codeberg.org/gruf/go-cache/v3/simple"
|
||||
"codeberg.org/gruf/go-structr"
|
||||
)
|
||||
|
|
@ -86,22 +87,19 @@ func (c *StructCache[T]) Init(config structr.CacheConfig[T]) {
|
|||
// GetOne calls structr.Cache{}.GetOne(), using a cached structr.Index{} by 'index' name.
|
||||
// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}.
|
||||
func (c *StructCache[T]) GetOne(index string, key ...any) (T, bool) {
|
||||
i := c.index[index]
|
||||
return c.Cache.GetOne(i, i.Key(key...))
|
||||
return c.Cache.GetOne(c.index[index], structr.MakeKey(key...))
|
||||
}
|
||||
|
||||
// Get calls structr.Cache{}.Get(), using a cached structr.Index{} by 'index' name.
|
||||
// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}.
|
||||
func (c *StructCache[T]) Get(index string, keys ...[]any) []T {
|
||||
i := c.index[index]
|
||||
return c.Cache.Get(i, i.Keys(keys...)...)
|
||||
return c.Cache.Get(c.index[index], structr.MakeKeys(keys...)...)
|
||||
}
|
||||
|
||||
// LoadOne calls structr.Cache{}.LoadOne(), using a cached structr.Index{} by 'index' name.
|
||||
// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}.
|
||||
func (c *StructCache[T]) LoadOne(index string, load func() (T, error), key ...any) (T, error) {
|
||||
i := c.index[index]
|
||||
return c.Cache.LoadOne(i, i.Key(key...), load)
|
||||
return c.Cache.LoadOne(c.index[index], structr.MakeKey(key...), load)
|
||||
}
|
||||
|
||||
// LoadIDs calls structr.Cache{}.Load(), using a cached structr.Index{} by 'index' name. Note: this also handles
|
||||
|
|
@ -109,28 +107,26 @@ func (c *StructCache[T]) LoadOne(index string, load func() (T, error), key ...an
|
|||
//
|
||||
// If you need to load multiple cache keys other than by ID strings, please create another convenience wrapper.
|
||||
func (c *StructCache[T]) LoadIDs(index string, ids []string, load func([]string) ([]T, error)) ([]T, error) {
|
||||
i := c.index[index]
|
||||
if i == nil {
|
||||
// we only perform this check here as
|
||||
// we're going to use the index before
|
||||
// passing it to cache in main .Load().
|
||||
panic("missing index for cache type")
|
||||
}
|
||||
|
||||
// Generate cache keys for ID types.
|
||||
keys := make([]structr.Key, len(ids))
|
||||
if len(keys) != len(ids) {
|
||||
panic(gtserror.New("BCE"))
|
||||
}
|
||||
for x, id := range ids {
|
||||
keys[x] = i.Key(id)
|
||||
keys[x] = structr.MakeKey(id)
|
||||
}
|
||||
|
||||
// Pass loader callback with wrapper onto main cache load function.
|
||||
return c.Cache.Load(i, keys, func(uncached []structr.Key) ([]T, error) {
|
||||
uncachedIDs := make([]string, len(uncached))
|
||||
for i := range uncached {
|
||||
uncachedIDs[i] = uncached[i].Values()[0].(string)
|
||||
}
|
||||
return load(uncachedIDs)
|
||||
})
|
||||
// Pass loader callback with
|
||||
// wrapper onto main cache load function.
|
||||
return c.Cache.Load(c.index[index], keys,
|
||||
func(uncached []structr.Key) ([]T, error) {
|
||||
uncachedIDs := make([]string, len(uncached))
|
||||
for i := range uncached {
|
||||
uncachedIDs[i] = uncached[i].Values()[0].(string)
|
||||
}
|
||||
return load(uncachedIDs)
|
||||
})
|
||||
}
|
||||
|
||||
// LoadIDs2Part works as LoadIDs, except using a two-part key,
|
||||
|
|
@ -147,8 +143,11 @@ func (c *StructCache[T]) LoadIDs2Part(index string, id1 string, id2s []string, l
|
|||
|
||||
// Generate cache keys for two-part IDs.
|
||||
keys := make([]structr.Key, len(id2s))
|
||||
if len(keys) != len(id2s) {
|
||||
panic(gtserror.New("BCE"))
|
||||
}
|
||||
for x, id2 := range id2s {
|
||||
keys[x] = i.Key(id1, id2)
|
||||
keys[x] = structr.MakeKey(id1, id2)
|
||||
}
|
||||
|
||||
// Pass loader callback with wrapper onto main cache load function.
|
||||
|
|
@ -164,8 +163,7 @@ func (c *StructCache[T]) LoadIDs2Part(index string, id1 string, id2s []string, l
|
|||
// Invalidate calls structr.Cache{}.Invalidate(), using a cached structr.Index{} by 'index' name.
|
||||
// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}.
|
||||
func (c *StructCache[T]) Invalidate(index string, key ...any) {
|
||||
i := c.index[index]
|
||||
c.Cache.Invalidate(i, i.Key(key...))
|
||||
c.Cache.Invalidate(c.index[index], structr.MakeKey(key...))
|
||||
}
|
||||
|
||||
// InvalidateIDs calls structr.Cache{}.Invalidate(), using a cached structr.Index{} by 'index' name. Note: this also
|
||||
|
|
@ -173,20 +171,17 @@ func (c *StructCache[T]) Invalidate(index string, key ...any) {
|
|||
//
|
||||
// If you need to invalidate multiple cache keys other than by ID strings, please create another convenience wrapper.
|
||||
func (c *StructCache[T]) InvalidateIDs(index string, ids []string) {
|
||||
i := c.index[index]
|
||||
if i == nil {
|
||||
// we only perform this check here as
|
||||
// we're going to use the index before
|
||||
// passing it to cache in main .Load().
|
||||
panic("missing index for cache type")
|
||||
}
|
||||
|
||||
// Generate cache keys for ID types.
|
||||
keys := make([]structr.Key, len(ids))
|
||||
if len(keys) != len(ids) {
|
||||
panic(gtserror.New("BCE"))
|
||||
}
|
||||
for x, id := range ids {
|
||||
keys[x] = i.Key(id)
|
||||
keys[x] = structr.MakeKey(id)
|
||||
}
|
||||
|
||||
// Pass to main invalidate func.
|
||||
c.Cache.Invalidate(i, keys...)
|
||||
c.Cache.Invalidate(c.index[index],
|
||||
keys...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,8 +62,7 @@ func (q *StructQueue[T]) Push(values ...T) {
|
|||
|
||||
// Delete pops (and drops!) all queued entries under index with key.
|
||||
func (q *StructQueue[T]) Delete(index string, key ...any) {
|
||||
i := q.index[index]
|
||||
_ = q.queue.Pop(i, i.Key(key...))
|
||||
_ = q.queue.Pop(q.index[index], structr.MakeKey(key...))
|
||||
}
|
||||
|
||||
// Len: see structr.Queue{}.Len().
|
||||
|
|
|
|||
76
vendor/codeberg.org/gruf/go-bytesize/bytesize.go
generated
vendored
76
vendor/codeberg.org/gruf/go-bytesize/bytesize.go
generated
vendored
|
|
@ -94,8 +94,10 @@ var (
|
|||
// methods for byte sizes in both IEC and SI units.
|
||||
type Size uint64
|
||||
|
||||
// ParseSize will parse a valid Size from given string. Both IEC and SI units are supported.
|
||||
// ParseSize will parse a valid Size from given
|
||||
// string. Both IEC and SI units are supported.
|
||||
func ParseSize(s string) (Size, error) {
|
||||
|
||||
// Parse units from string
|
||||
unit, l, err := parseUnit(s)
|
||||
if err != nil {
|
||||
|
|
@ -121,10 +123,15 @@ func (sz *Size) Set(in string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// AppendText implements encoding.TextAppender{}.
|
||||
func (sz Size) AppendText(b []byte) ([]byte, error) {
|
||||
return sz.AppendFormatIEC(b), nil
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler{}.
|
||||
func (sz *Size) MarshalText() ([]byte, error) {
|
||||
func (sz Size) MarshalText() ([]byte, error) {
|
||||
const maxLen = 7 // max IEC string length
|
||||
return sz.AppendFormatIEC(make([]byte, 0, maxLen)), nil
|
||||
return sz.AppendText(make([]byte, 0, maxLen))
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler{}.
|
||||
|
|
@ -143,8 +150,12 @@ func (sz Size) AppendFormatSI(dst []byte) []byte {
|
|||
dst = itoa(dst, uint64(sz))
|
||||
dst = append(dst, 'B')
|
||||
return dst
|
||||
} // above is fast-path, .appendFormat() is outlined
|
||||
return sz.appendFormat(dst, 1000, &sipows, "B")
|
||||
}
|
||||
f, u := sztof(sz, 1000, sipows)
|
||||
dst = ftoa(dst, f)
|
||||
dst = append(dst, u)
|
||||
dst = append(dst, 'B')
|
||||
return dst
|
||||
}
|
||||
|
||||
// AppendFormatIEC will append IEC formatted size to 'dst'.
|
||||
|
|
@ -153,35 +164,11 @@ func (sz Size) AppendFormatIEC(dst []byte) []byte {
|
|||
dst = itoa(dst, uint64(sz))
|
||||
dst = append(dst, 'B')
|
||||
return dst
|
||||
} // above is fast-path, .appendFormat() is outlined
|
||||
return sz.appendFormat(dst, 1024, &iecpows, "iB")
|
||||
}
|
||||
|
||||
// appendFormat will append formatted Size to 'dst', depending on base, powers table and single unit suffix.
|
||||
func (sz Size) appendFormat(dst []byte, base uint64, pows *[6]float64, sunit string) []byte {
|
||||
const (
|
||||
// min "small" unit threshold
|
||||
min = 0.75
|
||||
|
||||
// binary unit chars.
|
||||
units = `kMGTPE`
|
||||
)
|
||||
|
||||
// Larger number: get value of
|
||||
// i / unit size. We have a 'min'
|
||||
// threshold after which we prefer
|
||||
// using the unit 1 down
|
||||
n := bits.Len64(uint64(sz)) / 10
|
||||
f := float64(sz) / pows[n-1]
|
||||
if f < min {
|
||||
f *= float64(base)
|
||||
n--
|
||||
}
|
||||
|
||||
// Append formatted float with units
|
||||
f, u := sztof(sz, 1024, iecpows)
|
||||
dst = ftoa(dst, f)
|
||||
dst = append(dst, units[n-1])
|
||||
dst = append(dst, sunit...)
|
||||
dst = append(dst, u)
|
||||
dst = append(dst, 'i', 'B')
|
||||
return dst
|
||||
}
|
||||
|
||||
|
|
@ -261,6 +248,31 @@ func parseUnit(s string) (float64, int, error) {
|
|||
return sivals[c], l, nil
|
||||
}
|
||||
|
||||
// sztof divides a Size with base and power units to a float value with power.
|
||||
func sztof(sz Size, base float64, pows [6]float64) (float64, byte) {
|
||||
const (
|
||||
// min "small"
|
||||
// unit threshold.
|
||||
min = 0.75
|
||||
|
||||
// binary unit chars.
|
||||
units = `kMGTPE`
|
||||
)
|
||||
|
||||
// Larger number: get value of
|
||||
// i / unit size. We have a 'min'
|
||||
// threshold after which we prefer
|
||||
// using the unit 1 down
|
||||
n := bits.Len64(uint64(sz)) / 10
|
||||
f := float64(sz) / pows[n-1]
|
||||
if f < min {
|
||||
f *= base
|
||||
n--
|
||||
}
|
||||
|
||||
return f, units[n-1]
|
||||
}
|
||||
|
||||
// ftoa appends string formatted 'f' to 'dst', assumed < ~800.
|
||||
func ftoa(dst []byte, f float64) []byte {
|
||||
switch i := uint64(f); {
|
||||
|
|
|
|||
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz
generated
vendored
BIN
vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz
generated
vendored
Binary file not shown.
32
vendor/codeberg.org/gruf/go-kv/v2/format/README.md
generated
vendored
Normal file
32
vendor/codeberg.org/gruf/go-kv/v2/format/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# format
|
||||
|
||||
a low-level string formatting library that takes arbitrary input types as interfaces, and arguments as a struct. this does not contain any printf-like argument parsing, only log-friendly serialization of arbitrary input arguments. (noting that our output is noticably more log-friendly for struct / map types than stdlib "fmt").
|
||||
|
||||
benchmarks:
|
||||
```shell
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: codeberg.org/gruf/go-kv/v2/format
|
||||
cpu: AMD Ryzen 7 7840U w/ Radeon 780M Graphics
|
||||
|
||||
# go-kv/v2/format (i.e. latest)
|
||||
BenchmarkFormatV2Append
|
||||
BenchmarkFormatV2Append-16 590422 1977 ns/op 488 B/op 23 allocs/op
|
||||
BenchmarkFormatV2AppendVerbose
|
||||
BenchmarkFormatV2AppendVerbose-16 375628 2981 ns/op 1704 B/op 45 allocs/op
|
||||
|
||||
# go-kv/format (i.e. v1)
|
||||
BenchmarkFormatAppend
|
||||
BenchmarkFormatAppend-16 208357 5883 ns/op 2624 B/op 169 allocs/op
|
||||
BenchmarkFormatAppendVerbose
|
||||
BenchmarkFormatAppendVerbose-16 35916 33563 ns/op 3734 B/op 208 allocs/op
|
||||
|
||||
# fmt (i.e. stdlib)
|
||||
BenchmarkFmtAppend
|
||||
BenchmarkFmtAppend-16 147722 8418 ns/op 4747 B/op 191 allocs/op
|
||||
BenchmarkFmtAppendVerbose
|
||||
BenchmarkFmtAppendVerbose-16 167112 7238 ns/op 4401 B/op 178 allocs/op
|
||||
|
||||
PASS
|
||||
ok codeberg.org/gruf/go-kv/v2/format
|
||||
```
|
||||
54
vendor/codeberg.org/gruf/go-kv/v2/format/methods.go
generated
vendored
54
vendor/codeberg.org/gruf/go-kv/v2/format/methods.go
generated
vendored
|
|
@ -84,8 +84,8 @@ func getInterfaceStringerType(t xunsafe.TypeIter) FormatFunc {
|
|||
// (i.e. non-interface{}) type that has a Stringer{} method receiver.
|
||||
func getConcreteStringerType(t xunsafe.TypeIter) FormatFunc {
|
||||
itab := xunsafe.GetIfaceITab[Stringer](t.Type)
|
||||
switch t.Indirect() && !t.IfaceIndir() {
|
||||
case true:
|
||||
switch {
|
||||
case t.Indirect() && !t.IfaceIndir():
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
s.P = *(*unsafe.Pointer)(s.P)
|
||||
if s.P == nil {
|
||||
|
|
@ -95,13 +95,23 @@ func getConcreteStringerType(t xunsafe.TypeIter) FormatFunc {
|
|||
v := *(*Stringer)(xunsafe.PackIface(itab, s.P))
|
||||
appendString(s, v.String())
|
||||
})
|
||||
case false:
|
||||
case t.Type.Kind() == reflect.Pointer && t.Type.Implements(stringerType):
|
||||
// if the interface implementation is received by
|
||||
// value type, the pointer type will also support
|
||||
// it but it requires an extra dereference check.
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
if s.P == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
v := *(*Stringer)(xunsafe.PackIface(itab, s.P))
|
||||
appendString(s, v.String())
|
||||
})
|
||||
default:
|
||||
panic("unreachable")
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
v := *(*Stringer)(xunsafe.PackIface(itab, s.P))
|
||||
appendString(s, v.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,8 +147,8 @@ func getInterfaceFormattableType(t xunsafe.TypeIter) FormatFunc {
|
|||
// (i.e. non-interface{}) type that has a Formattable{} method receiver.
|
||||
func getConcreteFormattableType(t xunsafe.TypeIter) FormatFunc {
|
||||
itab := xunsafe.GetIfaceITab[Formattable](t.Type)
|
||||
switch t.Indirect() && !t.IfaceIndir() {
|
||||
case true:
|
||||
switch {
|
||||
case t.Indirect() && !t.IfaceIndir():
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
s.P = *(*unsafe.Pointer)(s.P)
|
||||
if s.P == nil {
|
||||
|
|
@ -148,13 +158,23 @@ func getConcreteFormattableType(t xunsafe.TypeIter) FormatFunc {
|
|||
v := *(*Formattable)(xunsafe.PackIface(itab, s.P))
|
||||
v.Format(s)
|
||||
})
|
||||
case false:
|
||||
case t.Type.Kind() == reflect.Pointer && t.Type.Implements(formattableType):
|
||||
// if the interface implementation is received by
|
||||
// value type, the pointer type will also support
|
||||
// it but it requires an extra dereference check.
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
if s.P == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
v := *(*Formattable)(xunsafe.PackIface(itab, s.P))
|
||||
v.Format(s)
|
||||
})
|
||||
default:
|
||||
panic("unreachable")
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
v := *(*Formattable)(xunsafe.PackIface(itab, s.P))
|
||||
v.Format(s)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -190,8 +210,8 @@ func getInterfaceErrorType(t xunsafe.TypeIter) FormatFunc {
|
|||
// (i.e. non-interface{}) type that has an error{} method receiver.
|
||||
func getConcreteErrorType(t xunsafe.TypeIter) FormatFunc {
|
||||
itab := xunsafe.GetIfaceITab[error](t.Type)
|
||||
switch t.Indirect() && !t.IfaceIndir() {
|
||||
case true:
|
||||
switch {
|
||||
case t.Indirect() && !t.IfaceIndir():
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
s.P = *(*unsafe.Pointer)(s.P)
|
||||
if s.P == nil {
|
||||
|
|
@ -201,12 +221,22 @@ func getConcreteErrorType(t xunsafe.TypeIter) FormatFunc {
|
|||
v := *(*error)(xunsafe.PackIface(itab, s.P))
|
||||
appendString(s, v.Error())
|
||||
})
|
||||
case false:
|
||||
case t.Type.Kind() == reflect.Pointer && t.Type.Implements(errorType):
|
||||
// if the interface implementation is received by
|
||||
// value type, the pointer type will also support
|
||||
// it but it requires an extra dereference check.
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
if s.P == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
v := *(*error)(xunsafe.PackIface(itab, s.P))
|
||||
appendString(s, v.Error())
|
||||
})
|
||||
default:
|
||||
panic("unreachable")
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
v := *(*error)(xunsafe.PackIface(itab, s.P))
|
||||
appendString(s, v.Error())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
230
vendor/codeberg.org/gruf/go-mangler/helpers.go
generated
vendored
230
vendor/codeberg.org/gruf/go-mangler/helpers.go
generated
vendored
|
|
@ -1,230 +0,0 @@
|
|||
//go:build go1.19 && !go1.25
|
||||
|
||||
package mangler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func append_uint16(b []byte, u uint16) []byte {
|
||||
return append(b, // LE
|
||||
byte(u),
|
||||
byte(u>>8),
|
||||
)
|
||||
}
|
||||
|
||||
func append_uint32(b []byte, u uint32) []byte {
|
||||
return append(b, // LE
|
||||
byte(u),
|
||||
byte(u>>8),
|
||||
byte(u>>16),
|
||||
byte(u>>24),
|
||||
)
|
||||
}
|
||||
|
||||
func append_uint64(b []byte, u uint64) []byte {
|
||||
return append(b, // LE
|
||||
byte(u),
|
||||
byte(u>>8),
|
||||
byte(u>>16),
|
||||
byte(u>>24),
|
||||
byte(u>>32),
|
||||
byte(u>>40),
|
||||
byte(u>>48),
|
||||
byte(u>>56),
|
||||
)
|
||||
}
|
||||
|
||||
type typecontext struct {
|
||||
isptr bool
|
||||
direct bool
|
||||
ntype reflect.Type
|
||||
rtype reflect.Type
|
||||
}
|
||||
|
||||
func (ctx *typecontext) set_nested(direct bool) {
|
||||
ctx.direct = ctx.direct && direct && !ctx.isptr
|
||||
ctx.ntype = ctx.rtype
|
||||
ctx.rtype = nil
|
||||
ctx.isptr = false
|
||||
}
|
||||
|
||||
func deref_ptr_mangler(ctx typecontext, mangle Mangler, n uint) Mangler {
|
||||
if mangle == nil || n == 0 {
|
||||
panic("bad input")
|
||||
}
|
||||
|
||||
// If this is a direct value type, i.e. non-nested primitive,
|
||||
// or part of a single-field struct / single element array
|
||||
// then it can be treated as a direct ptr with 1 less deref.
|
||||
if ctx.direct {
|
||||
n--
|
||||
}
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
// Deref n number times.
|
||||
for i := n; i > 0; i-- {
|
||||
|
||||
if ptr == nil {
|
||||
// Check for nil values
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
|
||||
// Further deref ptr
|
||||
buf = append(buf, '1')
|
||||
ptr = *(*unsafe.Pointer)(ptr)
|
||||
}
|
||||
|
||||
if ptr == nil {
|
||||
// Final nil val check
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
|
||||
// Mangle fully deref'd
|
||||
buf = append(buf, '1')
|
||||
buf = mangle(buf, ptr)
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
func iter_slice_mangler(ctx typecontext, mangle Mangler) Mangler {
|
||||
if ctx.rtype == nil || mangle == nil {
|
||||
panic("bad input")
|
||||
}
|
||||
|
||||
// memory size of elem.
|
||||
esz := ctx.rtype.Size()
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
// Get data as slice hdr.
|
||||
hdr := (*slice_header)(ptr)
|
||||
|
||||
for i := 0; i < hdr.len; i++ {
|
||||
// Mangle data at slice index.
|
||||
eptr := array_at(hdr.data, esz, i)
|
||||
buf = mangle(buf, eptr)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
if hdr.len > 0 {
|
||||
// Drop final comma.
|
||||
buf = buf[:len(buf)-1]
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
func iter_array_mangler(ctx typecontext, mangle Mangler) Mangler {
|
||||
if ctx.rtype == nil || mangle == nil {
|
||||
panic("bad input")
|
||||
}
|
||||
|
||||
// no. array elements.
|
||||
n := ctx.ntype.Len()
|
||||
|
||||
// Optimize
|
||||
// easy cases.
|
||||
switch n {
|
||||
case 0:
|
||||
return empty_mangler
|
||||
case 1:
|
||||
return mangle
|
||||
}
|
||||
|
||||
// memory size of elem.
|
||||
esz := ctx.rtype.Size()
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
for i := 0; i < n; i++ {
|
||||
// Mangle data at array index.
|
||||
offset := esz * uintptr(i)
|
||||
eptr := add(ptr, offset)
|
||||
buf = mangle(buf, eptr)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// Drop final comma.
|
||||
buf = buf[:len(buf)-1]
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
func iter_struct_mangler(ctx typecontext, manglers []Mangler) Mangler {
|
||||
if ctx.rtype == nil || len(manglers) != ctx.ntype.NumField() {
|
||||
panic("bad input")
|
||||
}
|
||||
|
||||
// Optimized easy cases.
|
||||
switch len(manglers) {
|
||||
case 0:
|
||||
return empty_mangler
|
||||
case 1:
|
||||
return manglers[0]
|
||||
}
|
||||
|
||||
type field struct {
|
||||
mangle Mangler
|
||||
offset uintptr
|
||||
}
|
||||
|
||||
// Bundle together the fields and manglers.
|
||||
fields := make([]field, ctx.ntype.NumField())
|
||||
for i := range fields {
|
||||
rfield := ctx.ntype.Field(i)
|
||||
fields[i].offset = rfield.Offset
|
||||
fields[i].mangle = manglers[i]
|
||||
if fields[i].mangle == nil {
|
||||
panic("bad input")
|
||||
}
|
||||
}
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
for i := range fields {
|
||||
// Get struct field ptr via offset.
|
||||
fptr := add(ptr, fields[i].offset)
|
||||
|
||||
// Mangle the struct field data.
|
||||
buf = fields[i].mangle(buf, fptr)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
if len(fields) > 0 {
|
||||
// Drop final comma.
|
||||
buf = buf[:len(buf)-1]
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
func empty_mangler(buf []byte, _ unsafe.Pointer) []byte {
|
||||
return buf
|
||||
}
|
||||
|
||||
// array_at returns ptr to index in array at ptr, given element size.
|
||||
func array_at(ptr unsafe.Pointer, esz uintptr, i int) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(ptr) + esz*uintptr(i))
|
||||
}
|
||||
|
||||
// add returns the ptr addition of starting ptr and a delta.
|
||||
func add(ptr unsafe.Pointer, delta uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(ptr) + delta)
|
||||
}
|
||||
|
||||
type slice_header struct {
|
||||
data unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
|
||||
func eface_data(a any) unsafe.Pointer {
|
||||
type eface struct{ _, data unsafe.Pointer }
|
||||
return (*eface)(unsafe.Pointer(&a)).data
|
||||
}
|
||||
230
vendor/codeberg.org/gruf/go-mangler/load.go
generated
vendored
230
vendor/codeberg.org/gruf/go-mangler/load.go
generated
vendored
|
|
@ -1,230 +0,0 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// loadMangler is the top-most Mangler load function. It guarantees that a Mangler
|
||||
// function will be returned for given value interface{} and reflected type. Else panics.
|
||||
func loadMangler(t reflect.Type) Mangler {
|
||||
ctx := typecontext{rtype: t}
|
||||
ctx.direct = true
|
||||
|
||||
// Load mangler fn
|
||||
mng := load(ctx)
|
||||
if mng != nil {
|
||||
return mng
|
||||
}
|
||||
|
||||
// No mangler function could be determined
|
||||
panic("cannot mangle type: " + t.String())
|
||||
}
|
||||
|
||||
// load will load a Mangler or reflect Mangler for given type and iface 'a'.
|
||||
// Note: allocates new interface value if nil provided, i.e. if coming via reflection.
|
||||
func load(ctx typecontext) Mangler {
|
||||
if ctx.rtype == nil {
|
||||
// There is no reflect type to search by
|
||||
panic("cannot mangle nil interface{} type")
|
||||
}
|
||||
|
||||
// Search by reflection.
|
||||
mng := loadReflect(ctx)
|
||||
if mng != nil {
|
||||
return mng
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadReflect will load a Mangler (or rMangler) function for the given reflected type info.
|
||||
// NOTE: this is used as the top level load function for nested reflective searches.
|
||||
func loadReflect(ctx typecontext) Mangler {
|
||||
switch ctx.rtype.Kind() {
|
||||
case reflect.Pointer:
|
||||
return loadReflectPtr(ctx)
|
||||
|
||||
case reflect.String:
|
||||
return mangle_string
|
||||
|
||||
case reflect.Struct:
|
||||
return loadReflectStruct(ctx)
|
||||
|
||||
case reflect.Array:
|
||||
return loadReflectArray(ctx)
|
||||
|
||||
case reflect.Slice:
|
||||
return loadReflectSlice(ctx)
|
||||
|
||||
case reflect.Bool:
|
||||
return mangle_bool
|
||||
|
||||
case reflect.Int,
|
||||
reflect.Uint,
|
||||
reflect.Uintptr:
|
||||
return mangle_int
|
||||
|
||||
case reflect.Int8, reflect.Uint8:
|
||||
return mangle_8bit
|
||||
|
||||
case reflect.Int16, reflect.Uint16:
|
||||
return mangle_16bit
|
||||
|
||||
case reflect.Int32, reflect.Uint32:
|
||||
return mangle_32bit
|
||||
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
return mangle_64bit
|
||||
|
||||
case reflect.Float32:
|
||||
return mangle_32bit
|
||||
|
||||
case reflect.Float64:
|
||||
return mangle_64bit
|
||||
|
||||
case reflect.Complex64:
|
||||
return mangle_64bit
|
||||
|
||||
case reflect.Complex128:
|
||||
return mangle_128bit
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// loadReflectPtr loads a Mangler (or rMangler) function for a ptr's element type.
|
||||
// This also handles further dereferencing of any further ptr indrections (e.g. ***int).
|
||||
func loadReflectPtr(ctx typecontext) Mangler {
|
||||
var n uint
|
||||
|
||||
// Iteratively dereference ptrs
|
||||
for ctx.rtype.Kind() == reflect.Pointer {
|
||||
ctx.rtype = ctx.rtype.Elem()
|
||||
n++
|
||||
}
|
||||
|
||||
// Set ptr type.
|
||||
ctx.isptr = true
|
||||
|
||||
// Search for elemn type mangler.
|
||||
if mng := load(ctx); mng != nil {
|
||||
return deref_ptr_mangler(ctx, mng, n)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadReflectKnownSlice loads a Mangler function for a
|
||||
// known slice-of-element type (in this case, primtives).
|
||||
func loadReflectKnownSlice(ctx typecontext) Mangler {
|
||||
switch ctx.rtype.Kind() {
|
||||
case reflect.String:
|
||||
return mangle_string_slice
|
||||
|
||||
case reflect.Bool:
|
||||
return mangle_bool_slice
|
||||
|
||||
case reflect.Int,
|
||||
reflect.Uint,
|
||||
reflect.Uintptr:
|
||||
return mangle_int_slice
|
||||
|
||||
case reflect.Int8, reflect.Uint8:
|
||||
return mangle_8bit_slice
|
||||
|
||||
case reflect.Int16, reflect.Uint16:
|
||||
return mangle_16bit_slice
|
||||
|
||||
case reflect.Int32, reflect.Uint32:
|
||||
return mangle_32bit_slice
|
||||
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
return mangle_64bit_slice
|
||||
|
||||
case reflect.Float32:
|
||||
return mangle_32bit_slice
|
||||
|
||||
case reflect.Float64:
|
||||
return mangle_64bit_slice
|
||||
|
||||
case reflect.Complex64:
|
||||
return mangle_64bit_slice
|
||||
|
||||
case reflect.Complex128:
|
||||
return mangle_128bit_slice
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// loadReflectSlice ...
|
||||
func loadReflectSlice(ctx typecontext) Mangler {
|
||||
|
||||
// Get nested element type.
|
||||
elem := ctx.rtype.Elem()
|
||||
|
||||
// Set this as nested type.
|
||||
ctx.set_nested(false)
|
||||
ctx.rtype = elem
|
||||
|
||||
// Preferably look for known slice mangler func
|
||||
if mng := loadReflectKnownSlice(ctx); mng != nil {
|
||||
return mng
|
||||
}
|
||||
|
||||
// Use nested mangler iteration.
|
||||
if mng := load(ctx); mng != nil {
|
||||
return iter_slice_mangler(ctx, mng)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadReflectArray ...
|
||||
func loadReflectArray(ctx typecontext) Mangler {
|
||||
|
||||
// Get nested element type.
|
||||
elem := ctx.rtype.Elem()
|
||||
|
||||
// Set this as a nested value type.
|
||||
direct := ctx.rtype.Len() <= 1
|
||||
ctx.set_nested(direct)
|
||||
ctx.rtype = elem
|
||||
|
||||
// Use manglers for nested iteration.
|
||||
if mng := load(ctx); mng != nil {
|
||||
return iter_array_mangler(ctx, mng)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadReflectStruct ...
|
||||
func loadReflectStruct(ctx typecontext) Mangler {
|
||||
var mngs []Mangler
|
||||
|
||||
// Set this as a nested value type.
|
||||
direct := ctx.rtype.NumField() <= 1
|
||||
ctx.set_nested(direct)
|
||||
|
||||
// Gather manglers for all fields.
|
||||
for i := 0; i < ctx.ntype.NumField(); i++ {
|
||||
|
||||
// Update context with field at index.
|
||||
ctx.rtype = ctx.ntype.Field(i).Type
|
||||
|
||||
// Load mangler.
|
||||
mng := load(ctx)
|
||||
if mng == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append next to map.
|
||||
mngs = append(mngs, mng)
|
||||
}
|
||||
|
||||
// Use manglers for nested iteration.
|
||||
return iter_struct_mangler(ctx, mngs)
|
||||
}
|
||||
130
vendor/codeberg.org/gruf/go-mangler/mangle.go
generated
vendored
130
vendor/codeberg.org/gruf/go-mangler/mangle.go
generated
vendored
|
|
@ -1,130 +0,0 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// manglers is a map of runtime
|
||||
// type ptrs => Mangler functions.
|
||||
var manglers sync.Map
|
||||
|
||||
// Mangler is a function that will take an input interface value of known
|
||||
// type, and append it in mangled serialized form to the given byte buffer.
|
||||
// While the value type is an interface, the Mangler functions are accessed
|
||||
// by the value's runtime type pointer, allowing the input value type to be known.
|
||||
type Mangler func(buf []byte, ptr unsafe.Pointer) []byte
|
||||
|
||||
// Get will fetch the Mangler function for given runtime type.
|
||||
// Note that the returned mangler will be a no-op in the case
|
||||
// that an incorrect type is passed as the value argument.
|
||||
func Get(t reflect.Type) Mangler {
|
||||
var mng Mangler
|
||||
|
||||
// Get raw runtime type ptr
|
||||
uptr := uintptr(eface_data(t))
|
||||
|
||||
// Look for a cached mangler
|
||||
v, ok := manglers.Load(uptr)
|
||||
|
||||
if !ok {
|
||||
// Load mangler function
|
||||
mng = loadMangler(t)
|
||||
} else {
|
||||
// cast cached value
|
||||
mng = v.(Mangler)
|
||||
}
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
// First write the type ptr (this adds
|
||||
// a unique prefix for each runtime type).
|
||||
buf = append_uint64(buf, uint64(uptr))
|
||||
|
||||
// Finally, mangle value
|
||||
return mng(buf, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
// Register will register the given Mangler function for use with vars of given runtime type. This allows
|
||||
// registering performant manglers for existing types not implementing Mangled (e.g. std library types).
|
||||
// NOTE: panics if there already exists a Mangler function for given type. Register on init().
|
||||
func Register(t reflect.Type, m Mangler) {
|
||||
if t == nil {
|
||||
// Nil interface{} types cannot be searched by, do not accept
|
||||
panic("cannot register mangler for nil interface{} type")
|
||||
}
|
||||
|
||||
// Get raw runtime type ptr
|
||||
uptr := uintptr(eface_data(t))
|
||||
|
||||
// Ensure this is a unique encoder
|
||||
if _, ok := manglers.Load(uptr); ok {
|
||||
panic("already registered mangler for type: " + t.String())
|
||||
}
|
||||
|
||||
// Cache this encoder func
|
||||
manglers.Store(uptr, m)
|
||||
}
|
||||
|
||||
// Append will append the mangled form of input value 'a' to buffer 'b'.
|
||||
// See mangler.String() for more information on mangled output.
|
||||
func Append(b []byte, a any) []byte {
|
||||
var mng Mangler
|
||||
|
||||
// Get reflect type of 'a'
|
||||
t := reflect.TypeOf(a)
|
||||
|
||||
// Get raw runtime type ptr
|
||||
uptr := uintptr(eface_data(t))
|
||||
|
||||
// Look for a cached mangler
|
||||
v, ok := manglers.Load(uptr)
|
||||
|
||||
if !ok {
|
||||
// Load into cache
|
||||
mng = loadMangler(t)
|
||||
manglers.Store(uptr, mng)
|
||||
} else {
|
||||
// cast cached value
|
||||
mng = v.(Mangler)
|
||||
}
|
||||
|
||||
// First write the type ptr (this adds
|
||||
// a unique prefix for each runtime type).
|
||||
b = append_uint64(b, uint64(uptr))
|
||||
|
||||
// Finally, mangle value
|
||||
ptr := eface_data(a)
|
||||
return mng(b, ptr)
|
||||
}
|
||||
|
||||
// String will return the mangled format of input value 'a'. This
|
||||
// mangled output will be unique for all default supported input types
|
||||
// during a single runtime instance. Uniqueness cannot be guaranteed
|
||||
// between separate runtime instances (whether running concurrently, or
|
||||
// the same application running at different times).
|
||||
//
|
||||
// The exact formatting of the output data should not be relied upon,
|
||||
// only that it is unique given the above constraints. Generally though,
|
||||
// the mangled output is the binary formatted text of given input data.
|
||||
//
|
||||
// Uniqueness is guaranteed for similar input data of differing types
|
||||
// (e.g. string("hello world") vs. []byte("hello world")) by prefixing
|
||||
// mangled output with the input data's runtime type pointer.
|
||||
//
|
||||
// Default supported types include:
|
||||
// - string
|
||||
// - bool
|
||||
// - int,int8,int16,int32,int64
|
||||
// - uint,uint8,uint16,uint32,uint64,uintptr
|
||||
// - float32,float64
|
||||
// - complex64,complex128
|
||||
// - arbitrary structs
|
||||
// - all type aliases of above
|
||||
// - all pointers to the above
|
||||
// - all slices / arrays of the above
|
||||
func String(a any) string {
|
||||
b := Append(make([]byte, 0, 32), a)
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
55
vendor/codeberg.org/gruf/go-mangler/v2/array.go
generated
vendored
Normal file
55
vendor/codeberg.org/gruf/go-mangler/v2/array.go
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// iterArrayType returns a Mangler capable of iterating
|
||||
// and mangling the given array type currently in TypeIter{}.
|
||||
// note this will fetch sub-Mangler for array element type.
|
||||
func iterArrayType(t xunsafe.TypeIter) Mangler {
|
||||
|
||||
// Array element type.
|
||||
elem := t.Type.Elem()
|
||||
|
||||
// Get nested elem TypeIter with appropriate flags.
|
||||
flags := xunsafe.ReflectArrayElemFlags(t.Flag, elem)
|
||||
et := t.Child(elem, flags)
|
||||
|
||||
// Get elem mangler.
|
||||
fn := loadOrGet(et)
|
||||
if fn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Array element in-memory size.
|
||||
esz := t.Type.Elem().Size()
|
||||
|
||||
// No of elements.
|
||||
n := t.Type.Len()
|
||||
switch n {
|
||||
case 0:
|
||||
return empty_mangler
|
||||
case 1:
|
||||
return fn
|
||||
default:
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
for i := 0; i < n; i++ {
|
||||
// Mangle data at array index.
|
||||
offset := esz * uintptr(i)
|
||||
eptr := add(ptr, offset)
|
||||
buf = fn(buf, eptr)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// Drop final comma.
|
||||
buf = buf[:len(buf)-1]
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
}
|
||||
62
vendor/codeberg.org/gruf/go-mangler/v2/cache.go
generated
vendored
Normal file
62
vendor/codeberg.org/gruf/go-mangler/v2/cache.go
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
var manglers cache
|
||||
|
||||
// cache is a concurrency-safe map[xunsafe.TypeInfo]Mangler
|
||||
// cache, designed for heavy reads but with unfortunately expensive
|
||||
// writes. it is designed such that after some initial load period
|
||||
// in which functions are cached by types, all future ops are reads.
|
||||
type cache struct{ p unsafe.Pointer }
|
||||
|
||||
// Get will check cache for mangler func under key.
|
||||
func (c *cache) Get(t xunsafe.TypeInfo) Mangler {
|
||||
if p := c.load(); p != nil {
|
||||
return (*p)[t]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Put will place given mangler func in cache under key, if not already exists.
|
||||
func (c *cache) Put(t xunsafe.TypeInfo, fn Mangler) {
|
||||
for {
|
||||
p := c.load()
|
||||
|
||||
var cache map[xunsafe.TypeInfo]Mangler
|
||||
|
||||
if p != nil {
|
||||
if _, ok := (*p)[t]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
cache = make(map[xunsafe.TypeInfo]Mangler, len(*p)+1)
|
||||
for key, value := range *p {
|
||||
cache[key] = value
|
||||
}
|
||||
} else {
|
||||
cache = make(map[xunsafe.TypeInfo]Mangler, 1)
|
||||
}
|
||||
|
||||
cache[t] = fn
|
||||
|
||||
if c.cas(p, &cache) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load is a typed wrapper around atomic.LoadPointer().
|
||||
func (c *cache) load() *map[xunsafe.TypeInfo]Mangler {
|
||||
return (*map[xunsafe.TypeInfo]Mangler)(atomic.LoadPointer(&c.p))
|
||||
}
|
||||
|
||||
// cas is a typed wrapper around atomic.CompareAndSwapPointer().
|
||||
func (c *cache) cas(old, new *map[xunsafe.TypeInfo]Mangler) bool {
|
||||
return atomic.CompareAndSwapPointer(&c.p, unsafe.Pointer(old), unsafe.Pointer(new))
|
||||
}
|
||||
43
vendor/codeberg.org/gruf/go-mangler/v2/helpers.go
generated
vendored
Normal file
43
vendor/codeberg.org/gruf/go-mangler/v2/helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func append_uint16(b []byte, u uint16) []byte {
|
||||
return append(b, // LE
|
||||
byte(u),
|
||||
byte(u>>8),
|
||||
)
|
||||
}
|
||||
|
||||
func append_uint32(b []byte, u uint32) []byte {
|
||||
return append(b, // LE
|
||||
byte(u),
|
||||
byte(u>>8),
|
||||
byte(u>>16),
|
||||
byte(u>>24),
|
||||
)
|
||||
}
|
||||
|
||||
func append_uint64(b []byte, u uint64) []byte {
|
||||
return append(b, // LE
|
||||
byte(u),
|
||||
byte(u>>8),
|
||||
byte(u>>16),
|
||||
byte(u>>24),
|
||||
byte(u>>32),
|
||||
byte(u>>40),
|
||||
byte(u>>48),
|
||||
byte(u>>56),
|
||||
)
|
||||
}
|
||||
|
||||
func empty_mangler(buf []byte, _ unsafe.Pointer) []byte {
|
||||
return buf
|
||||
}
|
||||
|
||||
// add returns the ptr addition of starting ptr and a delta.
|
||||
func add(ptr unsafe.Pointer, delta uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(ptr) + delta)
|
||||
}
|
||||
150
vendor/codeberg.org/gruf/go-mangler/v2/load.go
generated
vendored
Normal file
150
vendor/codeberg.org/gruf/go-mangler/v2/load.go
generated
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// loadOrStore first checks the cache for a Mangler
|
||||
// function, else generates one by calling get().
|
||||
// note: this does store generated funcs in cache.
|
||||
func loadOrStore(t xunsafe.TypeIter) Mangler {
|
||||
|
||||
// Get cache key.
|
||||
key := t.TypeInfo
|
||||
|
||||
// Check cache for func.
|
||||
fn := manglers.Get(key)
|
||||
|
||||
if fn == nil {
|
||||
// Generate new mangler
|
||||
// func for this type.
|
||||
fn = get(t)
|
||||
if fn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Store func in cache.
|
||||
manglers.Put(key, fn)
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
// loadOrGet first checks the cache for a Mangler
|
||||
// function, else generates one by calling get().
|
||||
// note: it does not store the function in cache.
|
||||
func loadOrGet(t xunsafe.TypeIter) Mangler {
|
||||
|
||||
// Check cache for mangler func.
|
||||
fn := manglers.Get(t.TypeInfo)
|
||||
|
||||
if fn == nil {
|
||||
// Generate new mangler
|
||||
// func for this type.
|
||||
fn = get(t)
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
var (
|
||||
// reflectTypeType is the reflected type of the reflect type,
|
||||
// used in fmt.get() to prevent iter of internal ABI structs.
|
||||
reflectTypeType = reflect.TypeOf(reflect.TypeOf(0))
|
||||
)
|
||||
|
||||
// get attempts to generate a new Mangler function
|
||||
// capable of mangling a ptr of given type information.
|
||||
func get(t xunsafe.TypeIter) (fn Mangler) {
|
||||
defer func() {
|
||||
if fn == nil {
|
||||
// nothing more
|
||||
// we can do.
|
||||
return
|
||||
}
|
||||
|
||||
if t.Parent != nil {
|
||||
// We're only interested
|
||||
// in wrapping top-level.
|
||||
return
|
||||
}
|
||||
|
||||
// Get reflected type ptr for prefix.
|
||||
ptr := xunsafe.ReflectTypeData(t.Type)
|
||||
uptr := uintptr(ptr)
|
||||
|
||||
// Outer fn.
|
||||
mng := fn
|
||||
|
||||
// Wrap the mangler func to prepend type pointer.
|
||||
fn = func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
buf = append_uint64(buf, uint64(uptr))
|
||||
return mng(buf, ptr)
|
||||
}
|
||||
}()
|
||||
|
||||
if t.Type == nil {
|
||||
// nil type.
|
||||
return nil
|
||||
}
|
||||
|
||||
if t.Type == reflectTypeType {
|
||||
// DO NOT iterate down internal ABI
|
||||
// types, some are in non-GC memory.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check supports known method receiver.
|
||||
if fn := getMethodType(t); fn != nil {
|
||||
return fn
|
||||
}
|
||||
|
||||
if !visit(t) {
|
||||
// On type recursion simply
|
||||
// mangle as raw pointer.
|
||||
return mangle_int
|
||||
}
|
||||
|
||||
// Get func for type kind.
|
||||
switch t.Type.Kind() {
|
||||
case reflect.Pointer:
|
||||
return derefPointerType(t)
|
||||
case reflect.Struct:
|
||||
return iterStructType(t)
|
||||
case reflect.Array:
|
||||
return iterArrayType(t)
|
||||
case reflect.Slice:
|
||||
return iterSliceType(t)
|
||||
case reflect.Map:
|
||||
return iterMapType(t)
|
||||
case reflect.String:
|
||||
return mangle_string
|
||||
case reflect.Bool:
|
||||
return mangle_bool
|
||||
case reflect.Int,
|
||||
reflect.Uint,
|
||||
reflect.Uintptr:
|
||||
return mangle_int
|
||||
case reflect.Int8, reflect.Uint8:
|
||||
return mangle_8bit
|
||||
case reflect.Int16, reflect.Uint16:
|
||||
return mangle_16bit
|
||||
case reflect.Int32, reflect.Uint32:
|
||||
return mangle_32bit
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
return mangle_64bit
|
||||
case reflect.Float32:
|
||||
return mangle_32bit
|
||||
case reflect.Float64:
|
||||
return mangle_64bit
|
||||
case reflect.Complex64:
|
||||
return mangle_64bit
|
||||
case reflect.Complex128:
|
||||
return mangle_128bit
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
93
vendor/codeberg.org/gruf/go-mangler/v2/mangle.go
generated
vendored
Normal file
93
vendor/codeberg.org/gruf/go-mangler/v2/mangle.go
generated
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// Mangler is a function that will take an input value of known type,
|
||||
// and append it in mangled serialized form to the given byte buffer.
|
||||
type Mangler func(buf []byte, ptr unsafe.Pointer) []byte
|
||||
|
||||
// Get will fetch the Mangler function for given runtime type information.
|
||||
// The required argument is of type xunsafe.TypeIter{} as unsafe pointer
|
||||
// access requires further contextual information like type nesting.
|
||||
func Get(t xunsafe.TypeIter) Mangler {
|
||||
t.Parent = nil // enforce type prefix
|
||||
fn := loadOrStore(t)
|
||||
if fn == nil {
|
||||
panic(fmt.Sprintf("cannot mangle type: %s", t.Type))
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// GetNoLoad is functionally similar to Get(),
|
||||
// without caching the resulting Mangler.
|
||||
func GetNoLoad(t xunsafe.TypeIter) Mangler {
|
||||
t.Parent = nil // enforce type prefix
|
||||
fn := loadOrGet(t)
|
||||
if fn == nil {
|
||||
panic(fmt.Sprintf("cannot mangle type: %s", t.Type))
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// Append will append the mangled form of input value 'a' to buffer 'b'.
|
||||
//
|
||||
// See mangler.String() for more information on mangled output.
|
||||
func Append(b []byte, a any) []byte {
|
||||
t := xunsafe.TypeIterFrom(a)
|
||||
p := xunsafe.UnpackEface(a)
|
||||
return Get(t)(b, p)
|
||||
}
|
||||
|
||||
// AppendMulti appends all mangled forms of input value(s) 'a' to buffer 'b'
|
||||
// separated by colon characters. When all type manglers are currently cached
|
||||
// for all types in 'a', this will be faster than multiple calls to Append().
|
||||
//
|
||||
// See mangler.String() for more information on mangled output.
|
||||
func AppendMulti(b []byte, a ...any) []byte {
|
||||
if p := manglers.load(); p != nil {
|
||||
b4 := len(b)
|
||||
for _, a := range a {
|
||||
t := xunsafe.TypeIterFrom(a)
|
||||
m := (*p)[t.TypeInfo]
|
||||
if m == nil {
|
||||
b = b[:b4]
|
||||
goto slow
|
||||
}
|
||||
b = m(b, xunsafe.UnpackEface(a))
|
||||
b = append(b, '.')
|
||||
}
|
||||
return b
|
||||
}
|
||||
slow:
|
||||
for _, a := range a {
|
||||
b = Append(b, a)
|
||||
b = append(b, '.')
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// String will return the mangled format of input value 'a'. This
|
||||
// mangled output will be unique for all default supported input types
|
||||
// during a single runtime instance. Uniqueness cannot be guaranteed
|
||||
// between separate runtime instances (whether running concurrently, or
|
||||
// the same application running at different times).
|
||||
//
|
||||
// The exact formatting of the output data should not be relied upon,
|
||||
// only that it is unique given the above constraints. Generally though,
|
||||
// the mangled output is the binary formatted text of given input data.
|
||||
//
|
||||
// Uniqueness is guaranteed for similar input data of differing types
|
||||
// (e.g. string("hello world") vs. []byte("hello world")) by prefixing
|
||||
// mangled output with the input data's runtime type pointer.
|
||||
//
|
||||
// Default supported types include all concrete (i.e. non-interface{})
|
||||
// data types, and interfaces implementing Mangleable{}.
|
||||
func String(a any) string {
|
||||
b := Append(make([]byte, 0, 32), a)
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
80
vendor/codeberg.org/gruf/go-mangler/v2/map.go
generated
vendored
Normal file
80
vendor/codeberg.org/gruf/go-mangler/v2/map.go
generated
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// iterMapType returns a Mangler capable of iterating
|
||||
// and mangling the given map type currently in TypeIter{}.
|
||||
// note this will fetch sub-Manglers for key / value types.
|
||||
func iterMapType(t xunsafe.TypeIter) Mangler {
|
||||
|
||||
// Key / value types.
|
||||
key := t.Type.Key()
|
||||
elem := t.Type.Elem()
|
||||
|
||||
// Get nested k / v TypeIters with appropriate flags.
|
||||
flagsKey := xunsafe.ReflectMapKeyFlags(key)
|
||||
flagsVal := xunsafe.ReflectMapElemFlags(elem)
|
||||
kt := t.Child(key, flagsKey)
|
||||
vt := t.Child(elem, flagsVal)
|
||||
|
||||
// Get key mangler.
|
||||
kfn := loadOrGet(kt)
|
||||
if kfn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get value mangler.
|
||||
vfn := loadOrGet(vt)
|
||||
if vfn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Final map type.
|
||||
rtype := t.Type
|
||||
flags := t.Flag
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
if ptr == nil || *(*unsafe.Pointer)(ptr) == nil {
|
||||
// Append nil indicator.
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
|
||||
// Build reflect value, and then a map iterator.
|
||||
v := xunsafe.BuildReflectValue(rtype, ptr, flags)
|
||||
i := xunsafe.GetMapIter(v)
|
||||
|
||||
// Before len.
|
||||
l := len(buf)
|
||||
|
||||
// Append not-nil flag.
|
||||
buf = append(buf, '1')
|
||||
|
||||
for i.Next() {
|
||||
// Pass to map key func.
|
||||
ptr = xunsafe.Map_Key(i)
|
||||
buf = kfn(buf, ptr)
|
||||
|
||||
// Add key seperator.
|
||||
buf = append(buf, ':')
|
||||
|
||||
// Pass to map elem func.
|
||||
ptr = xunsafe.Map_Elem(i)
|
||||
buf = vfn(buf, ptr)
|
||||
|
||||
// Add comma seperator.
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
if len(buf) != l {
|
||||
// Drop final comma.
|
||||
buf = buf[:len(buf)-1]
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
105
vendor/codeberg.org/gruf/go-mangler/v2/method.go
generated
vendored
Normal file
105
vendor/codeberg.org/gruf/go-mangler/v2/method.go
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
// mangleable type for implement checks.
|
||||
mangleableType = reflect.TypeFor[Mangleable]()
|
||||
)
|
||||
|
||||
type Mangleable interface {
|
||||
Mangle(dst []byte) []byte
|
||||
}
|
||||
|
||||
// getMethodType returns a *possible* Mangler to handle case
|
||||
// of a type that implements any known interface{} types, else nil.
|
||||
func getMethodType(t xunsafe.TypeIter) Mangler {
|
||||
switch {
|
||||
case t.Type.Implements(mangleableType):
|
||||
switch t.Type.Kind() {
|
||||
case reflect.Interface:
|
||||
return getInterfaceMangleableType(t)
|
||||
default:
|
||||
return getConcreteMangleableType(t)
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// getInterfaceMangleableType returns a Mangler to handle case of an interface{}
|
||||
// type that implements Mangleable{}, i.e. Mangleable{} itself and any superset of.
|
||||
func getInterfaceMangleableType(t xunsafe.TypeIter) Mangler {
|
||||
switch t.Indirect() && !t.IfaceIndir() {
|
||||
case true:
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
ptr = *(*unsafe.Pointer)(ptr)
|
||||
if ptr == nil || (*xunsafe.Abi_NonEmptyInterface)(ptr).Data == nil {
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
v := *(*Mangleable)(ptr)
|
||||
buf = append(buf, '1')
|
||||
buf = v.Mangle(buf)
|
||||
return buf
|
||||
}
|
||||
case false:
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
if ptr == nil || (*xunsafe.Abi_NonEmptyInterface)(ptr).Data == nil {
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
v := *(*Mangleable)(ptr)
|
||||
buf = append(buf, '1')
|
||||
buf = v.Mangle(buf)
|
||||
return buf
|
||||
}
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// getConcreteMangleableType returns a Manlger to handle case of concrete
|
||||
// (i.e. non-interface{}) type that has a Mangleable{} method receiver.
|
||||
func getConcreteMangleableType(t xunsafe.TypeIter) Mangler {
|
||||
itab := xunsafe.GetIfaceITab[Mangleable](t.Type)
|
||||
switch {
|
||||
case t.Indirect() && !t.IfaceIndir():
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
ptr = *(*unsafe.Pointer)(ptr)
|
||||
if ptr == nil {
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
v := *(*Mangleable)(xunsafe.PackIface(itab, ptr))
|
||||
buf = append(buf, '1')
|
||||
buf = v.Mangle(buf)
|
||||
return buf
|
||||
}
|
||||
case t.Type.Kind() == reflect.Pointer && t.Type.Implements(mangleableType):
|
||||
// if the interface implementation is received by
|
||||
// value type, the pointer type will also support
|
||||
// it but it requires an extra dereference check.
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
if ptr == nil {
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
v := *(*Mangleable)(xunsafe.PackIface(itab, ptr))
|
||||
buf = append(buf, '1')
|
||||
buf = v.Mangle(buf)
|
||||
return buf
|
||||
}
|
||||
default:
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
v := *(*Mangleable)(xunsafe.PackIface(itab, ptr))
|
||||
buf = v.Mangle(buf)
|
||||
return buf
|
||||
}
|
||||
}
|
||||
}
|
||||
81
vendor/codeberg.org/gruf/go-mangler/v2/pointer.go
generated
vendored
Normal file
81
vendor/codeberg.org/gruf/go-mangler/v2/pointer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// derefPointerType returns a Mangler capable of dereferencing
|
||||
// and formatting the given pointer type currently in TypeIter{}.
|
||||
// note this will fetch a sub-Mangler for resulting value type.
|
||||
func derefPointerType(t xunsafe.TypeIter) Mangler {
|
||||
var derefs int
|
||||
var indirects int64
|
||||
rtype := t.Type
|
||||
flags := t.Flag
|
||||
|
||||
// Iteratively dereference pointer types.
|
||||
for rtype.Kind() == reflect.Pointer {
|
||||
|
||||
// Only if this is actual indirect memory do we
|
||||
// perform a derefence, otherwise we just skip over
|
||||
// and increase the dereference indicator, i.e. '1'.
|
||||
if flags&xunsafe.Reflect_flagIndir != 0 {
|
||||
indirects |= 1 << derefs
|
||||
}
|
||||
derefs++
|
||||
|
||||
// Get next elem type.
|
||||
rtype = rtype.Elem()
|
||||
|
||||
// Get next set of dereferenced element type flags.
|
||||
flags = xunsafe.ReflectPointerElemFlags(flags, rtype)
|
||||
}
|
||||
|
||||
// Ensure this is a reasonable number of derefs.
|
||||
if derefs > 4*int(unsafe.Sizeof(indirects)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrap value as TypeIter.
|
||||
vt := t.Child(rtype, flags)
|
||||
|
||||
// Get value mangler.
|
||||
fn := loadOrGet(vt)
|
||||
if fn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
for i := 0; i < derefs; i++ {
|
||||
switch {
|
||||
case indirects&1<<i == 0:
|
||||
// No dereference needed.
|
||||
buf = append(buf, '1')
|
||||
|
||||
case ptr == nil:
|
||||
// Nil value, return here.
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
|
||||
default:
|
||||
// Further deref ptr.
|
||||
buf = append(buf, '1')
|
||||
ptr = *(*unsafe.Pointer)(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
if ptr == nil {
|
||||
// Final nil val check.
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
|
||||
// Mangle fully deref'd.
|
||||
buf = append(buf, '1')
|
||||
buf = fn(buf, ptr)
|
||||
return buf
|
||||
}
|
||||
}
|
||||
95
vendor/codeberg.org/gruf/go-mangler/v2/slice.go
generated
vendored
Normal file
95
vendor/codeberg.org/gruf/go-mangler/v2/slice.go
generated
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// iterSliceType returns a Mangler capable of iterating
|
||||
// and mangling the given slice type currently in TypeIter{}.
|
||||
// note this will fetch sub-Mangler for slice element type.
|
||||
func iterSliceType(t xunsafe.TypeIter) Mangler {
|
||||
|
||||
// Get nested element type.
|
||||
elem := t.Type.Elem()
|
||||
esz := elem.Size()
|
||||
|
||||
// Get nested elem TypeIter{} with flags.
|
||||
flags := xunsafe.ReflectSliceElemFlags(elem)
|
||||
et := t.Child(elem, flags)
|
||||
|
||||
// Prefer to use a known slice mangler func.
|
||||
if fn := mangleKnownSlice(et); fn != nil {
|
||||
return fn
|
||||
}
|
||||
|
||||
// Get elem mangler.
|
||||
fn := loadOrGet(et)
|
||||
if fn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
// Get data as unsafe slice header.
|
||||
hdr := (*xunsafe.Unsafeheader_Slice)(ptr)
|
||||
if hdr == nil || hdr.Data == nil {
|
||||
|
||||
// Append nil indicator.
|
||||
buf = append(buf, '0')
|
||||
return buf
|
||||
}
|
||||
|
||||
// Append not-nil flag.
|
||||
buf = append(buf, '1')
|
||||
|
||||
for i := 0; i < hdr.Len; i++ {
|
||||
// Mangle at array index.
|
||||
offset := esz * uintptr(i)
|
||||
ptr = add(hdr.Data, offset)
|
||||
buf = fn(buf, ptr)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
if hdr.Len > 0 {
|
||||
// Drop final comma.
|
||||
buf = buf[:len(buf)-1]
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
// mangleKnownSlice loads a Mangler function for a
|
||||
// known slice-of-element type (in this case, primtives).
|
||||
func mangleKnownSlice(t xunsafe.TypeIter) Mangler {
|
||||
switch t.Type.Kind() {
|
||||
case reflect.String:
|
||||
return mangle_string_slice
|
||||
case reflect.Bool:
|
||||
return mangle_bool_slice
|
||||
case reflect.Int,
|
||||
reflect.Uint,
|
||||
reflect.Uintptr:
|
||||
return mangle_int_slice
|
||||
case reflect.Int8, reflect.Uint8:
|
||||
return mangle_8bit_slice
|
||||
case reflect.Int16, reflect.Uint16:
|
||||
return mangle_16bit_slice
|
||||
case reflect.Int32, reflect.Uint32:
|
||||
return mangle_32bit_slice
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
return mangle_64bit_slice
|
||||
case reflect.Float32:
|
||||
return mangle_32bit_slice
|
||||
case reflect.Float64:
|
||||
return mangle_64bit_slice
|
||||
case reflect.Complex64:
|
||||
return mangle_64bit_slice
|
||||
case reflect.Complex128:
|
||||
return mangle_128bit_slice
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
75
vendor/codeberg.org/gruf/go-mangler/v2/struct.go
generated
vendored
Normal file
75
vendor/codeberg.org/gruf/go-mangler/v2/struct.go
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// field stores the minimum necessary
|
||||
// data for iterating and mangling
|
||||
// each field in a given struct.
|
||||
type field struct {
|
||||
mangle Mangler
|
||||
offset uintptr
|
||||
}
|
||||
|
||||
// iterStructType returns a Mangler capable of iterating
|
||||
// and mangling the given struct type currently in TypeIter{}.
|
||||
// note this will fetch sub-Manglers for each struct field.
|
||||
func iterStructType(t xunsafe.TypeIter) Mangler {
|
||||
|
||||
// Number of struct fields.
|
||||
n := t.Type.NumField()
|
||||
|
||||
// Gather mangler functions.
|
||||
fields := make([]field, n)
|
||||
for i := 0; i < n; i++ {
|
||||
|
||||
// Get struct field at index.
|
||||
sfield := t.Type.Field(i)
|
||||
rtype := sfield.Type
|
||||
|
||||
// Get nested field TypeIter with appropriate flags.
|
||||
flags := xunsafe.ReflectStructFieldFlags(t.Flag, rtype)
|
||||
ft := t.Child(sfield.Type, flags)
|
||||
|
||||
// Get field mangler.
|
||||
fn := loadOrGet(ft)
|
||||
if fn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set field info.
|
||||
fields[i] = field{
|
||||
mangle: fn,
|
||||
offset: sfield.Offset,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle no. fields.
|
||||
switch len(fields) {
|
||||
case 0:
|
||||
return empty_mangler
|
||||
case 1:
|
||||
return fields[0].mangle
|
||||
default:
|
||||
return func(buf []byte, ptr unsafe.Pointer) []byte {
|
||||
for i := range fields {
|
||||
// Get struct field ptr via offset.
|
||||
fptr := add(ptr, fields[i].offset)
|
||||
|
||||
// Mangle the struct field data.
|
||||
buf = fields[i].mangle(buf, fptr)
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
if len(fields) > 0 {
|
||||
// Drop final comma.
|
||||
buf = buf[:len(buf)-1]
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
}
|
||||
20
vendor/codeberg.org/gruf/go-mangler/v2/type.go
generated
vendored
Normal file
20
vendor/codeberg.org/gruf/go-mangler/v2/type.go
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package mangler
|
||||
|
||||
import (
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// visit checks if current type has already
|
||||
// appeared in the TypeIter{}'s parent heirarchy.
|
||||
func visit(iter xunsafe.TypeIter) bool {
|
||||
t := iter.Type
|
||||
|
||||
// Check if type is already encountered further up tree.
|
||||
for node := iter.Parent; node != nil; node = node.Parent {
|
||||
if node.Type == t {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
4
vendor/codeberg.org/gruf/go-mutexes/map_unsafe.go
generated
vendored
4
vendor/codeberg.org/gruf/go-mutexes/map_unsafe.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
//go:build go1.22 && !go1.25
|
||||
//go:build go1.22 && !go1.26
|
||||
|
||||
package mutexes
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ func syncCond_last_ticket(c *sync.Cond) uint32 {
|
|||
// this does not alter the first
|
||||
// 2 fields which are all we need.
|
||||
type notifyList struct {
|
||||
_ atomic.Uint32
|
||||
_ uint32
|
||||
notify uint32
|
||||
// ... other fields
|
||||
}
|
||||
|
|
|
|||
2
vendor/codeberg.org/gruf/go-structr/README.md
generated
vendored
2
vendor/codeberg.org/gruf/go-structr/README.md
generated
vendored
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
A library with a series of performant data types with automated struct value indexing. Indexing is supported via arbitrary combinations of fields, and in the case of the cache type, negative results (errors!) are also supported.
|
||||
|
||||
Under the hood, go-structr maintains a hashmap per index, where each hashmap is a hashmap keyed by serialized input key type. This is handled by the incredibly performant serialization library [go-mangler](https://codeberg.org/gruf/go-mangler), which at this point in time supports *most* arbitrary types (other than maps, channels, functions), so feel free to index by by almost *anything*!
|
||||
Under the hood, go-structr maintains a hashmap per index, where each hashmap is a hashmap keyed by serialized input key type. This is handled by the incredibly performant serialization library [go-mangler/v2](https://codeberg.org/gruf/go-mangler), which at this point in time supports *most* arbitrary types (other than channels, functions), so feel free to index by by almost *anything*!
|
||||
|
||||
See the [docs](https://pkg.go.dev/codeberg.org/gruf/go-structr) for more API information.
|
||||
|
||||
|
|
|
|||
60
vendor/codeberg.org/gruf/go-structr/cache.go
generated
vendored
60
vendor/codeberg.org/gruf/go-structr/cache.go
generated
vendored
|
|
@ -3,7 +3,6 @@ package structr
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
|
@ -83,7 +82,7 @@ type Cache[StructType any] struct {
|
|||
// Init initializes the cache with given configuration
|
||||
// including struct fields to index, and necessary fns.
|
||||
func (c *Cache[T]) Init(config CacheConfig[T]) {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
t := get_type_iter[T]()
|
||||
|
||||
if len(config.Indices) == 0 {
|
||||
panic("no indices provided")
|
||||
|
|
@ -182,9 +181,14 @@ func (c *Cache[T]) Put(values ...T) {
|
|||
// Acquire lock.
|
||||
c.mutex.Lock()
|
||||
|
||||
// Wrap unlock to only do once.
|
||||
unlock := once(c.mutex.Unlock)
|
||||
defer unlock()
|
||||
// Ensure mutex
|
||||
// gets unlocked.
|
||||
var unlocked bool
|
||||
defer func() {
|
||||
if !unlocked {
|
||||
c.mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
// Check cache init.
|
||||
if c.copy == nil {
|
||||
|
|
@ -202,9 +206,9 @@ func (c *Cache[T]) Put(values ...T) {
|
|||
// Get func ptrs.
|
||||
invalid := c.invalid
|
||||
|
||||
// Done with
|
||||
// the lock.
|
||||
unlock()
|
||||
// Done with lock.
|
||||
c.mutex.Unlock()
|
||||
unlocked = true
|
||||
|
||||
if invalid != nil {
|
||||
// Pass all invalidated values
|
||||
|
|
@ -241,9 +245,14 @@ func (c *Cache[T]) LoadOne(index *Index, key Key, load func() (T, error)) (T, er
|
|||
// Acquire lock.
|
||||
c.mutex.Lock()
|
||||
|
||||
// Wrap unlock to only do once.
|
||||
unlock := once(c.mutex.Unlock)
|
||||
defer unlock()
|
||||
// Ensure mutex
|
||||
// gets unlocked.
|
||||
var unlocked bool
|
||||
defer func() {
|
||||
if !unlocked {
|
||||
c.mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
// Check init'd.
|
||||
if c.copy == nil ||
|
||||
|
|
@ -276,9 +285,9 @@ func (c *Cache[T]) LoadOne(index *Index, key Key, load func() (T, error)) (T, er
|
|||
// Get func ptrs.
|
||||
ignore := c.ignore
|
||||
|
||||
// Done with
|
||||
// the lock.
|
||||
unlock()
|
||||
// Done with lock.
|
||||
c.mutex.Unlock()
|
||||
unlocked = true
|
||||
|
||||
if ok {
|
||||
// item found!
|
||||
|
|
@ -295,6 +304,7 @@ func (c *Cache[T]) LoadOne(index *Index, key Key, load func() (T, error)) (T, er
|
|||
|
||||
// Acquire lock.
|
||||
c.mutex.Lock()
|
||||
unlocked = false
|
||||
|
||||
// Index this new loaded item.
|
||||
// Note this handles copying of
|
||||
|
|
@ -308,6 +318,7 @@ func (c *Cache[T]) LoadOne(index *Index, key Key, load func() (T, error)) (T, er
|
|||
|
||||
// Done with lock.
|
||||
c.mutex.Unlock()
|
||||
unlocked = true
|
||||
|
||||
return val, err
|
||||
}
|
||||
|
|
@ -328,9 +339,14 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error))
|
|||
// Acquire lock.
|
||||
c.mutex.Lock()
|
||||
|
||||
// Wrap unlock to only do once.
|
||||
unlock := once(c.mutex.Unlock)
|
||||
defer unlock()
|
||||
// Ensure mutex
|
||||
// gets unlocked.
|
||||
var unlocked bool
|
||||
defer func() {
|
||||
if !unlocked {
|
||||
c.mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
// Check init'd.
|
||||
if c.copy == nil {
|
||||
|
|
@ -366,9 +382,9 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error))
|
|||
}
|
||||
}
|
||||
|
||||
// Done with
|
||||
// the lock.
|
||||
unlock()
|
||||
// Done with lock.
|
||||
c.mutex.Unlock()
|
||||
unlocked = true
|
||||
|
||||
if len(toLoad) == 0 {
|
||||
// We loaded everything!
|
||||
|
|
@ -383,6 +399,7 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error))
|
|||
|
||||
// Acquire lock.
|
||||
c.mutex.Lock()
|
||||
unlocked = false
|
||||
|
||||
// Store all uncached values.
|
||||
for i := range uncached {
|
||||
|
|
@ -394,6 +411,7 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error))
|
|||
|
||||
// Done with lock.
|
||||
c.mutex.Unlock()
|
||||
unlocked = true
|
||||
|
||||
// Append uncached to return values.
|
||||
values = append(values, uncached...)
|
||||
|
|
@ -685,7 +703,7 @@ func (c *Cache[T]) store_error(index *Index, key string, err error) {
|
|||
}
|
||||
|
||||
func (c *Cache[T]) delete(i *indexed_item) {
|
||||
for len(i.indexed) != 0 {
|
||||
for len(i.indexed) > 0 {
|
||||
// Pop last indexed entry from list.
|
||||
entry := i.indexed[len(i.indexed)-1]
|
||||
i.indexed[len(i.indexed)-1] = nil
|
||||
|
|
|
|||
80
vendor/codeberg.org/gruf/go-structr/index.go
generated
vendored
80
vendor/codeberg.org/gruf/go-structr/index.go
generated
vendored
|
|
@ -1,7 +1,6 @@
|
|||
package structr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
|
@ -9,6 +8,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-byteutil"
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// IndexConfig defines config variables
|
||||
|
|
@ -29,7 +29,7 @@ type IndexConfig struct {
|
|||
// is nil then it will not be indexed.
|
||||
//
|
||||
// Field types supported include any of those
|
||||
// supported by the `go-mangler` library.
|
||||
// supported by the `go-mangler/v2` library.
|
||||
Fields string
|
||||
|
||||
// Multiple indicates whether to accept multiple
|
||||
|
|
@ -58,7 +58,7 @@ type IndexConfig struct {
|
|||
type Index struct {
|
||||
|
||||
// ptr is a pointer to
|
||||
// the source Cache/Queue
|
||||
// the source type this
|
||||
// index is attached to.
|
||||
ptr unsafe.Pointer
|
||||
|
||||
|
|
@ -68,14 +68,12 @@ type Index struct {
|
|||
name string
|
||||
|
||||
// backing data store of the index, containing
|
||||
// the cached results contained within wrapping
|
||||
// index_entry{} which also contains the exact
|
||||
// key each result is stored under. the hash map
|
||||
// only keys by the xxh3 hash checksum for speed.
|
||||
// list{}s of index_entry{}s which each contain
|
||||
// the exact key each result is stored under.
|
||||
data hashmap
|
||||
|
||||
// struct fields encompassed by
|
||||
// keys (+ hashes) of this index.
|
||||
// struct fields encompassed
|
||||
// by keys of this index.
|
||||
fields []struct_field
|
||||
|
||||
// index flags:
|
||||
|
|
@ -89,55 +87,14 @@ func (i *Index) Name() string {
|
|||
return i.name
|
||||
}
|
||||
|
||||
// Key generates Key{} from given parts for
|
||||
// the type of lookup this Index uses in cache.
|
||||
// NOTE: panics on incorrect no. parts / types given.
|
||||
func (i *Index) Key(parts ...any) Key {
|
||||
ptrs := make([]unsafe.Pointer, len(parts))
|
||||
for x, part := range parts {
|
||||
ptrs[x] = eface_data(part)
|
||||
}
|
||||
buf := new_buffer()
|
||||
key := i.key(buf, ptrs)
|
||||
free_buffer(buf)
|
||||
return Key{
|
||||
raw: parts,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
// Keys generates []Key{} from given (multiple) parts
|
||||
// for the type of lookup this Index uses in the cache.
|
||||
// NOTE: panics on incorrect no. parts / types given.
|
||||
func (i *Index) Keys(parts ...[]any) []Key {
|
||||
keys := make([]Key, 0, len(parts))
|
||||
buf := new_buffer()
|
||||
for _, parts := range parts {
|
||||
ptrs := make([]unsafe.Pointer, len(parts))
|
||||
for x, part := range parts {
|
||||
ptrs[x] = eface_data(part)
|
||||
}
|
||||
key := i.key(buf, ptrs)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, Key{
|
||||
raw: parts,
|
||||
key: key,
|
||||
})
|
||||
}
|
||||
free_buffer(buf)
|
||||
return keys
|
||||
}
|
||||
|
||||
// init will initialize the cache with given type, config and capacity.
|
||||
func (i *Index) init(t reflect.Type, cfg IndexConfig, cap int) {
|
||||
func (i *Index) init(t xunsafe.TypeIter, cfg IndexConfig, cap int) {
|
||||
switch {
|
||||
// The only 2 types we support are
|
||||
// structs, and ptrs to a struct.
|
||||
case t.Kind() == reflect.Struct:
|
||||
case t.Kind() == reflect.Pointer &&
|
||||
t.Elem().Kind() == reflect.Struct:
|
||||
case t.Type.Kind() == reflect.Struct:
|
||||
case t.Type.Kind() == reflect.Pointer &&
|
||||
t.Type.Elem().Kind() == reflect.Struct:
|
||||
default:
|
||||
panic("index only support struct{} and *struct{}")
|
||||
}
|
||||
|
|
@ -164,8 +121,8 @@ func (i *Index) init(t reflect.Type, cfg IndexConfig, cap int) {
|
|||
// Split name to account for nesting.
|
||||
names := strings.Split(name, ".")
|
||||
|
||||
// Look for usable struct field.
|
||||
i.fields[x] = find_field(t, names)
|
||||
// Look for struct field by names.
|
||||
i.fields[x], _ = find_field(t, names)
|
||||
}
|
||||
|
||||
// Initialize store for
|
||||
|
|
@ -219,15 +176,12 @@ func (i *Index) get(key string, hook func(*indexed_item)) {
|
|||
}
|
||||
}
|
||||
|
||||
// key uses hasher to generate Key{} from given raw parts.
|
||||
// key ...
|
||||
func (i *Index) key(buf *byteutil.Buffer, parts []unsafe.Pointer) string {
|
||||
buf.B = buf.B[:0]
|
||||
if len(parts) != len(i.fields) {
|
||||
panic(fmt.Sprintf("incorrect number key parts: want=%d received=%d",
|
||||
len(i.fields),
|
||||
len(parts),
|
||||
))
|
||||
panic(assert("len(parts) = len(i.fields)"))
|
||||
}
|
||||
buf.B = buf.B[:0]
|
||||
if !allow_zero(i.flags) {
|
||||
for x, field := range i.fields {
|
||||
before := len(buf.B)
|
||||
|
|
@ -401,7 +355,7 @@ func (i *Index) delete_entry(entry *index_entry) {
|
|||
|
||||
// index_entry represents a single entry
|
||||
// in an Index{}, where it will be accessible
|
||||
// by Key{} pointing to a containing list{}.
|
||||
// by .key pointing to a containing list{}.
|
||||
type index_entry struct {
|
||||
|
||||
// list elem that entry is stored
|
||||
|
|
|
|||
37
vendor/codeberg.org/gruf/go-structr/key.go
generated
vendored
37
vendor/codeberg.org/gruf/go-structr/key.go
generated
vendored
|
|
@ -4,6 +4,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"codeberg.org/gruf/go-byteutil"
|
||||
"codeberg.org/gruf/go-mangler/v2"
|
||||
)
|
||||
|
||||
// Key represents one key to
|
||||
|
|
@ -14,6 +15,37 @@ type Key struct {
|
|||
raw []any
|
||||
}
|
||||
|
||||
// MakeKey generates Key{} from given parts.
|
||||
func MakeKey(parts ...any) Key {
|
||||
buf := new_buffer()
|
||||
buf.B = mangler.AppendMulti(buf.B[:0], parts...)
|
||||
key := string(buf.B)
|
||||
free_buffer(buf)
|
||||
return Key{
|
||||
raw: parts,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeKeys generates []Key{} from given (multiple) parts.
|
||||
func MakeKeys(parts ...[]any) []Key {
|
||||
keys := make([]Key, len(parts))
|
||||
if len(keys) != len(parts) {
|
||||
panic(assert("BCE"))
|
||||
}
|
||||
buf := new_buffer()
|
||||
for x, parts := range parts {
|
||||
buf.B = mangler.AppendMulti(buf.B[:0], parts...)
|
||||
key := string(buf.B)
|
||||
keys[x] = Key{
|
||||
raw: parts,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
free_buffer(buf)
|
||||
return keys
|
||||
}
|
||||
|
||||
// Key returns the underlying cache key string.
|
||||
// NOTE: this will not be log output friendly.
|
||||
func (k Key) Key() string {
|
||||
|
|
@ -31,11 +63,6 @@ func (k Key) Values() []any {
|
|||
return k.raw
|
||||
}
|
||||
|
||||
// Zero indicates a zero value key.
|
||||
func (k Key) Zero() bool {
|
||||
return (k.key == "")
|
||||
}
|
||||
|
||||
var buf_pool sync.Pool
|
||||
|
||||
// new_buffer returns a new initialized byte buffer.
|
||||
|
|
|
|||
8
vendor/codeberg.org/gruf/go-structr/list.go
generated
vendored
8
vendor/codeberg.org/gruf/go-structr/list.go
generated
vendored
|
|
@ -177,11 +177,3 @@ func (l *list) remove(elem *list_elem) {
|
|||
// Decr count
|
||||
l.len--
|
||||
}
|
||||
|
||||
// func (l *list) range_up(yield func(*list_elem) bool) {
|
||||
|
||||
// }
|
||||
|
||||
// func (l *list) range_down(yield func(*list_elem) bool) {
|
||||
|
||||
// }
|
||||
|
|
|
|||
5
vendor/codeberg.org/gruf/go-structr/queue.go
generated
vendored
5
vendor/codeberg.org/gruf/go-structr/queue.go
generated
vendored
|
|
@ -1,7 +1,6 @@
|
|||
package structr
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
|
@ -48,7 +47,7 @@ type Queue[StructType any] struct {
|
|||
// Init initializes the queue with given configuration
|
||||
// including struct fields to index, and necessary fns.
|
||||
func (q *Queue[T]) Init(config QueueConfig[T]) {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
t := get_type_iter[T]()
|
||||
|
||||
if len(config.Indices) == 0 {
|
||||
panic("no indices provided")
|
||||
|
|
@ -323,7 +322,7 @@ func (q *Queue[T]) index(value T) *indexed_item {
|
|||
}
|
||||
|
||||
func (q *Queue[T]) delete(i *indexed_item) {
|
||||
for len(i.indexed) != 0 {
|
||||
for len(i.indexed) > 0 {
|
||||
// Pop last indexed entry from list.
|
||||
entry := i.indexed[len(i.indexed)-1]
|
||||
i.indexed[len(i.indexed)-1] = nil
|
||||
|
|
|
|||
169
vendor/codeberg.org/gruf/go-structr/runtime.go
generated
vendored
169
vendor/codeberg.org/gruf/go-structr/runtime.go
generated
vendored
|
|
@ -1,5 +1,3 @@
|
|||
//go:build go1.22 && !go1.25
|
||||
|
||||
package structr
|
||||
|
||||
import (
|
||||
|
|
@ -11,17 +9,16 @@ import (
|
|||
"unicode/utf8"
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-mangler"
|
||||
"codeberg.org/gruf/go-mangler/v2"
|
||||
"codeberg.org/gruf/go-xunsafe"
|
||||
)
|
||||
|
||||
// struct_field contains pre-prepared type
|
||||
// information about a struct's field member,
|
||||
// including memory offset and hash function.
|
||||
type struct_field struct {
|
||||
rtype reflect.Type
|
||||
|
||||
// struct field type mangling
|
||||
// (i.e. fast serializing) fn.
|
||||
// mangle ...
|
||||
mangle mangler.Mangler
|
||||
|
||||
// zero value data, used when
|
||||
|
|
@ -30,18 +27,13 @@ type struct_field struct {
|
|||
zero unsafe.Pointer
|
||||
|
||||
// mangled zero value string,
|
||||
// if set this indicates zero
|
||||
// values of field not allowed
|
||||
// to check zero value keys.
|
||||
zerostr string
|
||||
|
||||
// offsets defines whereabouts in
|
||||
// memory this field is located.
|
||||
// memory this field is located,
|
||||
// and after how many dereferences.
|
||||
offsets []next_offset
|
||||
|
||||
// determines whether field type
|
||||
// is ptr-like in-memory, and so
|
||||
// requires a further dereference.
|
||||
likeptr bool
|
||||
}
|
||||
|
||||
// next_offset defines a next offset location
|
||||
|
|
@ -49,13 +41,22 @@ type struct_field struct {
|
|||
// derefences required, then by offset from
|
||||
// that final memory location.
|
||||
type next_offset struct {
|
||||
derefs uint
|
||||
derefs int
|
||||
offset uintptr
|
||||
}
|
||||
|
||||
// get_type_iter returns a prepared xunsafe.TypeIter{} for generic parameter type,
|
||||
// with flagIndir specifically set as we always take a reference to value type.
|
||||
func get_type_iter[T any]() xunsafe.TypeIter {
|
||||
rtype := reflect.TypeOf((*T)(nil)).Elem()
|
||||
flags := xunsafe.Reflect_flag(xunsafe.Abi_Type_Kind(rtype))
|
||||
flags |= xunsafe.Reflect_flagIndir // always comes from unsafe ptr
|
||||
return xunsafe.ToTypeIter(rtype, flags)
|
||||
}
|
||||
|
||||
// find_field will search for a struct field with given set of names,
|
||||
// where names is a len > 0 slice of names account for struct nesting.
|
||||
func find_field(t reflect.Type, names []string) (sfield struct_field) {
|
||||
func find_field(t xunsafe.TypeIter, names []string) (sfield struct_field, ftype reflect.Type) {
|
||||
var (
|
||||
// is_exported returns whether name is exported
|
||||
// from a package; can be func or struct field.
|
||||
|
|
@ -84,23 +85,42 @@ func find_field(t reflect.Type, names []string) (sfield struct_field) {
|
|||
// Pop next name.
|
||||
name := pop_name()
|
||||
|
||||
var off next_offset
|
||||
var n int
|
||||
rtype := t.Type
|
||||
flags := t.Flag
|
||||
|
||||
// Dereference any ptrs to struct.
|
||||
for t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
off.derefs++
|
||||
// Iteratively dereference pointer types.
|
||||
for rtype.Kind() == reflect.Pointer {
|
||||
|
||||
// If this actual indirect memory,
|
||||
// increase dereferences counter.
|
||||
if flags&xunsafe.Reflect_flagIndir != 0 {
|
||||
n++
|
||||
}
|
||||
|
||||
// Get next elem type.
|
||||
rtype = rtype.Elem()
|
||||
|
||||
// Get next set of dereferenced element type flags.
|
||||
flags = xunsafe.ReflectPointerElemFlags(flags, rtype)
|
||||
|
||||
// Update type iter info.
|
||||
t = t.Child(rtype, flags)
|
||||
}
|
||||
|
||||
// Check for valid struct type.
|
||||
if t.Kind() != reflect.Struct {
|
||||
panic(fmt.Sprintf("field %s is not struct (or ptr-to): %s", t, name))
|
||||
if rtype.Kind() != reflect.Struct {
|
||||
panic(fmt.Sprintf("field %s is not struct (or ptr-to): %s", rtype, name))
|
||||
}
|
||||
|
||||
// Set offset info.
|
||||
var off next_offset
|
||||
off.derefs = n
|
||||
|
||||
var ok bool
|
||||
|
||||
// Look for next field by name.
|
||||
field, ok = t.FieldByName(name)
|
||||
// Look for the next field by name.
|
||||
field, ok = rtype.FieldByName(name)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("unknown field: %s", name))
|
||||
}
|
||||
|
|
@ -109,24 +129,29 @@ func find_field(t reflect.Type, names []string) (sfield struct_field) {
|
|||
off.offset = field.Offset
|
||||
sfield.offsets = append(sfield.offsets, off)
|
||||
|
||||
// Set the next type.
|
||||
t = field.Type
|
||||
// Calculate value flags, and set next nested field type.
|
||||
flags = xunsafe.ReflectStructFieldFlags(t.Flag, field.Type)
|
||||
t = t.Child(field.Type, flags)
|
||||
}
|
||||
|
||||
// Check if ptr-like in-memory.
|
||||
sfield.likeptr = like_ptr(t)
|
||||
// Set final field type.
|
||||
ftype = t.TypeInfo.Type
|
||||
|
||||
// Set final type.
|
||||
sfield.rtype = t
|
||||
|
||||
// Find mangler for field type.
|
||||
// Get mangler from type info.
|
||||
sfield.mangle = mangler.Get(t)
|
||||
|
||||
// Get new zero value data ptr.
|
||||
v := reflect.New(t).Elem()
|
||||
zptr := eface_data(v.Interface())
|
||||
zstr := sfield.mangle(nil, zptr)
|
||||
sfield.zerostr = string(zstr)
|
||||
// Get field type as zero interface.
|
||||
v := reflect.New(t.Type).Elem()
|
||||
vi := v.Interface()
|
||||
|
||||
// Get argument mangler from iface.
|
||||
ti := xunsafe.TypeIterFrom(vi)
|
||||
mangleArg := mangler.Get(ti)
|
||||
|
||||
// Calculate zero value string.
|
||||
zptr := xunsafe.UnpackEface(vi)
|
||||
zstr := string(mangleArg(nil, zptr))
|
||||
sfield.zerostr = zstr
|
||||
sfield.zero = zptr
|
||||
|
||||
return
|
||||
|
|
@ -158,11 +183,6 @@ func extract_fields(ptr unsafe.Pointer, fields []struct_field) []unsafe.Pointer
|
|||
offset.offset)
|
||||
}
|
||||
|
||||
if field.likeptr && fptr != nil {
|
||||
// Further dereference value ptr.
|
||||
fptr = *(*unsafe.Pointer)(fptr)
|
||||
}
|
||||
|
||||
if fptr == nil {
|
||||
// Use zero value.
|
||||
fptr = field.zero
|
||||
|
|
@ -179,26 +199,26 @@ func extract_fields(ptr unsafe.Pointer, fields []struct_field) []unsafe.Pointer
|
|||
// information about a primary key struct's
|
||||
// field member, including memory offset.
|
||||
type pkey_field struct {
|
||||
rtype reflect.Type
|
||||
|
||||
// zero value data, used when
|
||||
// nil encountered during ptr
|
||||
// offset following.
|
||||
zero unsafe.Pointer
|
||||
|
||||
// offsets defines whereabouts in
|
||||
// memory this field is located.
|
||||
offsets []next_offset
|
||||
|
||||
// determines whether field type
|
||||
// is ptr-like in-memory, and so
|
||||
// requires a further dereference.
|
||||
likeptr bool
|
||||
}
|
||||
|
||||
// extract_pkey will extract a pointer from 'ptr', to
|
||||
// the primary key struct field defined by 'field'.
|
||||
func extract_pkey(ptr unsafe.Pointer, field pkey_field) unsafe.Pointer {
|
||||
for _, offset := range field.offsets {
|
||||
|
||||
// Dereference any ptrs to offset.
|
||||
ptr = deref(ptr, offset.derefs)
|
||||
if ptr == nil {
|
||||
return nil
|
||||
break
|
||||
}
|
||||
|
||||
// Jump forward by offset to next ptr.
|
||||
|
|
@ -206,43 +226,16 @@ func extract_pkey(ptr unsafe.Pointer, field pkey_field) unsafe.Pointer {
|
|||
offset.offset)
|
||||
}
|
||||
|
||||
if field.likeptr && ptr != nil {
|
||||
// Further dereference value ptr.
|
||||
ptr = *(*unsafe.Pointer)(ptr)
|
||||
if ptr == nil {
|
||||
// Use zero value.
|
||||
ptr = field.zero
|
||||
}
|
||||
|
||||
return ptr
|
||||
}
|
||||
|
||||
// like_ptr returns whether type's kind is ptr-like in-memory,
|
||||
// which indicates it may need a final additional dereference.
|
||||
func like_ptr(t reflect.Type) bool {
|
||||
switch t.Kind() {
|
||||
case reflect.Array:
|
||||
switch n := t.Len(); n {
|
||||
case 1:
|
||||
// specifically single elem arrays
|
||||
// follow like_ptr for contained type.
|
||||
return like_ptr(t.Elem())
|
||||
}
|
||||
case reflect.Struct:
|
||||
switch n := t.NumField(); n {
|
||||
case 1:
|
||||
// specifically single field structs
|
||||
// follow like_ptr for contained type.
|
||||
return like_ptr(t.Field(0).Type)
|
||||
}
|
||||
case reflect.Pointer,
|
||||
reflect.Map,
|
||||
reflect.Chan,
|
||||
reflect.Func:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// deref will dereference ptr 'n' times (or until nil).
|
||||
func deref(p unsafe.Pointer, n uint) unsafe.Pointer {
|
||||
func deref(p unsafe.Pointer, n int) unsafe.Pointer {
|
||||
for ; n > 0; n-- {
|
||||
if p == nil {
|
||||
return nil
|
||||
|
|
@ -252,24 +245,16 @@ func deref(p unsafe.Pointer, n uint) unsafe.Pointer {
|
|||
return p
|
||||
}
|
||||
|
||||
// eface_data returns the data ptr from an empty interface.
|
||||
func eface_data(a any) unsafe.Pointer {
|
||||
type eface struct{ _, data unsafe.Pointer }
|
||||
return (*eface)(unsafe.Pointer(&a)).data
|
||||
}
|
||||
|
||||
// assert can be called to indicated a block
|
||||
// of code should not be able to be reached,
|
||||
// it returns a BUG report with callsite.
|
||||
//
|
||||
//go:noinline
|
||||
func assert(assert string) string {
|
||||
pcs := make([]uintptr, 1)
|
||||
_ = runtime.Callers(2, pcs)
|
||||
fn := runtime.FuncForPC(pcs[0])
|
||||
funcname := "go-structr" // by default use just our library name
|
||||
if fn != nil {
|
||||
funcname = fn.Name()
|
||||
if frames := runtime.CallersFrames(pcs); frames != nil {
|
||||
frame, _ := frames.Next()
|
||||
funcname = frame.Function
|
||||
if i := strings.LastIndexByte(funcname, '/'); i != -1 {
|
||||
funcname = funcname[i+1:]
|
||||
}
|
||||
|
|
|
|||
46
vendor/codeberg.org/gruf/go-structr/timeline.go
generated
vendored
46
vendor/codeberg.org/gruf/go-structr/timeline.go
generated
vendored
|
|
@ -5,6 +5,7 @@ import (
|
|||
"os"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
|
@ -89,7 +90,7 @@ type Timeline[StructType any, PK cmp.Ordered] struct {
|
|||
// Init initializes the timeline with given configuration
|
||||
// including struct fields to index, and necessary fns.
|
||||
func (t *Timeline[T, PK]) Init(config TimelineConfig[T, PK]) {
|
||||
rt := reflect.TypeOf((*T)(nil)).Elem()
|
||||
ti := get_type_iter[T]()
|
||||
|
||||
if len(config.Indices) == 0 {
|
||||
panic("no indices provided")
|
||||
|
|
@ -99,6 +100,17 @@ func (t *Timeline[T, PK]) Init(config TimelineConfig[T, PK]) {
|
|||
panic("copy function must be provided")
|
||||
}
|
||||
|
||||
if strings.Contains(config.PKey.Fields, ",") {
|
||||
panic("primary key must contain only 1 field")
|
||||
}
|
||||
|
||||
// Verify primary key parameter type is correct.
|
||||
names := strings.Split(config.PKey.Fields, ".")
|
||||
if _, ftype := find_field(ti, names); //
|
||||
ftype != reflect.TypeFor[PK]() {
|
||||
panic("primary key field path and generic parameter type do not match")
|
||||
}
|
||||
|
||||
// Safely copy over
|
||||
// provided config.
|
||||
t.mutex.Lock()
|
||||
|
|
@ -108,21 +120,17 @@ func (t *Timeline[T, PK]) Init(config TimelineConfig[T, PK]) {
|
|||
// other indices are created as expected.
|
||||
t.indices = make([]Index, len(config.Indices)+1)
|
||||
t.indices[0].ptr = unsafe.Pointer(t)
|
||||
t.indices[0].init(rt, config.PKey, 0)
|
||||
if len(t.indices[0].fields) > 1 {
|
||||
panic("primary key must contain only 1 field")
|
||||
}
|
||||
t.indices[0].init(ti, config.PKey, 0)
|
||||
for i, cfg := range config.Indices {
|
||||
t.indices[i+1].ptr = unsafe.Pointer(t)
|
||||
t.indices[i+1].init(rt, cfg, 0)
|
||||
t.indices[i+1].init(ti, cfg, 0)
|
||||
}
|
||||
|
||||
// Extract pkey details from index.
|
||||
field := t.indices[0].fields[0]
|
||||
t.pkey = pkey_field{
|
||||
rtype: field.rtype,
|
||||
zero: field.zero,
|
||||
offsets: field.offsets,
|
||||
likeptr: field.likeptr,
|
||||
}
|
||||
|
||||
// Copy over remaining.
|
||||
|
|
@ -220,15 +228,7 @@ func (t *Timeline[T, PK]) Insert(values ...T) int {
|
|||
|
||||
// Extract primary key from vptr.
|
||||
kptr := extract_pkey(vptr, t.pkey)
|
||||
|
||||
var pkey PK
|
||||
if kptr != nil {
|
||||
// Cast as PK type.
|
||||
pkey = *(*PK)(kptr)
|
||||
} else {
|
||||
// Use zero value pointer.
|
||||
kptr = unsafe.Pointer(&pkey)
|
||||
}
|
||||
pkey := *(*PK)(kptr)
|
||||
|
||||
// Append wrapped value to slice with
|
||||
// the acquire pointers and primary key.
|
||||
|
|
@ -241,10 +241,8 @@ func (t *Timeline[T, PK]) Insert(values ...T) int {
|
|||
}
|
||||
}
|
||||
|
||||
var last *list_elem
|
||||
|
||||
// BEFORE inserting the prepared slice of value copies w/ primary
|
||||
// keys, sort them by their primary key, ascending. This permits
|
||||
// keys, sort them by their primary key, descending. This permits
|
||||
// us to re-use the 'last' timeline position as next insert cursor.
|
||||
// Otherwise we would have to iterate from 'head' every single time.
|
||||
slices.SortFunc(with_keys, func(a, b value_with_pk[T, PK]) int {
|
||||
|
|
@ -259,6 +257,8 @@ func (t *Timeline[T, PK]) Insert(values ...T) int {
|
|||
}
|
||||
})
|
||||
|
||||
var last *list_elem
|
||||
|
||||
// Store each value in the timeline,
|
||||
// updating the last used list element
|
||||
// each time so we don't have to iter
|
||||
|
|
@ -1071,7 +1071,7 @@ indexing:
|
|||
}
|
||||
|
||||
func (t *Timeline[T, PK]) delete(i *timeline_item) {
|
||||
for len(i.indexed) != 0 {
|
||||
for len(i.indexed) > 0 {
|
||||
// Pop last indexed entry from list.
|
||||
entry := i.indexed[len(i.indexed)-1]
|
||||
i.indexed[len(i.indexed)-1] = nil
|
||||
|
|
@ -1126,9 +1126,9 @@ func from_timeline_item(item *timeline_item) *indexed_item {
|
|||
func to_timeline_item(item *indexed_item) *timeline_item {
|
||||
to := (*timeline_item)(unsafe.Pointer(item))
|
||||
if to.ck != ^uint(0) {
|
||||
// ensure check bits are set indicating
|
||||
// ensure check bits set, indicating
|
||||
// it was a timeline_item originally.
|
||||
panic(assert("check bits are set"))
|
||||
panic(assert("t.ck = ^uint(0)"))
|
||||
}
|
||||
return to
|
||||
}
|
||||
|
|
|
|||
13
vendor/codeberg.org/gruf/go-structr/util.go
generated
vendored
13
vendor/codeberg.org/gruf/go-structr/util.go
generated
vendored
|
|
@ -1,13 +0,0 @@
|
|||
package structr
|
||||
|
||||
// once only executes 'fn' once.
|
||||
func once(fn func()) func() {
|
||||
var once int32
|
||||
return func() {
|
||||
if once != 0 {
|
||||
return
|
||||
}
|
||||
once = 1
|
||||
fn()
|
||||
}
|
||||
}
|
||||
6
vendor/github.com/tomnomnom/linkheader/.travis.yml
generated
vendored
6
vendor/github.com/tomnomnom/linkheader/.travis.yml
generated
vendored
|
|
@ -1,6 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
- 1.7
|
||||
- tip
|
||||
22
vendor/modules.txt
vendored
22
vendor/modules.txt
vendored
|
|
@ -221,7 +221,7 @@ code.superseriousbusiness.org/oauth2/v4/server
|
|||
# codeberg.org/gruf/go-bitutil v1.1.0
|
||||
## explicit; go 1.19
|
||||
codeberg.org/gruf/go-bitutil
|
||||
# codeberg.org/gruf/go-bytesize v1.0.3
|
||||
# codeberg.org/gruf/go-bytesize v1.0.4
|
||||
## explicit; go 1.17
|
||||
codeberg.org/gruf/go-bytesize
|
||||
# codeberg.org/gruf/go-byteutil v1.3.0
|
||||
|
|
@ -247,7 +247,7 @@ codeberg.org/gruf/go-fastcopy
|
|||
# codeberg.org/gruf/go-fastpath/v2 v2.0.0
|
||||
## explicit; go 1.14
|
||||
codeberg.org/gruf/go-fastpath/v2
|
||||
# codeberg.org/gruf/go-ffmpreg v0.6.8
|
||||
# codeberg.org/gruf/go-ffmpreg v0.6.9
|
||||
## explicit; go 1.22.0
|
||||
codeberg.org/gruf/go-ffmpreg/embed
|
||||
codeberg.org/gruf/go-ffmpreg/wasm
|
||||
|
|
@ -258,23 +258,23 @@ codeberg.org/gruf/go-iotools
|
|||
## explicit; go 1.20
|
||||
codeberg.org/gruf/go-kv
|
||||
codeberg.org/gruf/go-kv/format
|
||||
# codeberg.org/gruf/go-kv/v2 v2.0.6
|
||||
# codeberg.org/gruf/go-kv/v2 v2.0.7
|
||||
## explicit; go 1.24.5
|
||||
codeberg.org/gruf/go-kv/v2
|
||||
codeberg.org/gruf/go-kv/v2/format
|
||||
# codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
||||
## explicit; go 1.21.3
|
||||
codeberg.org/gruf/go-list
|
||||
# codeberg.org/gruf/go-mangler v1.4.4
|
||||
## explicit; go 1.19
|
||||
codeberg.org/gruf/go-mangler
|
||||
# codeberg.org/gruf/go-mangler/v2 v2.0.6
|
||||
## explicit; go 1.24.5
|
||||
codeberg.org/gruf/go-mangler/v2
|
||||
# codeberg.org/gruf/go-maps v1.0.4
|
||||
## explicit; go 1.20
|
||||
codeberg.org/gruf/go-maps
|
||||
# codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
|
||||
## explicit; go 1.22.2
|
||||
codeberg.org/gruf/go-mempool
|
||||
# codeberg.org/gruf/go-mutexes v1.5.2
|
||||
# codeberg.org/gruf/go-mutexes v1.5.3
|
||||
## explicit; go 1.22.2
|
||||
codeberg.org/gruf/go-mutexes
|
||||
# codeberg.org/gruf/go-runners v1.6.3
|
||||
|
|
@ -293,8 +293,8 @@ codeberg.org/gruf/go-storage/disk
|
|||
codeberg.org/gruf/go-storage/internal
|
||||
codeberg.org/gruf/go-storage/memory
|
||||
codeberg.org/gruf/go-storage/s3
|
||||
# codeberg.org/gruf/go-structr v0.9.7
|
||||
## explicit; go 1.22
|
||||
# codeberg.org/gruf/go-structr v0.9.8
|
||||
## explicit; go 1.24.5
|
||||
codeberg.org/gruf/go-structr
|
||||
# codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73
|
||||
## explicit; go 1.24.5
|
||||
|
|
@ -916,8 +916,8 @@ github.com/tinylib/msgp/msgp
|
|||
# github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc
|
||||
## explicit
|
||||
github.com/tmthrgd/go-hex
|
||||
# github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||
## explicit
|
||||
# github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e
|
||||
## explicit; go 1.13
|
||||
github.com/tomnomnom/linkheader
|
||||
# github.com/toqueteos/webbrowser v1.2.0
|
||||
## explicit; go 1.12
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue