GoToSocial/vendor/codeberg.org/gruf/go-mangler/helpers.go
2024-08-14 12:08:24 +00:00

201 lines
3.7 KiB
Go

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 {
ntype reflect.Type
rtype reflect.Type
}
func deref_ptr_mangler(ctx typecontext, mangle Mangler, n uint) Mangler {
if mangle == nil || n == 0 {
panic("bad input")
}
// Non-nested value types,
// i.e. just direct ptrs to
// primitives require one
// less dereference to ptr.
if ctx.ntype == nil {
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()
// 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.rtype.NumField() {
panic("bad input")
}
type field struct {
mangle Mangler
offset uintptr
}
// Bundle together the fields and manglers.
fields := make([]field, ctx.rtype.NumField())
for i := range fields {
rfield := ctx.rtype.FieldByIndex([]int{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
}
}
// 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
}