mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-28 01:56:30 +00:00
b93087ceb4
* updates go-structr and go-mangler to no longer rely on modern-go/reflect2 (*phew* now we're go1.23 safe) * update go-structr version * bump go-structr to improve memory usage (v. slightly) in certain conditions
224 lines
4.5 KiB
Go
224 lines
4.5 KiB
Go
package mangler
|
|
|
|
import (
|
|
"reflect"
|
|
)
|
|
|
|
// loadMangler is the top-most Mangler load function. It guarantees that a Mangler
|
|
// function will be returned for given value interface{} and reflected type. Else panics.
|
|
func loadMangler(t reflect.Type) Mangler {
|
|
ctx := typecontext{rtype: t}
|
|
|
|
// Load mangler fn
|
|
mng := load(ctx)
|
|
if mng != nil {
|
|
return mng
|
|
}
|
|
|
|
// No mangler function could be determined
|
|
panic("cannot mangle type: " + t.String())
|
|
}
|
|
|
|
// load will load a Mangler or reflect Mangler for given type and iface 'a'.
|
|
// Note: allocates new interface value if nil provided, i.e. if coming via reflection.
|
|
func load(ctx typecontext) Mangler {
|
|
if ctx.rtype == nil {
|
|
// There is no reflect type to search by
|
|
panic("cannot mangle nil interface{} type")
|
|
}
|
|
|
|
// Search by reflection.
|
|
mng := loadReflect(ctx)
|
|
if mng != nil {
|
|
return mng
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// loadReflect will load a Mangler (or rMangler) function for the given reflected type info.
|
|
// NOTE: this is used as the top level load function for nested reflective searches.
|
|
func loadReflect(ctx typecontext) Mangler {
|
|
switch ctx.rtype.Kind() {
|
|
case reflect.Pointer:
|
|
return loadReflectPtr(ctx)
|
|
|
|
case reflect.String:
|
|
return mangle_string
|
|
|
|
case reflect.Struct:
|
|
return loadReflectStruct(ctx)
|
|
|
|
case reflect.Array:
|
|
return loadReflectArray(ctx)
|
|
|
|
case reflect.Slice:
|
|
return loadReflectSlice(ctx)
|
|
|
|
case reflect.Bool:
|
|
return mangle_bool
|
|
|
|
case reflect.Int,
|
|
reflect.Uint,
|
|
reflect.Uintptr:
|
|
return mangle_int
|
|
|
|
case reflect.Int8, reflect.Uint8:
|
|
return mangle_8bit
|
|
|
|
case reflect.Int16, reflect.Uint16:
|
|
return mangle_16bit
|
|
|
|
case reflect.Int32, reflect.Uint32:
|
|
return mangle_32bit
|
|
|
|
case reflect.Int64, reflect.Uint64:
|
|
return mangle_64bit
|
|
|
|
case reflect.Float32:
|
|
return mangle_32bit
|
|
|
|
case reflect.Float64:
|
|
return mangle_64bit
|
|
|
|
case reflect.Complex64:
|
|
return mangle_64bit
|
|
|
|
case reflect.Complex128:
|
|
return mangle_128bit
|
|
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// loadReflectPtr loads a Mangler (or rMangler) function for a ptr's element type.
|
|
// This also handles further dereferencing of any further ptr indrections (e.g. ***int).
|
|
func loadReflectPtr(ctx typecontext) Mangler {
|
|
var n uint
|
|
|
|
// Iteratively dereference ptrs
|
|
for ctx.rtype.Kind() == reflect.Pointer {
|
|
ctx.rtype = ctx.rtype.Elem()
|
|
n++
|
|
}
|
|
|
|
// Search for elemn type mangler.
|
|
if mng := load(ctx); mng != nil {
|
|
return deref_ptr_mangler(ctx, mng, n)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// loadReflectKnownSlice loads a Mangler function for a
|
|
// known slice-of-element type (in this case, primtives).
|
|
func loadReflectKnownSlice(ctx typecontext) Mangler {
|
|
switch ctx.rtype.Kind() {
|
|
case reflect.String:
|
|
return mangle_string_slice
|
|
|
|
case reflect.Bool:
|
|
return mangle_bool_slice
|
|
|
|
case reflect.Int,
|
|
reflect.Uint,
|
|
reflect.Uintptr:
|
|
return mangle_int_slice
|
|
|
|
case reflect.Int8, reflect.Uint8:
|
|
return mangle_8bit_slice
|
|
|
|
case reflect.Int16, reflect.Uint16:
|
|
return mangle_16bit_slice
|
|
|
|
case reflect.Int32, reflect.Uint32:
|
|
return mangle_32bit_slice
|
|
|
|
case reflect.Int64, reflect.Uint64:
|
|
return mangle_64bit_slice
|
|
|
|
case reflect.Float32:
|
|
return mangle_32bit_slice
|
|
|
|
case reflect.Float64:
|
|
return mangle_64bit_slice
|
|
|
|
case reflect.Complex64:
|
|
return mangle_64bit_slice
|
|
|
|
case reflect.Complex128:
|
|
return mangle_128bit_slice
|
|
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// loadReflectSlice ...
|
|
func loadReflectSlice(ctx typecontext) Mangler {
|
|
// Set nesting type.
|
|
ctx.ntype = ctx.rtype
|
|
|
|
// Get nested element type.
|
|
ctx.rtype = ctx.rtype.Elem()
|
|
|
|
// Preferably look for known slice mangler func
|
|
if mng := loadReflectKnownSlice(ctx); mng != nil {
|
|
return mng
|
|
}
|
|
|
|
// Use nested mangler iteration.
|
|
if mng := load(ctx); mng != nil {
|
|
return iter_slice_mangler(ctx, mng)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// loadReflectArray ...
|
|
func loadReflectArray(ctx typecontext) Mangler {
|
|
// Set nesting type.
|
|
ctx.ntype = ctx.rtype
|
|
|
|
// Get nested element type.
|
|
ctx.rtype = ctx.rtype.Elem()
|
|
|
|
// Use manglers for nested iteration.
|
|
if mng := load(ctx); mng != nil {
|
|
return iter_array_mangler(ctx, mng)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// loadReflectStruct ...
|
|
func loadReflectStruct(ctx typecontext) Mangler {
|
|
var mngs []Mangler
|
|
|
|
// Set nesting type.
|
|
ctx.ntype = ctx.rtype
|
|
|
|
// Gather manglers for all fields.
|
|
for i := 0; i < ctx.ntype.NumField(); i++ {
|
|
|
|
// Field typectx.
|
|
ctx := typecontext{
|
|
ntype: ctx.ntype,
|
|
rtype: ctx.ntype.Field(i).Type,
|
|
}
|
|
|
|
// Load mangler.
|
|
mng := load(ctx)
|
|
if mng == nil {
|
|
return nil
|
|
}
|
|
|
|
// Append next to map.
|
|
mngs = append(mngs, mng)
|
|
}
|
|
|
|
// Use manglers for nested iteration.
|
|
return iter_struct_mangler(ctx, mngs)
|
|
}
|