mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 15:02:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			254 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package msgpack
 | |
| 
 | |
| import (
 | |
| 	"encoding"
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| )
 | |
| 
 | |
| var valueEncoders []encoderFunc
 | |
| 
 | |
| //nolint:gochecknoinits
 | |
| func init() {
 | |
| 	valueEncoders = []encoderFunc{
 | |
| 		reflect.Bool:          encodeBoolValue,
 | |
| 		reflect.Int:           encodeIntValue,
 | |
| 		reflect.Int8:          encodeInt8CondValue,
 | |
| 		reflect.Int16:         encodeInt16CondValue,
 | |
| 		reflect.Int32:         encodeInt32CondValue,
 | |
| 		reflect.Int64:         encodeInt64CondValue,
 | |
| 		reflect.Uint:          encodeUintValue,
 | |
| 		reflect.Uint8:         encodeUint8CondValue,
 | |
| 		reflect.Uint16:        encodeUint16CondValue,
 | |
| 		reflect.Uint32:        encodeUint32CondValue,
 | |
| 		reflect.Uint64:        encodeUint64CondValue,
 | |
| 		reflect.Float32:       encodeFloat32Value,
 | |
| 		reflect.Float64:       encodeFloat64Value,
 | |
| 		reflect.Complex64:     encodeUnsupportedValue,
 | |
| 		reflect.Complex128:    encodeUnsupportedValue,
 | |
| 		reflect.Array:         encodeArrayValue,
 | |
| 		reflect.Chan:          encodeUnsupportedValue,
 | |
| 		reflect.Func:          encodeUnsupportedValue,
 | |
| 		reflect.Interface:     encodeInterfaceValue,
 | |
| 		reflect.Map:           encodeMapValue,
 | |
| 		reflect.Ptr:           encodeUnsupportedValue,
 | |
| 		reflect.Slice:         encodeSliceValue,
 | |
| 		reflect.String:        encodeStringValue,
 | |
| 		reflect.Struct:        encodeStructValue,
 | |
| 		reflect.UnsafePointer: encodeUnsupportedValue,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func getEncoder(typ reflect.Type) encoderFunc {
 | |
| 	if v, ok := typeEncMap.Load(typ); ok {
 | |
| 		return v.(encoderFunc)
 | |
| 	}
 | |
| 	fn := _getEncoder(typ)
 | |
| 	typeEncMap.Store(typ, fn)
 | |
| 	return fn
 | |
| }
 | |
| 
 | |
| func _getEncoder(typ reflect.Type) encoderFunc {
 | |
| 	kind := typ.Kind()
 | |
| 
 | |
| 	if kind == reflect.Ptr {
 | |
| 		if _, ok := typeEncMap.Load(typ.Elem()); ok {
 | |
| 			return ptrEncoderFunc(typ)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if typ.Implements(customEncoderType) {
 | |
| 		return encodeCustomValue
 | |
| 	}
 | |
| 	if typ.Implements(marshalerType) {
 | |
| 		return marshalValue
 | |
| 	}
 | |
| 	if typ.Implements(binaryMarshalerType) {
 | |
| 		return marshalBinaryValue
 | |
| 	}
 | |
| 	if typ.Implements(textMarshalerType) {
 | |
| 		return marshalTextValue
 | |
| 	}
 | |
| 
 | |
| 	// Addressable struct field value.
 | |
| 	if kind != reflect.Ptr {
 | |
| 		ptr := reflect.PtrTo(typ)
 | |
| 		if ptr.Implements(customEncoderType) {
 | |
| 			return encodeCustomValuePtr
 | |
| 		}
 | |
| 		if ptr.Implements(marshalerType) {
 | |
| 			return marshalValuePtr
 | |
| 		}
 | |
| 		if ptr.Implements(binaryMarshalerType) {
 | |
| 			return marshalBinaryValueAddr
 | |
| 		}
 | |
| 		if ptr.Implements(textMarshalerType) {
 | |
| 			return marshalTextValueAddr
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if typ == errorType {
 | |
| 		return encodeErrorValue
 | |
| 	}
 | |
| 
 | |
| 	switch kind {
 | |
| 	case reflect.Ptr:
 | |
| 		return ptrEncoderFunc(typ)
 | |
| 	case reflect.Slice:
 | |
| 		elem := typ.Elem()
 | |
| 		if elem.Kind() == reflect.Uint8 {
 | |
| 			return encodeByteSliceValue
 | |
| 		}
 | |
| 		if elem == stringType {
 | |
| 			return encodeStringSliceValue
 | |
| 		}
 | |
| 	case reflect.Array:
 | |
| 		if typ.Elem().Kind() == reflect.Uint8 {
 | |
| 			return encodeByteArrayValue
 | |
| 		}
 | |
| 	case reflect.Map:
 | |
| 		if typ.Key() == stringType {
 | |
| 			switch typ.Elem() {
 | |
| 			case stringType:
 | |
| 				return encodeMapStringStringValue
 | |
| 			case boolType:
 | |
| 				return encodeMapStringBoolValue
 | |
| 			case interfaceType:
 | |
| 				return encodeMapStringInterfaceValue
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return valueEncoders[kind]
 | |
| }
 | |
| 
 | |
| func ptrEncoderFunc(typ reflect.Type) encoderFunc {
 | |
| 	encoder := getEncoder(typ.Elem())
 | |
| 	return func(e *Encoder, v reflect.Value) error {
 | |
| 		if v.IsNil() {
 | |
| 			return e.EncodeNil()
 | |
| 		}
 | |
| 		return encoder(e, v.Elem())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func encodeCustomValuePtr(e *Encoder, v reflect.Value) error {
 | |
| 	if !v.CanAddr() {
 | |
| 		return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
 | |
| 	}
 | |
| 	encoder := v.Addr().Interface().(CustomEncoder)
 | |
| 	return encoder.EncodeMsgpack(e)
 | |
| }
 | |
| 
 | |
| func encodeCustomValue(e *Encoder, v reflect.Value) error {
 | |
| 	if nilable(v.Kind()) && v.IsNil() {
 | |
| 		return e.EncodeNil()
 | |
| 	}
 | |
| 
 | |
| 	encoder := v.Interface().(CustomEncoder)
 | |
| 	return encoder.EncodeMsgpack(e)
 | |
| }
 | |
| 
 | |
| func marshalValuePtr(e *Encoder, v reflect.Value) error {
 | |
| 	if !v.CanAddr() {
 | |
| 		return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
 | |
| 	}
 | |
| 	return marshalValue(e, v.Addr())
 | |
| }
 | |
| 
 | |
| func marshalValue(e *Encoder, v reflect.Value) error {
 | |
| 	if nilable(v.Kind()) && v.IsNil() {
 | |
| 		return e.EncodeNil()
 | |
| 	}
 | |
| 
 | |
| 	marshaler := v.Interface().(Marshaler)
 | |
| 	b, err := marshaler.MarshalMsgpack()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	_, err = e.w.Write(b)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func encodeBoolValue(e *Encoder, v reflect.Value) error {
 | |
| 	return e.EncodeBool(v.Bool())
 | |
| }
 | |
| 
 | |
| func encodeInterfaceValue(e *Encoder, v reflect.Value) error {
 | |
| 	if v.IsNil() {
 | |
| 		return e.EncodeNil()
 | |
| 	}
 | |
| 	return e.EncodeValue(v.Elem())
 | |
| }
 | |
| 
 | |
| func encodeErrorValue(e *Encoder, v reflect.Value) error {
 | |
| 	if v.IsNil() {
 | |
| 		return e.EncodeNil()
 | |
| 	}
 | |
| 	return e.EncodeString(v.Interface().(error).Error())
 | |
| }
 | |
| 
 | |
| func encodeUnsupportedValue(e *Encoder, v reflect.Value) error {
 | |
| 	return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type())
 | |
| }
 | |
| 
 | |
| func nilable(kind reflect.Kind) bool {
 | |
| 	switch kind {
 | |
| 	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func nilableType(t reflect.Type) bool {
 | |
| 	if t.Kind() == reflect.Ptr {
 | |
| 		t = t.Elem()
 | |
| 	}
 | |
| 	return nilable(t.Kind())
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| func marshalBinaryValueAddr(e *Encoder, v reflect.Value) error {
 | |
| 	if !v.CanAddr() {
 | |
| 		return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
 | |
| 	}
 | |
| 	return marshalBinaryValue(e, v.Addr())
 | |
| }
 | |
| 
 | |
| func marshalBinaryValue(e *Encoder, v reflect.Value) error {
 | |
| 	if nilable(v.Kind()) && v.IsNil() {
 | |
| 		return e.EncodeNil()
 | |
| 	}
 | |
| 
 | |
| 	marshaler := v.Interface().(encoding.BinaryMarshaler)
 | |
| 	data, err := marshaler.MarshalBinary()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return e.EncodeBytes(data)
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| func marshalTextValueAddr(e *Encoder, v reflect.Value) error {
 | |
| 	if !v.CanAddr() {
 | |
| 		return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
 | |
| 	}
 | |
| 	return marshalTextValue(e, v.Addr())
 | |
| }
 | |
| 
 | |
| func marshalTextValue(e *Encoder, v reflect.Value) error {
 | |
| 	if nilable(v.Kind()) && v.IsNil() {
 | |
| 		return e.EncodeNil()
 | |
| 	}
 | |
| 
 | |
| 	marshaler := v.Interface().(encoding.TextMarshaler)
 | |
| 	data, err := marshaler.MarshalText()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return e.EncodeBytes(data)
 | |
| }
 |