mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 08:52:26 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			438 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package decoder
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	nilValue = reflect.ValueOf(nil)
 | 
						|
)
 | 
						|
 | 
						|
func AssignValue(src, dst reflect.Value) error {
 | 
						|
	if dst.Type().Kind() != reflect.Ptr {
 | 
						|
		return fmt.Errorf("invalid dst type. required pointer type: %T", dst.Type())
 | 
						|
	}
 | 
						|
	casted, err := castValue(dst.Elem().Type(), src)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	dst.Elem().Set(casted)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func castValue(t reflect.Type, v reflect.Value) (reflect.Value, error) {
 | 
						|
	switch t.Kind() {
 | 
						|
	case reflect.Int:
 | 
						|
		vv, err := castInt(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(int(vv.Int())), nil
 | 
						|
	case reflect.Int8:
 | 
						|
		vv, err := castInt(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(int8(vv.Int())), nil
 | 
						|
	case reflect.Int16:
 | 
						|
		vv, err := castInt(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(int16(vv.Int())), nil
 | 
						|
	case reflect.Int32:
 | 
						|
		vv, err := castInt(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(int32(vv.Int())), nil
 | 
						|
	case reflect.Int64:
 | 
						|
		return castInt(v)
 | 
						|
	case reflect.Uint:
 | 
						|
		vv, err := castUint(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(uint(vv.Uint())), nil
 | 
						|
	case reflect.Uint8:
 | 
						|
		vv, err := castUint(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(uint8(vv.Uint())), nil
 | 
						|
	case reflect.Uint16:
 | 
						|
		vv, err := castUint(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(uint16(vv.Uint())), nil
 | 
						|
	case reflect.Uint32:
 | 
						|
		vv, err := castUint(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(uint32(vv.Uint())), nil
 | 
						|
	case reflect.Uint64:
 | 
						|
		return castUint(v)
 | 
						|
	case reflect.Uintptr:
 | 
						|
		vv, err := castUint(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(uintptr(vv.Uint())), nil
 | 
						|
	case reflect.String:
 | 
						|
		return castString(v)
 | 
						|
	case reflect.Bool:
 | 
						|
		return castBool(v)
 | 
						|
	case reflect.Float32:
 | 
						|
		vv, err := castFloat(v)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(float32(vv.Float())), nil
 | 
						|
	case reflect.Float64:
 | 
						|
		return castFloat(v)
 | 
						|
	case reflect.Array:
 | 
						|
		return castArray(t, v)
 | 
						|
	case reflect.Slice:
 | 
						|
		return castSlice(t, v)
 | 
						|
	case reflect.Map:
 | 
						|
		return castMap(t, v)
 | 
						|
	case reflect.Struct:
 | 
						|
		return castStruct(t, v)
 | 
						|
	}
 | 
						|
	return v, nil
 | 
						|
}
 | 
						|
 | 
						|
func castInt(v reflect.Value) (reflect.Value, error) {
 | 
						|
	switch v.Type().Kind() {
 | 
						|
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
		return v, nil
 | 
						|
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
						|
		return reflect.ValueOf(int64(v.Uint())), nil
 | 
						|
	case reflect.String:
 | 
						|
		i64, err := strconv.ParseInt(v.String(), 10, 64)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(i64), nil
 | 
						|
	case reflect.Bool:
 | 
						|
		if v.Bool() {
 | 
						|
			return reflect.ValueOf(int64(1)), nil
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(int64(0)), nil
 | 
						|
	case reflect.Float32, reflect.Float64:
 | 
						|
		return reflect.ValueOf(int64(v.Float())), nil
 | 
						|
	case reflect.Array:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castInt(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to int64 from empty array")
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castInt(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to int64 from empty slice")
 | 
						|
	case reflect.Interface:
 | 
						|
		return castInt(reflect.ValueOf(v.Interface()))
 | 
						|
	case reflect.Map:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to int64 from map")
 | 
						|
	case reflect.Struct:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to int64 from struct")
 | 
						|
	case reflect.Ptr:
 | 
						|
		return castInt(v.Elem())
 | 
						|
	}
 | 
						|
	return nilValue, fmt.Errorf("failed to cast to int64 from %s", v.Type().Kind())
 | 
						|
}
 | 
						|
 | 
						|
func castUint(v reflect.Value) (reflect.Value, error) {
 | 
						|
	switch v.Type().Kind() {
 | 
						|
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
		return reflect.ValueOf(uint64(v.Int())), nil
 | 
						|
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
						|
		return v, nil
 | 
						|
	case reflect.String:
 | 
						|
		u64, err := strconv.ParseUint(v.String(), 10, 64)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(u64), nil
 | 
						|
	case reflect.Bool:
 | 
						|
		if v.Bool() {
 | 
						|
			return reflect.ValueOf(uint64(1)), nil
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(uint64(0)), nil
 | 
						|
	case reflect.Float32, reflect.Float64:
 | 
						|
		return reflect.ValueOf(uint64(v.Float())), nil
 | 
						|
	case reflect.Array:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castUint(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to uint64 from empty array")
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castUint(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to uint64 from empty slice")
 | 
						|
	case reflect.Interface:
 | 
						|
		return castUint(reflect.ValueOf(v.Interface()))
 | 
						|
	case reflect.Map:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to uint64 from map")
 | 
						|
	case reflect.Struct:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to uint64 from struct")
 | 
						|
	case reflect.Ptr:
 | 
						|
		return castUint(v.Elem())
 | 
						|
	}
 | 
						|
	return nilValue, fmt.Errorf("failed to cast to uint64 from %s", v.Type().Kind())
 | 
						|
}
 | 
						|
 | 
						|
func castString(v reflect.Value) (reflect.Value, error) {
 | 
						|
	switch v.Type().Kind() {
 | 
						|
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
		return reflect.ValueOf(fmt.Sprint(v.Int())), nil
 | 
						|
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
						|
		return reflect.ValueOf(fmt.Sprint(v.Uint())), nil
 | 
						|
	case reflect.String:
 | 
						|
		return v, nil
 | 
						|
	case reflect.Bool:
 | 
						|
		if v.Bool() {
 | 
						|
			return reflect.ValueOf("true"), nil
 | 
						|
		}
 | 
						|
		return reflect.ValueOf("false"), nil
 | 
						|
	case reflect.Float32, reflect.Float64:
 | 
						|
		return reflect.ValueOf(fmt.Sprint(v.Float())), nil
 | 
						|
	case reflect.Array:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castString(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from empty array")
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castString(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from empty slice")
 | 
						|
	case reflect.Interface:
 | 
						|
		return castString(reflect.ValueOf(v.Interface()))
 | 
						|
	case reflect.Map:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from map")
 | 
						|
	case reflect.Struct:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from struct")
 | 
						|
	case reflect.Ptr:
 | 
						|
		return castString(v.Elem())
 | 
						|
	}
 | 
						|
	return nilValue, fmt.Errorf("failed to cast to string from %s", v.Type().Kind())
 | 
						|
}
 | 
						|
 | 
						|
func castBool(v reflect.Value) (reflect.Value, error) {
 | 
						|
	switch v.Type().Kind() {
 | 
						|
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
		switch v.Int() {
 | 
						|
		case 0:
 | 
						|
			return reflect.ValueOf(false), nil
 | 
						|
		case 1:
 | 
						|
			return reflect.ValueOf(true), nil
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to bool from %d", v.Int())
 | 
						|
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
						|
		switch v.Uint() {
 | 
						|
		case 0:
 | 
						|
			return reflect.ValueOf(false), nil
 | 
						|
		case 1:
 | 
						|
			return reflect.ValueOf(true), nil
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to bool from %d", v.Uint())
 | 
						|
	case reflect.String:
 | 
						|
		b, err := strconv.ParseBool(v.String())
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(b), nil
 | 
						|
	case reflect.Bool:
 | 
						|
		return v, nil
 | 
						|
	case reflect.Float32, reflect.Float64:
 | 
						|
		switch v.Float() {
 | 
						|
		case 0:
 | 
						|
			return reflect.ValueOf(false), nil
 | 
						|
		case 1:
 | 
						|
			return reflect.ValueOf(true), nil
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to bool from %f", v.Float())
 | 
						|
	case reflect.Array:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castBool(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from empty array")
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castBool(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from empty slice")
 | 
						|
	case reflect.Interface:
 | 
						|
		return castBool(reflect.ValueOf(v.Interface()))
 | 
						|
	case reflect.Map:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from map")
 | 
						|
	case reflect.Struct:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to string from struct")
 | 
						|
	case reflect.Ptr:
 | 
						|
		return castBool(v.Elem())
 | 
						|
	}
 | 
						|
	return nilValue, fmt.Errorf("failed to cast to bool from %s", v.Type().Kind())
 | 
						|
}
 | 
						|
 | 
						|
func castFloat(v reflect.Value) (reflect.Value, error) {
 | 
						|
	switch v.Type().Kind() {
 | 
						|
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
		return reflect.ValueOf(float64(v.Int())), nil
 | 
						|
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
						|
		return reflect.ValueOf(float64(v.Uint())), nil
 | 
						|
	case reflect.String:
 | 
						|
		f64, err := strconv.ParseFloat(v.String(), 64)
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(f64), nil
 | 
						|
	case reflect.Bool:
 | 
						|
		if v.Bool() {
 | 
						|
			return reflect.ValueOf(float64(1)), nil
 | 
						|
		}
 | 
						|
		return reflect.ValueOf(float64(0)), nil
 | 
						|
	case reflect.Float32, reflect.Float64:
 | 
						|
		return v, nil
 | 
						|
	case reflect.Array:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castFloat(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to float64 from empty array")
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castFloat(v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to float64 from empty slice")
 | 
						|
	case reflect.Interface:
 | 
						|
		return castFloat(reflect.ValueOf(v.Interface()))
 | 
						|
	case reflect.Map:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to float64 from map")
 | 
						|
	case reflect.Struct:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to float64 from struct")
 | 
						|
	case reflect.Ptr:
 | 
						|
		return castFloat(v.Elem())
 | 
						|
	}
 | 
						|
	return nilValue, fmt.Errorf("failed to cast to float64 from %s", v.Type().Kind())
 | 
						|
}
 | 
						|
 | 
						|
func castArray(t reflect.Type, v reflect.Value) (reflect.Value, error) {
 | 
						|
	kind := v.Type().Kind()
 | 
						|
	if kind == reflect.Interface {
 | 
						|
		return castArray(t, reflect.ValueOf(v.Interface()))
 | 
						|
	}
 | 
						|
	if kind != reflect.Slice && kind != reflect.Array {
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to array from %s", kind)
 | 
						|
	}
 | 
						|
	if t.Elem() == v.Type().Elem() {
 | 
						|
		return v, nil
 | 
						|
	}
 | 
						|
	if t.Len() != v.Len() {
 | 
						|
		return nilValue, fmt.Errorf("failed to cast [%d]array from slice of %d length", t.Len(), v.Len())
 | 
						|
	}
 | 
						|
	ret := reflect.New(t).Elem()
 | 
						|
	for i := 0; i < v.Len(); i++ {
 | 
						|
		vv, err := castValue(t.Elem(), v.Index(i))
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		ret.Index(i).Set(vv)
 | 
						|
	}
 | 
						|
	return ret, nil
 | 
						|
}
 | 
						|
 | 
						|
func castSlice(t reflect.Type, v reflect.Value) (reflect.Value, error) {
 | 
						|
	kind := v.Type().Kind()
 | 
						|
	if kind == reflect.Interface {
 | 
						|
		return castSlice(t, reflect.ValueOf(v.Interface()))
 | 
						|
	}
 | 
						|
	if kind != reflect.Slice && kind != reflect.Array {
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to slice from %s", kind)
 | 
						|
	}
 | 
						|
	if t.Elem() == v.Type().Elem() {
 | 
						|
		return v, nil
 | 
						|
	}
 | 
						|
	ret := reflect.MakeSlice(t, v.Len(), v.Len())
 | 
						|
	for i := 0; i < v.Len(); i++ {
 | 
						|
		vv, err := castValue(t.Elem(), v.Index(i))
 | 
						|
		if err != nil {
 | 
						|
			return nilValue, err
 | 
						|
		}
 | 
						|
		ret.Index(i).Set(vv)
 | 
						|
	}
 | 
						|
	return ret, nil
 | 
						|
}
 | 
						|
 | 
						|
func castMap(t reflect.Type, v reflect.Value) (reflect.Value, error) {
 | 
						|
	ret := reflect.MakeMap(t)
 | 
						|
	switch v.Type().Kind() {
 | 
						|
	case reflect.Map:
 | 
						|
		iter := v.MapRange()
 | 
						|
		for iter.Next() {
 | 
						|
			key, err := castValue(t.Key(), iter.Key())
 | 
						|
			if err != nil {
 | 
						|
				return nilValue, err
 | 
						|
			}
 | 
						|
			value, err := castValue(t.Elem(), iter.Value())
 | 
						|
			if err != nil {
 | 
						|
				return nilValue, err
 | 
						|
			}
 | 
						|
			ret.SetMapIndex(key, value)
 | 
						|
		}
 | 
						|
		return ret, nil
 | 
						|
	case reflect.Interface:
 | 
						|
		return castMap(t, reflect.ValueOf(v.Interface()))
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castMap(t, v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to map from empty slice")
 | 
						|
	}
 | 
						|
	return nilValue, fmt.Errorf("failed to cast to map from %s", v.Type().Kind())
 | 
						|
}
 | 
						|
 | 
						|
func castStruct(t reflect.Type, v reflect.Value) (reflect.Value, error) {
 | 
						|
	ret := reflect.New(t).Elem()
 | 
						|
	switch v.Type().Kind() {
 | 
						|
	case reflect.Map:
 | 
						|
		iter := v.MapRange()
 | 
						|
		for iter.Next() {
 | 
						|
			key := iter.Key()
 | 
						|
			k, err := castString(key)
 | 
						|
			if err != nil {
 | 
						|
				return nilValue, err
 | 
						|
			}
 | 
						|
			fieldName := k.String()
 | 
						|
			field, ok := t.FieldByName(fieldName)
 | 
						|
			if ok {
 | 
						|
				value, err := castValue(field.Type, iter.Value())
 | 
						|
				if err != nil {
 | 
						|
					return nilValue, err
 | 
						|
				}
 | 
						|
				ret.FieldByName(fieldName).Set(value)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return ret, nil
 | 
						|
	case reflect.Struct:
 | 
						|
		for i := 0; i < v.Type().NumField(); i++ {
 | 
						|
			name := v.Type().Field(i).Name
 | 
						|
			ret.FieldByName(name).Set(v.FieldByName(name))
 | 
						|
		}
 | 
						|
		return ret, nil
 | 
						|
	case reflect.Interface:
 | 
						|
		return castStruct(t, reflect.ValueOf(v.Interface()))
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.Len() > 0 {
 | 
						|
			return castStruct(t, v.Index(0))
 | 
						|
		}
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to struct from empty slice")
 | 
						|
	default:
 | 
						|
		return nilValue, fmt.Errorf("failed to cast to struct from %s", v.Type().Kind())
 | 
						|
	}
 | 
						|
}
 |