mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-21 16:55:38 +03:00
update go-structr to v0.8.11 (#3380)
This commit is contained in:
parent
e3019eada4
commit
c17abea921
11 changed files with 306 additions and 91 deletions
2
go.mod
2
go.mod
|
@ -22,7 +22,7 @@ require (
|
|||
codeberg.org/gruf/go-runners v1.6.3
|
||||
codeberg.org/gruf/go-sched v1.2.4
|
||||
codeberg.org/gruf/go-storage v0.2.0
|
||||
codeberg.org/gruf/go-structr v0.8.10
|
||||
codeberg.org/gruf/go-structr v0.8.11
|
||||
codeberg.org/superseriousbusiness/exif-terminator v0.9.0
|
||||
github.com/DmitriyVTitov/size v1.5.0
|
||||
github.com/KimMachineGun/automemlimit v0.6.1
|
||||
|
|
4
go.sum
4
go.sum
|
@ -72,8 +72,8 @@ codeberg.org/gruf/go-sched v1.2.4 h1:ddBB9o0D/2oU8NbQ0ldN5aWxogpXPRBATWi58+p++Hw
|
|||
codeberg.org/gruf/go-sched v1.2.4/go.mod h1:wad6l+OcYGWMA2TzNLMmLObsrbBDxdJfEy5WvTgBjNk=
|
||||
codeberg.org/gruf/go-storage v0.2.0 h1:mKj3Lx6AavEkuXXtxqPhdq+akW9YwrnP16yQBF7K5ZI=
|
||||
codeberg.org/gruf/go-storage v0.2.0/go.mod h1:o3GzMDE5QNUaRnm/daUzFqvuAaC4utlgXDXYO79sWKU=
|
||||
codeberg.org/gruf/go-structr v0.8.10 h1:uSapW97/StRnYEhCtycaM0isCsEMYC+tx/knYr6SiVo=
|
||||
codeberg.org/gruf/go-structr v0.8.10/go.mod h1:zkoXVrAnKosh8VFAsbP/Hhs8FmLBjbVVy5w/Ngm8ApM=
|
||||
codeberg.org/gruf/go-structr v0.8.11 h1:I3cQCHpK3fQSXWaaUfksAJRN4+efULiuF11Oi/m8c+o=
|
||||
codeberg.org/gruf/go-structr v0.8.11/go.mod h1:zkoXVrAnKosh8VFAsbP/Hhs8FmLBjbVVy5w/Ngm8ApM=
|
||||
codeberg.org/superseriousbusiness/exif-terminator v0.9.0 h1:/EfyGI6HIrbkhFwgXGSjZ9o1kr/+k8v4mKdfXTH02Go=
|
||||
codeberg.org/superseriousbusiness/exif-terminator v0.9.0/go.mod h1:gCWKduudUWFzsnixoMzu0FYVdxHWG+AbXnZ50DqxsUE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
|
|
47
vendor/codeberg.org/gruf/go-structr/cache.go
generated
vendored
47
vendor/codeberg.org/gruf/go-structr/cache.go
generated
vendored
|
@ -119,9 +119,9 @@ func (c *Cache[T]) Init(config CacheConfig[T]) {
|
|||
|
||||
// Index selects index with given name from cache, else panics.
|
||||
func (c *Cache[T]) Index(name string) *Index {
|
||||
for i := range c.indices {
|
||||
if c.indices[i].name == name {
|
||||
return &c.indices[i]
|
||||
for i, idx := range c.indices {
|
||||
if idx.name == name {
|
||||
return &(c.indices[i])
|
||||
}
|
||||
}
|
||||
panic("unknown index: " + name)
|
||||
|
@ -337,13 +337,16 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error))
|
|||
panic("not initialized")
|
||||
}
|
||||
|
||||
for i := 0; i < len(keys); {
|
||||
// Iterate keys and catch uncached.
|
||||
toLoad := make([]Key, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
|
||||
// Value length before
|
||||
// any below appends.
|
||||
before := len(values)
|
||||
|
||||
// Concatenate all *values* from cached items.
|
||||
index.get(keys[i].key, func(item *indexed_item) {
|
||||
index.get(key.key, func(item *indexed_item) {
|
||||
if value, ok := item.data.(T); ok {
|
||||
// Append value COPY.
|
||||
value = c.copy(value)
|
||||
|
@ -358,30 +361,22 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error))
|
|||
|
||||
// Only if values changed did
|
||||
// we actually find anything.
|
||||
if len(values) != before {
|
||||
|
||||
// We found values at key,
|
||||
// drop key from the slice.
|
||||
copy(keys[i:], keys[i+1:])
|
||||
keys = keys[:len(keys)-1]
|
||||
continue
|
||||
if len(values) == before {
|
||||
toLoad = append(toLoad, key)
|
||||
}
|
||||
|
||||
// Iter
|
||||
i++
|
||||
}
|
||||
|
||||
// Done with
|
||||
// the lock.
|
||||
unlock()
|
||||
|
||||
if len(keys) == 0 {
|
||||
if len(toLoad) == 0 {
|
||||
// We loaded everything!
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// Load uncached values.
|
||||
uncached, err := load(keys)
|
||||
// Load uncached key values.
|
||||
uncached, err := load(toLoad)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -515,8 +510,8 @@ func (c *Cache[T]) Trim(perc float64) {
|
|||
}
|
||||
|
||||
// Compact index data stores.
|
||||
for i := range c.indices {
|
||||
c.indices[i].data.Compact()
|
||||
for _, idx := range c.indices {
|
||||
(&idx).data.Compact()
|
||||
}
|
||||
|
||||
// Done with lock.
|
||||
|
@ -536,17 +531,17 @@ func (c *Cache[T]) Len() int {
|
|||
|
||||
// Debug returns debug stats about cache.
|
||||
func (c *Cache[T]) Debug() map[string]any {
|
||||
m := make(map[string]any)
|
||||
m := make(map[string]any, 2)
|
||||
c.mutex.Lock()
|
||||
m["lru"] = c.lru.len
|
||||
indices := make(map[string]any)
|
||||
indices := make(map[string]any, len(c.indices))
|
||||
m["indices"] = indices
|
||||
for i := range c.indices {
|
||||
for _, idx := range c.indices {
|
||||
var n uint64
|
||||
for _, l := range c.indices[i].data.m {
|
||||
for _, l := range idx.data.m {
|
||||
n += uint64(l.len)
|
||||
}
|
||||
indices[c.indices[i].name] = n
|
||||
indices[idx.name] = n
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
return m
|
||||
|
@ -588,7 +583,7 @@ func (c *Cache[T]) store_value(index *Index, key string, value T) {
|
|||
|
||||
for i := range c.indices {
|
||||
// Get current index ptr.
|
||||
idx := &(c.indices[i])
|
||||
idx := (&c.indices[i])
|
||||
if idx == index {
|
||||
|
||||
// Already stored under
|
||||
|
|
42
vendor/codeberg.org/gruf/go-structr/index.go
generated
vendored
42
vendor/codeberg.org/gruf/go-structr/index.go
generated
vendored
|
@ -197,8 +197,13 @@ func (i *Index) get(key string, hook func(*indexed_item)) {
|
|||
return
|
||||
}
|
||||
|
||||
// Iterate all entries in list.
|
||||
l.rangefn(func(elem *list_elem) {
|
||||
// Iterate the list.
|
||||
for elem := l.head; //
|
||||
elem != nil; //
|
||||
{
|
||||
// Get next before
|
||||
// any modification.
|
||||
next := elem.next
|
||||
|
||||
// Extract element entry + item.
|
||||
entry := (*index_entry)(elem.data)
|
||||
|
@ -206,18 +211,21 @@ func (i *Index) get(key string, hook func(*indexed_item)) {
|
|||
|
||||
// Pass to hook.
|
||||
hook(item)
|
||||
})
|
||||
|
||||
// Set next.
|
||||
elem = next
|
||||
}
|
||||
}
|
||||
|
||||
// key uses hasher to generate Key{} from given raw parts.
|
||||
func (i *Index) key(buf *byteutil.Buffer, parts []unsafe.Pointer) string {
|
||||
buf.B = buf.B[:0]
|
||||
if len(parts) != len(i.fields) {
|
||||
panicf("incorrect number key parts: want=%d received=%d",
|
||||
len(i.fields),
|
||||
len(parts),
|
||||
)
|
||||
}
|
||||
buf.B = buf.B[:0]
|
||||
if !allow_zero(i.flags) {
|
||||
for x, field := range i.fields {
|
||||
before := len(buf.B)
|
||||
|
@ -301,8 +309,13 @@ func (i *Index) delete(key string, hook func(*indexed_item)) {
|
|||
// Delete at hash.
|
||||
i.data.Delete(key)
|
||||
|
||||
// Iterate entries in list.
|
||||
l.rangefn(func(elem *list_elem) {
|
||||
// Iterate the list.
|
||||
for elem := l.head; //
|
||||
elem != nil; //
|
||||
{
|
||||
// Get next before
|
||||
// any modification.
|
||||
next := elem.next
|
||||
|
||||
// Remove elem.
|
||||
l.remove(elem)
|
||||
|
@ -319,7 +332,10 @@ func (i *Index) delete(key string, hook func(*indexed_item)) {
|
|||
|
||||
// Pass to hook.
|
||||
hook(item)
|
||||
})
|
||||
|
||||
// Set next.
|
||||
elem = next
|
||||
}
|
||||
|
||||
// Release list.
|
||||
free_list(l)
|
||||
|
@ -375,17 +391,21 @@ var index_entry_pool sync.Pool
|
|||
func new_index_entry() *index_entry {
|
||||
v := index_entry_pool.Get()
|
||||
if v == nil {
|
||||
v = new(index_entry)
|
||||
e := new(index_entry)
|
||||
e.elem.data = unsafe.Pointer(e)
|
||||
v = e
|
||||
}
|
||||
entry := v.(*index_entry)
|
||||
ptr := unsafe.Pointer(entry)
|
||||
entry.elem.data = ptr
|
||||
return entry
|
||||
}
|
||||
|
||||
// free_index_entry releases the index_entry.
|
||||
func free_index_entry(entry *index_entry) {
|
||||
entry.elem.data = nil
|
||||
if entry.elem.next != nil ||
|
||||
entry.elem.prev != nil {
|
||||
should_not_reach()
|
||||
return
|
||||
}
|
||||
entry.key = ""
|
||||
entry.index = nil
|
||||
entry.item = nil
|
||||
|
|
16
vendor/codeberg.org/gruf/go-structr/item.go
generated
vendored
16
vendor/codeberg.org/gruf/go-structr/item.go
generated
vendored
|
@ -24,18 +24,22 @@ var indexed_item_pool sync.Pool
|
|||
func new_indexed_item() *indexed_item {
|
||||
v := indexed_item_pool.Get()
|
||||
if v == nil {
|
||||
v = new(indexed_item)
|
||||
i := new(indexed_item)
|
||||
i.elem.data = unsafe.Pointer(i)
|
||||
v = i
|
||||
}
|
||||
item := v.(*indexed_item)
|
||||
ptr := unsafe.Pointer(item)
|
||||
item.elem.data = ptr
|
||||
return item
|
||||
}
|
||||
|
||||
// free_indexed_item releases the indexed_item.
|
||||
func free_indexed_item(item *indexed_item) {
|
||||
item.elem.data = nil
|
||||
item.indexed = item.indexed[:0]
|
||||
if len(item.indexed) > 0 ||
|
||||
item.elem.next != nil ||
|
||||
item.elem.prev != nil {
|
||||
should_not_reach()
|
||||
return
|
||||
}
|
||||
item.data = nil
|
||||
indexed_item_pool.Put(item)
|
||||
}
|
||||
|
@ -50,7 +54,7 @@ func (i *indexed_item) drop_index(entry *index_entry) {
|
|||
continue
|
||||
}
|
||||
|
||||
// Move all index entries down + reslice.
|
||||
// Reslice index entries minus 'x'.
|
||||
_ = copy(i.indexed[x:], i.indexed[x+1:])
|
||||
i.indexed[len(i.indexed)-1] = nil
|
||||
i.indexed = i.indexed[:len(i.indexed)-1]
|
||||
|
|
52
vendor/codeberg.org/gruf/go-structr/list.go
generated
vendored
52
vendor/codeberg.org/gruf/go-structr/list.go
generated
vendored
|
@ -40,9 +40,12 @@ func new_list() *list {
|
|||
|
||||
// free_list releases the list.
|
||||
func free_list(list *list) {
|
||||
list.head = nil
|
||||
list.tail = nil
|
||||
list.len = 0
|
||||
if list.head != nil ||
|
||||
list.tail != nil ||
|
||||
list.len != 0 {
|
||||
should_not_reach()
|
||||
return
|
||||
}
|
||||
list_pool.Put(list)
|
||||
}
|
||||
|
||||
|
@ -115,21 +118,28 @@ func (l *list) remove(elem *list_elem) {
|
|||
elem.prev = nil
|
||||
|
||||
switch {
|
||||
// elem is ONLY one in list.
|
||||
case next == nil && prev == nil:
|
||||
l.head = nil
|
||||
l.tail = nil
|
||||
case next == nil:
|
||||
if prev == nil {
|
||||
// next == nil && prev == nil
|
||||
//
|
||||
// elem is ONLY one in list.
|
||||
l.head = nil
|
||||
l.tail = nil
|
||||
} else {
|
||||
// next == nil && prev != nil
|
||||
//
|
||||
// elem is last in list.
|
||||
l.tail = prev
|
||||
prev.next = nil
|
||||
}
|
||||
|
||||
// elem is front in list.
|
||||
case next != nil && prev == nil:
|
||||
case prev == nil:
|
||||
// next != nil && prev == nil
|
||||
//
|
||||
// elem is front in list.
|
||||
l.head = next
|
||||
next.prev = nil
|
||||
|
||||
// elem is last in list.
|
||||
case prev != nil && next == nil:
|
||||
l.tail = prev
|
||||
prev.next = nil
|
||||
|
||||
// elem in middle of list.
|
||||
default:
|
||||
next.prev = prev
|
||||
|
@ -139,17 +149,3 @@ func (l *list) remove(elem *list_elem) {
|
|||
// Decr count
|
||||
l.len--
|
||||
}
|
||||
|
||||
// rangefn will range all elems in list, passing each to fn.
|
||||
func (l *list) rangefn(fn func(*list_elem)) {
|
||||
if fn == nil {
|
||||
panic("nil fn")
|
||||
}
|
||||
for e := l.head; //
|
||||
e != nil; //
|
||||
{
|
||||
n := e.next
|
||||
fn(e)
|
||||
e = n
|
||||
}
|
||||
}
|
||||
|
|
180
vendor/codeberg.org/gruf/go-structr/ordered_list.bak
generated
vendored
Normal file
180
vendor/codeberg.org/gruf/go-structr/ordered_list.bak
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
package structr
|
||||
|
||||
import "sync"
|
||||
|
||||
type Timeline[StructType any, PK comparable] struct {
|
||||
|
||||
// hook functions.
|
||||
pkey func(StructType) PK
|
||||
gte func(PK, PK) bool
|
||||
lte func(PK, PK) bool
|
||||
copy func(StructType) StructType
|
||||
|
||||
// main underlying
|
||||
// ordered item list.
|
||||
list list
|
||||
|
||||
// indices used in storing passed struct
|
||||
// types by user defined sets of fields.
|
||||
indices []Index
|
||||
|
||||
// protective mutex, guards:
|
||||
// - TODO
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (t *Timeline[T, PK]) Init(config any) {
|
||||
|
||||
}
|
||||
|
||||
func (t *Timeline[T, PK]) Index(name string) *Index {
|
||||
for i := range t.indices {
|
||||
if t.indices[i].name == name {
|
||||
return &t.indices[i]
|
||||
}
|
||||
}
|
||||
panic("unknown index: " + name)
|
||||
}
|
||||
|
||||
func (t *Timeline[T, PK]) Insert(values ...T) {
|
||||
|
||||
}
|
||||
|
||||
func (t *Timeline[T, PK]) LoadTop(min, max PK, length int, load func(min, max PK, length int) ([]T, error)) ([]T, error) {
|
||||
// Allocate expected no. values.
|
||||
values := make([]T, 0, length)
|
||||
|
||||
// Acquire lock.
|
||||
t.mutex.Lock()
|
||||
|
||||
// Wrap unlock to only do once.
|
||||
unlock := once(t.mutex.Unlock)
|
||||
defer unlock()
|
||||
|
||||
// Check init'd.
|
||||
if t.copy == nil {
|
||||
panic("not initialized")
|
||||
}
|
||||
|
||||
// Iterate through linked list from top (i.e. head).
|
||||
for next := t.list.head; next != nil; next = next.next {
|
||||
|
||||
// Check if we've gathered
|
||||
// enough values from timeline.
|
||||
if len(values) >= length {
|
||||
return values, nil
|
||||
}
|
||||
|
||||
item := (*indexed_item)(next.data)
|
||||
value := item.data.(T)
|
||||
pkey := t.pkey(value)
|
||||
|
||||
// Check if below min.
|
||||
if t.lte(pkey, min) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Update min.
|
||||
min = pkey
|
||||
|
||||
// Check if above max.
|
||||
if t.gte(pkey, max) {
|
||||
break
|
||||
}
|
||||
|
||||
// Append value copy.
|
||||
value = t.copy(value)
|
||||
values = append(values, value)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timeline[T, PK]) LoadBottom(min, max PK, length int, load func(min, max PK, length int) ([]T, error)) ([]T, error) {
|
||||
// Allocate expected no. values.
|
||||
values := make([]T, 0, length)
|
||||
|
||||
// Acquire lock.
|
||||
t.mutex.Lock()
|
||||
|
||||
// Wrap unlock to only do once.
|
||||
unlock := once(t.mutex.Unlock)
|
||||
defer unlock()
|
||||
|
||||
// Check init'd.
|
||||
if t.copy == nil {
|
||||
panic("not initialized")
|
||||
}
|
||||
|
||||
// Iterate through linked list from bottom (i.e. tail).
|
||||
for next := t.list.tail; next != nil; next = next.prev {
|
||||
|
||||
// Check if we've gathered
|
||||
// enough values from timeline.
|
||||
if len(values) >= length {
|
||||
return values, nil
|
||||
}
|
||||
|
||||
item := (*indexed_item)(next.data)
|
||||
value := item.data.(T)
|
||||
pkey := t.pkey(value)
|
||||
|
||||
// Check if above max.
|
||||
if t.gte(pkey, max) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Update max.
|
||||
max = pkey
|
||||
|
||||
// Check if below min.
|
||||
if t.lte(pkey, min) {
|
||||
break
|
||||
}
|
||||
|
||||
// Append value copy.
|
||||
value = t.copy(value)
|
||||
values = append(values, value)
|
||||
}
|
||||
|
||||
// Done with
|
||||
// the lock.
|
||||
unlock()
|
||||
|
||||
// Attempt to load values up to given length.
|
||||
next, err := load(min, max, length-len(values))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Acquire lock.
|
||||
t.mutex.Lock()
|
||||
|
||||
// Store uncached values.
|
||||
for i := range next {
|
||||
t.store_value(
|
||||
nil, "",
|
||||
uncached[i],
|
||||
)
|
||||
}
|
||||
|
||||
// Done with lock.
|
||||
t.mutex.Unlock()
|
||||
|
||||
// Append uncached to return values.
|
||||
values = append(values, next...)
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (t *Timeline[T, PK]) index(value T) *indexed_item {
|
||||
pk := t.pkey(value)
|
||||
|
||||
switch {
|
||||
case t.list.len == 0:
|
||||
|
||||
case pk < t.list.head.data:
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timeline[T, PK]) delete(item *indexed_item) {
|
||||
|
||||
}
|
16
vendor/codeberg.org/gruf/go-structr/queue.go
generated
vendored
16
vendor/codeberg.org/gruf/go-structr/queue.go
generated
vendored
|
@ -68,9 +68,9 @@ func (q *Queue[T]) Init(config QueueConfig[T]) {
|
|||
|
||||
// Index selects index with given name from queue, else panics.
|
||||
func (q *Queue[T]) Index(name string) *Index {
|
||||
for i := range q.indices {
|
||||
if q.indices[i].name == name {
|
||||
return &q.indices[i]
|
||||
for i, idx := range q.indices {
|
||||
if idx.name == name {
|
||||
return &(q.indices[i])
|
||||
}
|
||||
}
|
||||
panic("unknown index: " + name)
|
||||
|
@ -207,17 +207,17 @@ func (q *Queue[T]) Len() int {
|
|||
|
||||
// Debug returns debug stats about queue.
|
||||
func (q *Queue[T]) Debug() map[string]any {
|
||||
m := make(map[string]any)
|
||||
m := make(map[string]any, 2)
|
||||
q.mutex.Lock()
|
||||
m["queue"] = q.queue.len
|
||||
indices := make(map[string]any)
|
||||
indices := make(map[string]any, len(q.indices))
|
||||
m["indices"] = indices
|
||||
for i := range q.indices {
|
||||
for _, idx := range q.indices {
|
||||
var n uint64
|
||||
for _, l := range q.indices[i].data.m {
|
||||
for _, l := range idx.data.m {
|
||||
n += uint64(l.len)
|
||||
}
|
||||
indices[q.indices[i].name] = n
|
||||
indices[idx.name] = n
|
||||
}
|
||||
q.mutex.Unlock()
|
||||
return m
|
||||
|
|
28
vendor/codeberg.org/gruf/go-structr/runtime.go
generated
vendored
28
vendor/codeberg.org/gruf/go-structr/runtime.go
generated
vendored
|
@ -2,7 +2,10 @@ package structr
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
|
@ -182,7 +185,32 @@ 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
|
||||
}
|
||||
|
||||
// panicf provides a panic with string formatting.
|
||||
func panicf(format string, args ...any) {
|
||||
panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// should_not_reach can be called to indicated a
|
||||
// block of code should not be able to be reached,
|
||||
// else it prints callsite info with a BUG report.
|
||||
//
|
||||
//go:noinline
|
||||
func should_not_reach() {
|
||||
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 i := strings.LastIndexByte(funcname, '/'); i != -1 {
|
||||
funcname = funcname[i+1:]
|
||||
}
|
||||
}
|
||||
os.Stderr.WriteString("BUG: assertion failed in " + funcname + "\n")
|
||||
}
|
||||
|
|
8
vendor/codeberg.org/gruf/go-structr/util.go
generated
vendored
8
vendor/codeberg.org/gruf/go-structr/util.go
generated
vendored
|
@ -1,7 +1,5 @@
|
|||
package structr
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// once only executes 'fn' once.
|
||||
func once(fn func()) func() {
|
||||
var once int32
|
||||
|
@ -13,9 +11,3 @@ func once(fn func()) func() {
|
|||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -66,7 +66,7 @@ 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.8.10
|
||||
# codeberg.org/gruf/go-structr v0.8.11
|
||||
## explicit; go 1.21
|
||||
codeberg.org/gruf/go-structr
|
||||
# codeberg.org/superseriousbusiness/exif-terminator v0.9.0
|
||||
|
|
Loading…
Reference in a new issue