mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 18:12:25 -06:00 
			
		
		
		
	* 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
		
			
				
	
	
		
			223 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			223 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)
 | 
						|
}
 |