mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 07:52:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			355 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			355 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								package mangler
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"encoding"
							 | 
						||
| 
								 | 
							
									"net/url"
							 | 
						||
| 
								 | 
							
									"reflect"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 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(a any, t reflect.Type) Mangler {
							 | 
						||
| 
								 | 
							
									// Load mangler function
							 | 
						||
| 
								 | 
							
									mng, rmng := load(a, t)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if rmng != nil {
							 | 
						||
| 
								 | 
							
										// Wrap reflect mangler to handle iface
							 | 
						||
| 
								 | 
							
										return func(buf []byte, a any) []byte {
							 | 
						||
| 
								 | 
							
											return rmng(buf, reflect.ValueOf(a))
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if mng == nil {
							 | 
						||
| 
								 | 
							
										// No mangler function could be determined
							 | 
						||
| 
								 | 
							
										panic("cannot mangle type: " + t.String())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return mng
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 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(a any, t reflect.Type) (Mangler, rMangler) {
							 | 
						||
| 
								 | 
							
									if t == nil {
							 | 
						||
| 
								 | 
							
										// There is no reflect type to search by
							 | 
						||
| 
								 | 
							
										panic("cannot mangle nil interface{} type")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if a == nil {
							 | 
						||
| 
								 | 
							
										// Alloc new iface instance
							 | 
						||
| 
								 | 
							
										v := reflect.New(t).Elem()
							 | 
						||
| 
								 | 
							
										a = v.Interface()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Check in fast iface type switch
							 | 
						||
| 
								 | 
							
									if mng := loadIface(a); mng != nil {
							 | 
						||
| 
								 | 
							
										return mng, nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Search by reflection
							 | 
						||
| 
								 | 
							
									return loadReflect(t)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// loadIface is used as a first-resort interface{} type switcher loader
							 | 
						||
| 
								 | 
							
								// for types implementing Mangled and providing performant alternative
							 | 
						||
| 
								 | 
							
								// Mangler functions for standard library types to avoid reflection.
							 | 
						||
| 
								 | 
							
								func loadIface(a any) Mangler {
							 | 
						||
| 
								 | 
							
									switch a.(type) {
							 | 
						||
| 
								 | 
							
									case Mangled:
							 | 
						||
| 
								 | 
							
										return mangle_mangled
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case time.Time:
							 | 
						||
| 
								 | 
							
										return mangle_time
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case *time.Time:
							 | 
						||
| 
								 | 
							
										return mangle_time_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case *url.URL:
							 | 
						||
| 
								 | 
							
										return mangle_stringer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case encoding.BinaryMarshaler:
							 | 
						||
| 
								 | 
							
										return mangle_binary
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// NOTE:
							 | 
						||
| 
								 | 
							
									// we don't just handle ALL fmt.Stringer types as often
							 | 
						||
| 
								 | 
							
									// the output is large and unwieldy and this interface
							 | 
						||
| 
								 | 
							
									// switch is for types it would be faster to avoid reflection.
							 | 
						||
| 
								 | 
							
									// If they want better performance they can implement Mangled{}.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										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(t reflect.Type) (Mangler, rMangler) {
							 | 
						||
| 
								 | 
							
									switch t.Kind() {
							 | 
						||
| 
								 | 
							
									case reflect.Pointer:
							 | 
						||
| 
								 | 
							
										return loadReflectPtr(t.Elem())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.String:
							 | 
						||
| 
								 | 
							
										return mangle_string, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Array:
							 | 
						||
| 
								 | 
							
										return nil, loadReflectArray(t.Elem())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Slice:
							 | 
						||
| 
								 | 
							
										// Element type
							 | 
						||
| 
								 | 
							
										et := t.Elem()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Preferably look for known slice mangler func
							 | 
						||
| 
								 | 
							
										if mng := loadReflectKnownSlice(et); mng != nil {
							 | 
						||
| 
								 | 
							
											return mng, nil
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Else handle as array elements
							 | 
						||
| 
								 | 
							
										return nil, loadReflectArray(et)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Map:
							 | 
						||
| 
								 | 
							
										return nil, loadReflectMap(t.Key(), t.Elem())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Bool:
							 | 
						||
| 
								 | 
							
										return mangle_bool, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int,
							 | 
						||
| 
								 | 
							
										reflect.Uint,
							 | 
						||
| 
								 | 
							
										reflect.Uintptr:
							 | 
						||
| 
								 | 
							
										return mangle_platform_int, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int8,
							 | 
						||
| 
								 | 
							
										reflect.Uint8:
							 | 
						||
| 
								 | 
							
										return mangle_8bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int16,
							 | 
						||
| 
								 | 
							
										reflect.Uint16:
							 | 
						||
| 
								 | 
							
										return mangle_16bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int32,
							 | 
						||
| 
								 | 
							
										reflect.Uint32:
							 | 
						||
| 
								 | 
							
										return mangle_32bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int64,
							 | 
						||
| 
								 | 
							
										reflect.Uint64:
							 | 
						||
| 
								 | 
							
										return mangle_64bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Float32:
							 | 
						||
| 
								 | 
							
										return mangle_32bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Float64:
							 | 
						||
| 
								 | 
							
										return mangle_64bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Complex64:
							 | 
						||
| 
								 | 
							
										return mangle_64bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Complex128:
							 | 
						||
| 
								 | 
							
										return mangle_128bit, nil
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return nil, 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(et reflect.Type) (Mangler, rMangler) {
							 | 
						||
| 
								 | 
							
									count := 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Iteratively dereference ptrs
							 | 
						||
| 
								 | 
							
									for et.Kind() == reflect.Pointer {
							 | 
						||
| 
								 | 
							
										et = et.Elem()
							 | 
						||
| 
								 | 
							
										count++
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if et.Kind() == reflect.Array {
							 | 
						||
| 
								 | 
							
										// Special case of addressable (sliceable) array
							 | 
						||
| 
								 | 
							
										if mng := loadReflectKnownSlice(et); mng != nil {
							 | 
						||
| 
								 | 
							
											if count == 1 {
							 | 
						||
| 
								 | 
							
												return mng, nil
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return nil, deref_ptr_mangler(mng, count-1)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Look for an array mangler function, this will
							 | 
						||
| 
								 | 
							
										// access elements by index using reflect.Value and
							 | 
						||
| 
								 | 
							
										// pass each one to a separate mangler function.
							 | 
						||
| 
								 | 
							
										if rmng := loadReflectArray(et); rmng != nil {
							 | 
						||
| 
								 | 
							
											return nil, deref_ptr_rmangler(rmng, count)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return nil, nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Try remove a layer of derefs by loading a mangler
							 | 
						||
| 
								 | 
							
									// for a known ptr kind. The less reflection the better!
							 | 
						||
| 
								 | 
							
									if mng := loadReflectKnownPtr(et); mng != nil {
							 | 
						||
| 
								 | 
							
										if count == 1 {
							 | 
						||
| 
								 | 
							
											return mng, nil
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return nil, deref_ptr_mangler(mng, count-1)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Search for ptr elemn type mangler
							 | 
						||
| 
								 | 
							
									if mng, rmng := load(nil, et); mng != nil {
							 | 
						||
| 
								 | 
							
										return nil, deref_ptr_mangler(mng, count)
							 | 
						||
| 
								 | 
							
									} else if rmng != nil {
							 | 
						||
| 
								 | 
							
										return nil, deref_ptr_rmangler(rmng, count)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// loadReflectKnownPtr loads a Mangler function for a known ptr-of-element type (in this case, primtive ptrs).
							 | 
						||
| 
								 | 
							
								func loadReflectKnownPtr(et reflect.Type) Mangler {
							 | 
						||
| 
								 | 
							
									switch et.Kind() {
							 | 
						||
| 
								 | 
							
									case reflect.String:
							 | 
						||
| 
								 | 
							
										return mangle_string_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Bool:
							 | 
						||
| 
								 | 
							
										return mangle_bool_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int,
							 | 
						||
| 
								 | 
							
										reflect.Uint,
							 | 
						||
| 
								 | 
							
										reflect.Uintptr:
							 | 
						||
| 
								 | 
							
										return mangle_platform_int_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int8,
							 | 
						||
| 
								 | 
							
										reflect.Uint8:
							 | 
						||
| 
								 | 
							
										return mangle_8bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int16,
							 | 
						||
| 
								 | 
							
										reflect.Uint16:
							 | 
						||
| 
								 | 
							
										return mangle_16bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int32,
							 | 
						||
| 
								 | 
							
										reflect.Uint32:
							 | 
						||
| 
								 | 
							
										return mangle_32bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int64,
							 | 
						||
| 
								 | 
							
										reflect.Uint64:
							 | 
						||
| 
								 | 
							
										return mangle_64bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Float32:
							 | 
						||
| 
								 | 
							
										return mangle_32bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Float64:
							 | 
						||
| 
								 | 
							
										return mangle_64bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Complex64:
							 | 
						||
| 
								 | 
							
										return mangle_64bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Complex128:
							 | 
						||
| 
								 | 
							
										return mangle_128bit_ptr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// loadReflectKnownSlice loads a Mangler function for a known slice-of-element type (in this case, primtives).
							 | 
						||
| 
								 | 
							
								func loadReflectKnownSlice(et reflect.Type) Mangler {
							 | 
						||
| 
								 | 
							
									switch et.Kind() {
							 | 
						||
| 
								 | 
							
									case reflect.String:
							 | 
						||
| 
								 | 
							
										return mangle_string_slice
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Bool:
							 | 
						||
| 
								 | 
							
										return mangle_bool_slice
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									case reflect.Int,
							 | 
						||
| 
								 | 
							
										reflect.Uint,
							 | 
						||
| 
								 | 
							
										reflect.Uintptr:
							 | 
						||
| 
								 | 
							
										return mangle_platform_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
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// loadReflectArray loads an rMangler function for an array (or slice) or given element type.
							 | 
						||
| 
								 | 
							
								func loadReflectArray(et reflect.Type) rMangler {
							 | 
						||
| 
								 | 
							
									// Search via reflected array element type
							 | 
						||
| 
								 | 
							
									if mng, rmng := load(nil, et); mng != nil {
							 | 
						||
| 
								 | 
							
										return iter_array_mangler(mng)
							 | 
						||
| 
								 | 
							
									} else if rmng != nil {
							 | 
						||
| 
								 | 
							
										return iter_array_rmangler(rmng)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// loadReflectMap ...
							 | 
						||
| 
								 | 
							
								func loadReflectMap(kt, vt reflect.Type) rMangler {
							 | 
						||
| 
								 | 
							
									var kmng, vmng rMangler
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Search for mangler for key type
							 | 
						||
| 
								 | 
							
									mng, rmng := load(nil, kt)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch {
							 | 
						||
| 
								 | 
							
									// Wrap key mangler to reflect
							 | 
						||
| 
								 | 
							
									case mng != nil:
							 | 
						||
| 
								 | 
							
										mng := mng // take our own ptr
							 | 
						||
| 
								 | 
							
										kmng = func(buf []byte, v reflect.Value) []byte {
							 | 
						||
| 
								 | 
							
											return mng(buf, v.Interface())
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Use reflect key mangler as-is
							 | 
						||
| 
								 | 
							
									case rmng != nil:
							 | 
						||
| 
								 | 
							
										kmng = rmng
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// No mangler found
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Search for mangler for value type
							 | 
						||
| 
								 | 
							
									mng, rmng = load(nil, vt)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch {
							 | 
						||
| 
								 | 
							
									// Wrap key mangler to reflect
							 | 
						||
| 
								 | 
							
									case mng != nil:
							 | 
						||
| 
								 | 
							
										mng := mng // take our own ptr
							 | 
						||
| 
								 | 
							
										vmng = func(buf []byte, v reflect.Value) []byte {
							 | 
						||
| 
								 | 
							
											return mng(buf, v.Interface())
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Use reflect key mangler as-is
							 | 
						||
| 
								 | 
							
									case rmng != nil:
							 | 
						||
| 
								 | 
							
										vmng = rmng
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// No mangler found
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Wrap key/value manglers in map iter
							 | 
						||
| 
								 | 
							
									return iter_map_rmangler(kmng, vmng)
							 | 
						||
| 
								 | 
							
								}
							 |