mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 14:32:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			251 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package msgpack
 | |
| 
 | |
| import (
 | |
| 	"encoding"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
 | |
| 	stringType    = reflect.TypeOf((*string)(nil)).Elem()
 | |
| 	boolType      = reflect.TypeOf((*bool)(nil)).Elem()
 | |
| )
 | |
| 
 | |
| var valueDecoders []decoderFunc
 | |
| 
 | |
| //nolint:gochecknoinits
 | |
| func init() {
 | |
| 	valueDecoders = []decoderFunc{
 | |
| 		reflect.Bool:          decodeBoolValue,
 | |
| 		reflect.Int:           decodeInt64Value,
 | |
| 		reflect.Int8:          decodeInt64Value,
 | |
| 		reflect.Int16:         decodeInt64Value,
 | |
| 		reflect.Int32:         decodeInt64Value,
 | |
| 		reflect.Int64:         decodeInt64Value,
 | |
| 		reflect.Uint:          decodeUint64Value,
 | |
| 		reflect.Uint8:         decodeUint64Value,
 | |
| 		reflect.Uint16:        decodeUint64Value,
 | |
| 		reflect.Uint32:        decodeUint64Value,
 | |
| 		reflect.Uint64:        decodeUint64Value,
 | |
| 		reflect.Float32:       decodeFloat32Value,
 | |
| 		reflect.Float64:       decodeFloat64Value,
 | |
| 		reflect.Complex64:     decodeUnsupportedValue,
 | |
| 		reflect.Complex128:    decodeUnsupportedValue,
 | |
| 		reflect.Array:         decodeArrayValue,
 | |
| 		reflect.Chan:          decodeUnsupportedValue,
 | |
| 		reflect.Func:          decodeUnsupportedValue,
 | |
| 		reflect.Interface:     decodeInterfaceValue,
 | |
| 		reflect.Map:           decodeMapValue,
 | |
| 		reflect.Ptr:           decodeUnsupportedValue,
 | |
| 		reflect.Slice:         decodeSliceValue,
 | |
| 		reflect.String:        decodeStringValue,
 | |
| 		reflect.Struct:        decodeStructValue,
 | |
| 		reflect.UnsafePointer: decodeUnsupportedValue,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func getDecoder(typ reflect.Type) decoderFunc {
 | |
| 	if v, ok := typeDecMap.Load(typ); ok {
 | |
| 		return v.(decoderFunc)
 | |
| 	}
 | |
| 	fn := _getDecoder(typ)
 | |
| 	typeDecMap.Store(typ, fn)
 | |
| 	return fn
 | |
| }
 | |
| 
 | |
| func _getDecoder(typ reflect.Type) decoderFunc {
 | |
| 	kind := typ.Kind()
 | |
| 
 | |
| 	if kind == reflect.Ptr {
 | |
| 		if _, ok := typeDecMap.Load(typ.Elem()); ok {
 | |
| 			return ptrValueDecoder(typ)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if typ.Implements(customDecoderType) {
 | |
| 		return nilAwareDecoder(typ, decodeCustomValue)
 | |
| 	}
 | |
| 	if typ.Implements(unmarshalerType) {
 | |
| 		return nilAwareDecoder(typ, unmarshalValue)
 | |
| 	}
 | |
| 	if typ.Implements(binaryUnmarshalerType) {
 | |
| 		return nilAwareDecoder(typ, unmarshalBinaryValue)
 | |
| 	}
 | |
| 	if typ.Implements(textUnmarshalerType) {
 | |
| 		return nilAwareDecoder(typ, unmarshalTextValue)
 | |
| 	}
 | |
| 
 | |
| 	// Addressable struct field value.
 | |
| 	if kind != reflect.Ptr {
 | |
| 		ptr := reflect.PtrTo(typ)
 | |
| 		if ptr.Implements(customDecoderType) {
 | |
| 			return addrDecoder(nilAwareDecoder(typ, decodeCustomValue))
 | |
| 		}
 | |
| 		if ptr.Implements(unmarshalerType) {
 | |
| 			return addrDecoder(nilAwareDecoder(typ, unmarshalValue))
 | |
| 		}
 | |
| 		if ptr.Implements(binaryUnmarshalerType) {
 | |
| 			return addrDecoder(nilAwareDecoder(typ, unmarshalBinaryValue))
 | |
| 		}
 | |
| 		if ptr.Implements(textUnmarshalerType) {
 | |
| 			return addrDecoder(nilAwareDecoder(typ, unmarshalTextValue))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	switch kind {
 | |
| 	case reflect.Ptr:
 | |
| 		return ptrValueDecoder(typ)
 | |
| 	case reflect.Slice:
 | |
| 		elem := typ.Elem()
 | |
| 		if elem.Kind() == reflect.Uint8 {
 | |
| 			return decodeBytesValue
 | |
| 		}
 | |
| 		if elem == stringType {
 | |
| 			return decodeStringSliceValue
 | |
| 		}
 | |
| 	case reflect.Array:
 | |
| 		if typ.Elem().Kind() == reflect.Uint8 {
 | |
| 			return decodeByteArrayValue
 | |
| 		}
 | |
| 	case reflect.Map:
 | |
| 		if typ.Key() == stringType {
 | |
| 			switch typ.Elem() {
 | |
| 			case stringType:
 | |
| 				return decodeMapStringStringValue
 | |
| 			case interfaceType:
 | |
| 				return decodeMapStringInterfaceValue
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return valueDecoders[kind]
 | |
| }
 | |
| 
 | |
| func ptrValueDecoder(typ reflect.Type) decoderFunc {
 | |
| 	decoder := getDecoder(typ.Elem())
 | |
| 	return func(d *Decoder, v reflect.Value) error {
 | |
| 		if d.hasNilCode() {
 | |
| 			if !v.IsNil() {
 | |
| 				v.Set(d.newValue(typ).Elem())
 | |
| 			}
 | |
| 			return d.DecodeNil()
 | |
| 		}
 | |
| 		if v.IsNil() {
 | |
| 			v.Set(d.newValue(typ.Elem()))
 | |
| 		}
 | |
| 		return decoder(d, v.Elem())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func addrDecoder(fn decoderFunc) decoderFunc {
 | |
| 	return func(d *Decoder, v reflect.Value) error {
 | |
| 		if !v.CanAddr() {
 | |
| 			return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
 | |
| 		}
 | |
| 		return fn(d, v.Addr())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func nilAwareDecoder(typ reflect.Type, fn decoderFunc) decoderFunc {
 | |
| 	if nilable(typ.Kind()) {
 | |
| 		return func(d *Decoder, v reflect.Value) error {
 | |
| 			if d.hasNilCode() {
 | |
| 				return d.decodeNilValue(v)
 | |
| 			}
 | |
| 			if v.IsNil() {
 | |
| 				v.Set(d.newValue(typ.Elem()))
 | |
| 			}
 | |
| 			return fn(d, v)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return func(d *Decoder, v reflect.Value) error {
 | |
| 		if d.hasNilCode() {
 | |
| 			return d.decodeNilValue(v)
 | |
| 		}
 | |
| 		return fn(d, v)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func decodeBoolValue(d *Decoder, v reflect.Value) error {
 | |
| 	flag, err := d.DecodeBool()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	v.SetBool(flag)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func decodeInterfaceValue(d *Decoder, v reflect.Value) error {
 | |
| 	if v.IsNil() {
 | |
| 		return d.interfaceValue(v)
 | |
| 	}
 | |
| 	return d.DecodeValue(v.Elem())
 | |
| }
 | |
| 
 | |
| func (d *Decoder) interfaceValue(v reflect.Value) error {
 | |
| 	vv, err := d.decodeInterfaceCond()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if vv != nil {
 | |
| 		if v.Type() == errorType {
 | |
| 			if vv, ok := vv.(string); ok {
 | |
| 				v.Set(reflect.ValueOf(errors.New(vv)))
 | |
| 				return nil
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		v.Set(reflect.ValueOf(vv))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func decodeUnsupportedValue(d *Decoder, v reflect.Value) error {
 | |
| 	return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type())
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| func decodeCustomValue(d *Decoder, v reflect.Value) error {
 | |
| 	decoder := v.Interface().(CustomDecoder)
 | |
| 	return decoder.DecodeMsgpack(d)
 | |
| }
 | |
| 
 | |
| func unmarshalValue(d *Decoder, v reflect.Value) error {
 | |
| 	var b []byte
 | |
| 
 | |
| 	d.rec = make([]byte, 0, 64)
 | |
| 	if err := d.Skip(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	b = d.rec
 | |
| 	d.rec = nil
 | |
| 
 | |
| 	unmarshaler := v.Interface().(Unmarshaler)
 | |
| 	return unmarshaler.UnmarshalMsgpack(b)
 | |
| }
 | |
| 
 | |
| func unmarshalBinaryValue(d *Decoder, v reflect.Value) error {
 | |
| 	data, err := d.DecodeBytes()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	unmarshaler := v.Interface().(encoding.BinaryUnmarshaler)
 | |
| 	return unmarshaler.UnmarshalBinary(data)
 | |
| }
 | |
| 
 | |
| func unmarshalTextValue(d *Decoder, v reflect.Value) error {
 | |
| 	data, err := d.DecodeBytes()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	unmarshaler := v.Interface().(encoding.TextUnmarshaler)
 | |
| 	return unmarshaler.UnmarshalText(data)
 | |
| }
 |