diff --git a/go.mod b/go.mod index c87468255..2e018e2a3 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( codeberg.org/gruf/go-runners v1.6.2 codeberg.org/gruf/go-sched v1.2.3 codeberg.org/gruf/go-store/v2 v2.2.4 - codeberg.org/gruf/go-structr v0.6.0 + codeberg.org/gruf/go-structr v0.6.2 codeberg.org/superseriousbusiness/exif-terminator v0.7.0 github.com/DmitriyVTitov/size v1.5.0 github.com/KimMachineGun/automemlimit v0.5.0 diff --git a/go.sum b/go.sum index 3f12c7947..a0809cc88 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ codeberg.org/gruf/go-sched v1.2.3 h1:H5ViDxxzOBR3uIyGBCf0eH8b1L8wMybOXcdtUUTXZHk codeberg.org/gruf/go-sched v1.2.3/go.mod h1:vT9uB6KWFIIwnG9vcPY2a0alYNoqdL1mSzRM8I+PK7A= codeberg.org/gruf/go-store/v2 v2.2.4 h1:8HO1Jh2gg7boQKA3hsDAIXd9zwieu5uXwDXEcTOD9js= codeberg.org/gruf/go-store/v2 v2.2.4/go.mod h1:zI4VWe5CpXAktYMtaBMrgA5QmO0sQH53LBRvfn1huys= -codeberg.org/gruf/go-structr v0.6.0 h1:cFiTE0SN1RzgX833y5DnPgWcdVNfqcvLVvPGLTNcvjg= -codeberg.org/gruf/go-structr v0.6.0/go.mod h1:K1FXkUyO6N/JKt8aWqyQ8rtW7Z9ZmXKWP8mFAQ2OJjE= +codeberg.org/gruf/go-structr v0.6.2 h1:1zs7UkPBsRGRDMHhrfFL7GrwAyPHxFXCchu8ADv/zuM= +codeberg.org/gruf/go-structr v0.6.2/go.mod h1:K1FXkUyO6N/JKt8aWqyQ8rtW7Z9ZmXKWP8mFAQ2OJjE= codeberg.org/superseriousbusiness/exif-terminator v0.7.0 h1:Y6VApSXhKqExG0H2hZ2JelRK4xmWdjDQjn13CpEfzko= codeberg.org/superseriousbusiness/exif-terminator v0.7.0/go.mod h1:gCWKduudUWFzsnixoMzu0FYVdxHWG+AbXnZ50DqxsUE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= diff --git a/vendor/codeberg.org/gruf/go-structr/cache.go b/vendor/codeberg.org/gruf/go-structr/cache.go index 7b0772acf..9d5e7f912 100644 --- a/vendor/codeberg.org/gruf/go-structr/cache.go +++ b/vendor/codeberg.org/gruf/go-structr/cache.go @@ -255,18 +255,21 @@ func (c *Cache[T]) LoadOne(index *Index, key Key, load func() (T, error)) (T, er item := index.get_one(key) if ok = (item != nil); ok { - if value, is := item.data.(T); is { + var is bool + + if val, is = item.data.(T); is { // Set value COPY. - val = c.copy(value) + val = c.copy(val) // Push to front of LRU list, USING // THE ITEM'S LRU ENTRY, NOT THE // INDEX KEY ENTRY. VERY IMPORTANT!! c.lru.move_front(&item.elem) - } else if error, is := item.data.(error); is { - // Return error. - err = error + } else { + + // Attempt to return error. + err, _ = item.data.(error) } } @@ -423,10 +426,10 @@ func (c *Cache[T]) Invalidate(index *Index, keys ...Key) { // Preallocate expected ret slice. values := make([]T, 0, len(keys)) - for i := range keys { + for _, key := range keys { // Delete all items under key from index, collecting // value items and dropping them from all their indices. - index.delete(keys[i], func(item *indexed_item) { + index.delete(key, func(item *indexed_item) { if value, ok := item.data.(T); ok { // No need to copy, as item @@ -524,6 +527,9 @@ func (c *Cache[T]) store_value(index *Index, key Key, value T) { index.append(key, item) } + // Get ptr to value data. + ptr := unsafe.Pointer(&value) + // Acquire key buf. buf := new_buffer() @@ -538,7 +544,10 @@ func (c *Cache[T]) store_value(index *Index, key Key, value T) { } // Extract fields comprising index key. - parts := extract_fields(value, idx.fields) + parts := extract_fields(ptr, idx.fields) + if parts == nil { + continue + } // Calculate index key. key := idx.key(buf, parts) diff --git a/vendor/codeberg.org/gruf/go-structr/index.go b/vendor/codeberg.org/gruf/go-structr/index.go index c7115e0b4..b8f6b9d01 100644 --- a/vendor/codeberg.org/gruf/go-structr/index.go +++ b/vendor/codeberg.org/gruf/go-structr/index.go @@ -19,17 +19,15 @@ type IndexConfig struct { // be specified using periods. An example: // "Username,Favorites.Color" // - // Field types supported include: - // - ~int - // - ~int8 - // - ~int16 - // - ~int32 - // - ~int64 - // - ~float32 - // - ~float64 - // - ~string - // - slices of above - // - ptrs of above + // Note that nested fields where the nested + // struct field is a ptr are supported, but + // nil ptr values in nesting will result in + // that particular value NOT being indexed. + // e.g. with "Favorites.Color" if *Favorites + // is nil then it will not be indexed. + // + // Field types supported include any of those + // supported by the `go-mangler` library. Fields string // Multiple indicates whether to accept multiple @@ -124,7 +122,6 @@ func (i *Index) init(t reflect.Type, cfg IndexConfig, cap int) { case t.Kind() == reflect.Struct: case t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Struct: - t = t.Elem() default: panic("index only support struct{} and *struct{}") } @@ -146,10 +143,10 @@ func (i *Index) init(t reflect.Type, cfg IndexConfig, cap int) { // Preallocate expected struct field slice. i.fields = make([]struct_field, len(fields)) + for x, name := range fields { - for x, fieldName := range fields { // Split name to account for nesting. - names := strings.Split(fieldName, ".") + names := strings.Split(name, ".") // Look for usable struct field. i.fields[x] = find_field(t, names) @@ -214,23 +211,23 @@ func (i *Index) get(key Key, hook func(*indexed_item)) { func (i *Index) key(buf *byteutil.Buffer, parts []any) Key { if len(parts) != len(i.fields) { panicf("incorrect number key parts: want=%d received=%d", - len(parts), len(i.fields), + len(parts), ) } buf.B = buf.B[:0] if !allow_zero(i.flags) { - for x := range parts { + for x, field := range i.fields { before := len(buf.B) - buf.B = i.fields[x].mangle(buf.B, parts[x]) - if string(buf.B[before:]) == i.fields[x].zero { + buf.B = field.mangle(buf.B, parts[x]) + if string(buf.B[before:]) == field.zero { return Key{} } buf.B = append(buf.B, '.') } } else { - for x := range parts { - buf.B = i.fields[x].mangle(buf.B, parts[x]) + for x, field := range i.fields { + buf.B = field.mangle(buf.B, parts[x]) buf.B = append(buf.B, '.') } } diff --git a/vendor/codeberg.org/gruf/go-structr/queue.go b/vendor/codeberg.org/gruf/go-structr/queue.go index 1e735762f..70c18c839 100644 --- a/vendor/codeberg.org/gruf/go-structr/queue.go +++ b/vendor/codeberg.org/gruf/go-structr/queue.go @@ -262,6 +262,9 @@ func (q *Queue[T]) index(value T) *indexed_item { // Set item value. item.data = value + // Get ptr to value data. + ptr := unsafe.Pointer(&value) + // Acquire key buf. buf := new_buffer() @@ -270,7 +273,10 @@ func (q *Queue[T]) index(value T) *indexed_item { idx := &(q.indices[i]) // Extract fields comprising index key. - parts := extract_fields(value, idx.fields) + parts := extract_fields(ptr, idx.fields) + if parts == nil { + continue + } // Calculate index key. key := idx.key(buf, parts) diff --git a/vendor/codeberg.org/gruf/go-structr/runtime.go b/vendor/codeberg.org/gruf/go-structr/runtime.go index 7db1d7e7a..9990fe7b9 100644 --- a/vendor/codeberg.org/gruf/go-structr/runtime.go +++ b/vendor/codeberg.org/gruf/go-structr/runtime.go @@ -16,15 +16,14 @@ // including memory offset and hash function. type struct_field struct { - // type2 is the runtime type pointer - // underlying the struct field type. - // used for repacking our own erfaces. + // type2 contains the reflect2 + // type information for this field, + // used in repacking it as eface. type2 reflect2.Type - // offset is the offset in memory - // of this struct field from the - // outer-most value ptr location. - offset uintptr + // offsets defines whereabouts in + // memory this field is located. + offsets []next_offset // struct field type mangling // (i.e. fast serializing) fn. @@ -36,6 +35,15 @@ type struct_field struct { zero string } +// next_offset defines a next offset location +// in a struct_field, first by the number of +// derefences required, then by offset from +// that final memory location. +type next_offset struct { + derefs uint + offset uintptr +} + // 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) { @@ -64,24 +72,33 @@ func find_field(t reflect.Type, names []string) (sfield struct_field) { ) for len(names) > 0 { - var ok bool - // Pop next name. name := pop_name() + var off next_offset + + // Dereference any ptrs to struct. + for t.Kind() == reflect.Pointer { + t = t.Elem() + off.derefs++ + } + // Check for valid struct type. if t.Kind() != reflect.Struct { - panicf("field %s is not struct: %s", t, name) + panicf("field %s is not struct (or ptr-to): %s", t, name) } + var ok bool + // Look for next field by name. field, ok = t.FieldByName(name) if !ok { panicf("unknown field: %s", name) } - // Increment total field offset. - sfield.offset += field.Offset + // Set next offset value. + off.offset = field.Offset + sfield.offsets = append(sfield.offsets, off) // Set the next type. t = field.Type @@ -89,36 +106,57 @@ func find_field(t reflect.Type, names []string) (sfield struct_field) { // Get field type as reflect2. sfield.type2 = reflect2.Type2(t) + i := sfield.type2.New() // Find mangler for field type. sfield.mangle = mangler.Get(t) + // Set possible mangled zero value. + sfield.zero = string(sfield.mangle(nil, i)) + return } // extract_fields extracts given structfields from the provided value type, // this is done using predetermined struct field memory offset locations. -func extract_fields[T any](value T, fields []struct_field) []any { - // Get ptr to raw value data. - ptr := unsafe.Pointer(&value) - - // If this is a pointer type deref the value ptr. - if reflect.TypeOf(value).Kind() == reflect.Pointer { - ptr = *(*unsafe.Pointer)(ptr) - } - +func extract_fields(ptr unsafe.Pointer, fields []struct_field) []any { // Prepare slice of field ifaces. ifaces := make([]any, len(fields)) + for i, field := range fields { - for i := 0; i < len(fields); i++ { - // Manually access field at memory offset and pack eface. - ptr := unsafe.Pointer(uintptr(ptr) + fields[i].offset) - ifaces[i] = fields[i].type2.UnsafeIndirect(ptr) + // loop scope. + fptr := ptr + + for _, offset := range field.offsets { + // Dereference any ptrs to offset. + fptr = deref(fptr, offset.derefs) + if fptr == nil { + return nil + } + + // Jump forward by offset to next ptr. + fptr = unsafe.Pointer(uintptr(fptr) + + offset.offset) + } + + // Repack value data ptr as empty interface. + ifaces[i] = field.type2.UnsafeIndirect(fptr) } return ifaces } +// deref will dereference ptr 'n' times (or until nil). +func deref(p unsafe.Pointer, n uint) unsafe.Pointer { + for ; n > 0; n-- { + if p == nil { + return nil + } + p = *(*unsafe.Pointer)(p) + } + return p +} + // panicf provides a panic with string formatting. func panicf(format string, args ...any) { panic(fmt.Sprintf(format, args...)) diff --git a/vendor/modules.txt b/vendor/modules.txt index 19a580cd0..f2d53d960 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -59,7 +59,7 @@ codeberg.org/gruf/go-sched ## explicit; go 1.19 codeberg.org/gruf/go-store/v2/storage codeberg.org/gruf/go-store/v2/util -# codeberg.org/gruf/go-structr v0.6.0 +# codeberg.org/gruf/go-structr v0.6.2 ## explicit; go 1.21 codeberg.org/gruf/go-structr # codeberg.org/superseriousbusiness/exif-terminator v0.7.0