diff options
author | 2024-04-11 10:46:08 +0100 | |
---|---|---|
committer | 2024-04-11 11:46:08 +0200 | |
commit | db2dcc3455e91aa3cc9599358d8eae4f0ef75b91 (patch) | |
tree | b43016efd4f105634bd3ea04fe72417dadaca5e6 /vendor/codeberg.org/gruf/go-structr/runtime.go | |
parent | [feature] New user sign-up via web page (#2796) (diff) | |
download | gotosocial-db2dcc3455e91aa3cc9599358d8eae4f0ef75b91.tar.xz |
[chore] update go-structr => v0.6.2 (fixes nested field ptr following) (#2822)
* update go-structr => v0.6.1 (fixes nested field ptr following)
* bump to v0.6.2
Diffstat (limited to 'vendor/codeberg.org/gruf/go-structr/runtime.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-structr/runtime.go | 88 |
1 files changed, 63 insertions, 25 deletions
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 @@ import ( // 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 { + + // loop scope. + fptr := ptr + + for _, offset := range field.offsets { + // Dereference any ptrs to offset. + fptr = deref(fptr, offset.derefs) + if fptr == nil { + return nil + } - 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) + // 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...)) |