diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-mangler/helpers.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-mangler/helpers.go | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-mangler/helpers.go b/vendor/codeberg.org/gruf/go-mangler/helpers.go new file mode 100644 index 000000000..c7e91376e --- /dev/null +++ b/vendor/codeberg.org/gruf/go-mangler/helpers.go @@ -0,0 +1,250 @@ +package mangler + +import ( + "reflect" + "unsafe" + + "github.com/modern-go/reflect2" +) + +type ( + byteser interface{ Bytes() []byte } + stringer interface{ String() string } + binarymarshaler interface{ MarshalBinary() ([]byte, error) } + textmarshaler interface{ MarshalText() ([]byte, error) } + jsonmarshaler interface{ MarshalJSON() ([]byte, error) } +) + +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 deref_ptr_mangler(rtype reflect.Type, mangle Mangler, count int) Mangler { + if rtype == nil || mangle == nil || count == 0 { + panic("bad input") + } + + // Get reflect2's type for later + // unsafe interface data repacking, + type2 := reflect2.Type2(rtype) + + return func(buf []byte, value any) []byte { + // Get raw value data. + ptr := eface_data(value) + + // Deref n - 1 number times. + for i := 0; i < count-1; 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 value check. + buf = append(buf, '0') + return buf + } + + // Repack and mangle fully deref'd + value = type2.UnsafeIndirect(ptr) + buf = append(buf, '1') + return mangle(buf, value) + } +} + +func iter_slice_mangler(rtype reflect.Type, mangle Mangler) Mangler { + if rtype == nil || mangle == nil { + panic("bad input") + } + + // Get reflect2's type for later + // unsafe slice data manipulation. + slice2 := reflect2.Type2(rtype).(*reflect2.UnsafeSliceType) + + return func(buf []byte, value any) []byte { + // Get raw value data. + ptr := eface_data(value) + + // Get length of slice value. + n := slice2.UnsafeLengthOf(ptr) + + for i := 0; i < n; i++ { + // Mangle data at each slice index. + e := slice2.UnsafeGetIndex(ptr, i) + buf = mangle(buf, e) + buf = append(buf, ',') + } + + if n > 0 { + // Drop final comma. + buf = buf[:len(buf)-1] + } + + return buf + } +} + +func iter_array_mangler(rtype reflect.Type, mangle Mangler) Mangler { + if rtype == nil || mangle == nil { + panic("bad input") + } + + // Get reflect2's type for later + // unsafe slice data manipulation. + array2 := reflect2.Type2(rtype).(*reflect2.UnsafeArrayType) + n := array2.Len() + + return func(buf []byte, value any) []byte { + // Get raw value data. + ptr := eface_data(value) + + for i := 0; i < n; i++ { + // Mangle data at each slice index. + e := array2.UnsafeGetIndex(ptr, i) + buf = mangle(buf, e) + buf = append(buf, ',') + } + + if n > 0 { + // Drop final comma. + buf = buf[:len(buf)-1] + } + + return buf + } +} + +func iter_map_mangler(rtype reflect.Type, kmangle, emangle Mangler) Mangler { + if rtype == nil || kmangle == nil || emangle == nil { + panic("bad input") + } + + // Get reflect2's type for later + // unsafe map data manipulation. + map2 := reflect2.Type2(rtype).(*reflect2.UnsafeMapType) + key2, elem2 := map2.Key(), map2.Elem() + + return func(buf []byte, value any) []byte { + // Get raw value data. + ptr := eface_data(value) + ptr = indirect_ptr(ptr) + + // Create iterator for map value. + iter := map2.UnsafeIterate(ptr) + + // Check if empty map. + empty := !iter.HasNext() + + for iter.HasNext() { + // Get key + elem data as ifaces. + kptr, eptr := iter.UnsafeNext() + key := key2.UnsafeIndirect(kptr) + elem := elem2.UnsafeIndirect(eptr) + + // Mangle data for key + elem. + buf = kmangle(buf, key) + buf = append(buf, ':') + buf = emangle(buf, elem) + buf = append(buf, ',') + } + + if !empty { + // Drop final comma. + buf = buf[:len(buf)-1] + } + + return buf + } +} + +func iter_struct_mangler(rtype reflect.Type, manglers []Mangler) Mangler { + if rtype == nil || len(manglers) != rtype.NumField() { + panic("bad input") + } + + type field struct { + type2 reflect2.Type + field *reflect2.UnsafeStructField + mangle Mangler + } + + // Get reflect2's type for later + // unsafe struct field data access. + struct2 := reflect2.Type2(rtype).(*reflect2.UnsafeStructType) + + // Bundle together the fields and manglers. + fields := make([]field, rtype.NumField()) + for i := range fields { + fields[i].field = struct2.Field(i).(*reflect2.UnsafeStructField) + fields[i].type2 = fields[i].field.Type() + fields[i].mangle = manglers[i] + if fields[i].type2 == nil || + fields[i].field == nil || + fields[i].mangle == nil { + panic("bad input") + } + } + + return func(buf []byte, value any) []byte { + // Get raw value data. + ptr := eface_data(value) + + for i := range fields { + // Get struct field as iface via offset. + fptr := fields[i].field.UnsafeGet(ptr) + field := fields[i].type2.UnsafeIndirect(fptr) + + // Mangle the struct field data. + buf = fields[i].mangle(buf, field) + buf = append(buf, ',') + } + + if len(fields) > 0 { + // Drop final comma. + buf = buf[:len(buf)-1] + } + + return buf + } +} + +func indirect_ptr(p unsafe.Pointer) unsafe.Pointer { + return unsafe.Pointer(&p) +} + +func eface_data(a any) unsafe.Pointer { + type eface struct{ _, data unsafe.Pointer } + return (*eface)(unsafe.Pointer(&a)).data +} |