mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 02:22:26 -05:00 
			
		
		
		
	* start fixing up tests * fix up tests + automate with drone * fiddle with linting * messing about with drone.yml * some more fiddling * hmmm * add cache * add vendor directory * verbose * ci updates * update some little things * update sig
		
			
				
	
	
		
			325 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			325 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package jsoniter
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"github.com/modern-go/reflect2"
 | |
| 	"io"
 | |
| 	"reflect"
 | |
| 	"strconv"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| // Any generic object representation.
 | |
| // The lazy json implementation holds []byte and parse lazily.
 | |
| type Any interface {
 | |
| 	LastError() error
 | |
| 	ValueType() ValueType
 | |
| 	MustBeValid() Any
 | |
| 	ToBool() bool
 | |
| 	ToInt() int
 | |
| 	ToInt32() int32
 | |
| 	ToInt64() int64
 | |
| 	ToUint() uint
 | |
| 	ToUint32() uint32
 | |
| 	ToUint64() uint64
 | |
| 	ToFloat32() float32
 | |
| 	ToFloat64() float64
 | |
| 	ToString() string
 | |
| 	ToVal(val interface{})
 | |
| 	Get(path ...interface{}) Any
 | |
| 	Size() int
 | |
| 	Keys() []string
 | |
| 	GetInterface() interface{}
 | |
| 	WriteTo(stream *Stream)
 | |
| }
 | |
| 
 | |
| type baseAny struct{}
 | |
| 
 | |
| func (any *baseAny) Get(path ...interface{}) Any {
 | |
| 	return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)}
 | |
| }
 | |
| 
 | |
| func (any *baseAny) Size() int {
 | |
| 	return 0
 | |
| }
 | |
| 
 | |
| func (any *baseAny) Keys() []string {
 | |
| 	return []string{}
 | |
| }
 | |
| 
 | |
| func (any *baseAny) ToVal(obj interface{}) {
 | |
| 	panic("not implemented")
 | |
| }
 | |
| 
 | |
| // WrapInt32 turn int32 into Any interface
 | |
| func WrapInt32(val int32) Any {
 | |
| 	return &int32Any{baseAny{}, val}
 | |
| }
 | |
| 
 | |
| // WrapInt64 turn int64 into Any interface
 | |
| func WrapInt64(val int64) Any {
 | |
| 	return &int64Any{baseAny{}, val}
 | |
| }
 | |
| 
 | |
| // WrapUint32 turn uint32 into Any interface
 | |
| func WrapUint32(val uint32) Any {
 | |
| 	return &uint32Any{baseAny{}, val}
 | |
| }
 | |
| 
 | |
| // WrapUint64 turn uint64 into Any interface
 | |
| func WrapUint64(val uint64) Any {
 | |
| 	return &uint64Any{baseAny{}, val}
 | |
| }
 | |
| 
 | |
| // WrapFloat64 turn float64 into Any interface
 | |
| func WrapFloat64(val float64) Any {
 | |
| 	return &floatAny{baseAny{}, val}
 | |
| }
 | |
| 
 | |
| // WrapString turn string into Any interface
 | |
| func WrapString(val string) Any {
 | |
| 	return &stringAny{baseAny{}, val}
 | |
| }
 | |
| 
 | |
| // Wrap turn a go object into Any interface
 | |
| func Wrap(val interface{}) Any {
 | |
| 	if val == nil {
 | |
| 		return &nilAny{}
 | |
| 	}
 | |
| 	asAny, isAny := val.(Any)
 | |
| 	if isAny {
 | |
| 		return asAny
 | |
| 	}
 | |
| 	typ := reflect2.TypeOf(val)
 | |
| 	switch typ.Kind() {
 | |
| 	case reflect.Slice:
 | |
| 		return wrapArray(val)
 | |
| 	case reflect.Struct:
 | |
| 		return wrapStruct(val)
 | |
| 	case reflect.Map:
 | |
| 		return wrapMap(val)
 | |
| 	case reflect.String:
 | |
| 		return WrapString(val.(string))
 | |
| 	case reflect.Int:
 | |
| 		if strconv.IntSize == 32 {
 | |
| 			return WrapInt32(int32(val.(int)))
 | |
| 		}
 | |
| 		return WrapInt64(int64(val.(int)))
 | |
| 	case reflect.Int8:
 | |
| 		return WrapInt32(int32(val.(int8)))
 | |
| 	case reflect.Int16:
 | |
| 		return WrapInt32(int32(val.(int16)))
 | |
| 	case reflect.Int32:
 | |
| 		return WrapInt32(val.(int32))
 | |
| 	case reflect.Int64:
 | |
| 		return WrapInt64(val.(int64))
 | |
| 	case reflect.Uint:
 | |
| 		if strconv.IntSize == 32 {
 | |
| 			return WrapUint32(uint32(val.(uint)))
 | |
| 		}
 | |
| 		return WrapUint64(uint64(val.(uint)))
 | |
| 	case reflect.Uintptr:
 | |
| 		if ptrSize == 32 {
 | |
| 			return WrapUint32(uint32(val.(uintptr)))
 | |
| 		}
 | |
| 		return WrapUint64(uint64(val.(uintptr)))
 | |
| 	case reflect.Uint8:
 | |
| 		return WrapUint32(uint32(val.(uint8)))
 | |
| 	case reflect.Uint16:
 | |
| 		return WrapUint32(uint32(val.(uint16)))
 | |
| 	case reflect.Uint32:
 | |
| 		return WrapUint32(uint32(val.(uint32)))
 | |
| 	case reflect.Uint64:
 | |
| 		return WrapUint64(val.(uint64))
 | |
| 	case reflect.Float32:
 | |
| 		return WrapFloat64(float64(val.(float32)))
 | |
| 	case reflect.Float64:
 | |
| 		return WrapFloat64(val.(float64))
 | |
| 	case reflect.Bool:
 | |
| 		if val.(bool) == true {
 | |
| 			return &trueAny{}
 | |
| 		}
 | |
| 		return &falseAny{}
 | |
| 	}
 | |
| 	return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)}
 | |
| }
 | |
| 
 | |
| // ReadAny read next JSON element as an Any object. It is a better json.RawMessage.
 | |
| func (iter *Iterator) ReadAny() Any {
 | |
| 	return iter.readAny()
 | |
| }
 | |
| 
 | |
| func (iter *Iterator) readAny() Any {
 | |
| 	c := iter.nextToken()
 | |
| 	switch c {
 | |
| 	case '"':
 | |
| 		iter.unreadByte()
 | |
| 		return &stringAny{baseAny{}, iter.ReadString()}
 | |
| 	case 'n':
 | |
| 		iter.skipThreeBytes('u', 'l', 'l') // null
 | |
| 		return &nilAny{}
 | |
| 	case 't':
 | |
| 		iter.skipThreeBytes('r', 'u', 'e') // true
 | |
| 		return &trueAny{}
 | |
| 	case 'f':
 | |
| 		iter.skipFourBytes('a', 'l', 's', 'e') // false
 | |
| 		return &falseAny{}
 | |
| 	case '{':
 | |
| 		return iter.readObjectAny()
 | |
| 	case '[':
 | |
| 		return iter.readArrayAny()
 | |
| 	case '-':
 | |
| 		return iter.readNumberAny(false)
 | |
| 	case 0:
 | |
| 		return &invalidAny{baseAny{}, errors.New("input is empty")}
 | |
| 	default:
 | |
| 		return iter.readNumberAny(true)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (iter *Iterator) readNumberAny(positive bool) Any {
 | |
| 	iter.startCapture(iter.head - 1)
 | |
| 	iter.skipNumber()
 | |
| 	lazyBuf := iter.stopCapture()
 | |
| 	return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil}
 | |
| }
 | |
| 
 | |
| func (iter *Iterator) readObjectAny() Any {
 | |
| 	iter.startCapture(iter.head - 1)
 | |
| 	iter.skipObject()
 | |
| 	lazyBuf := iter.stopCapture()
 | |
| 	return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil}
 | |
| }
 | |
| 
 | |
| func (iter *Iterator) readArrayAny() Any {
 | |
| 	iter.startCapture(iter.head - 1)
 | |
| 	iter.skipArray()
 | |
| 	lazyBuf := iter.stopCapture()
 | |
| 	return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil}
 | |
| }
 | |
| 
 | |
| func locateObjectField(iter *Iterator, target string) []byte {
 | |
| 	var found []byte
 | |
| 	iter.ReadObjectCB(func(iter *Iterator, field string) bool {
 | |
| 		if field == target {
 | |
| 			found = iter.SkipAndReturnBytes()
 | |
| 			return false
 | |
| 		}
 | |
| 		iter.Skip()
 | |
| 		return true
 | |
| 	})
 | |
| 	return found
 | |
| }
 | |
| 
 | |
| func locateArrayElement(iter *Iterator, target int) []byte {
 | |
| 	var found []byte
 | |
| 	n := 0
 | |
| 	iter.ReadArrayCB(func(iter *Iterator) bool {
 | |
| 		if n == target {
 | |
| 			found = iter.SkipAndReturnBytes()
 | |
| 			return false
 | |
| 		}
 | |
| 		iter.Skip()
 | |
| 		n++
 | |
| 		return true
 | |
| 	})
 | |
| 	return found
 | |
| }
 | |
| 
 | |
| func locatePath(iter *Iterator, path []interface{}) Any {
 | |
| 	for i, pathKeyObj := range path {
 | |
| 		switch pathKey := pathKeyObj.(type) {
 | |
| 		case string:
 | |
| 			valueBytes := locateObjectField(iter, pathKey)
 | |
| 			if valueBytes == nil {
 | |
| 				return newInvalidAny(path[i:])
 | |
| 			}
 | |
| 			iter.ResetBytes(valueBytes)
 | |
| 		case int:
 | |
| 			valueBytes := locateArrayElement(iter, pathKey)
 | |
| 			if valueBytes == nil {
 | |
| 				return newInvalidAny(path[i:])
 | |
| 			}
 | |
| 			iter.ResetBytes(valueBytes)
 | |
| 		case int32:
 | |
| 			if '*' == pathKey {
 | |
| 				return iter.readAny().Get(path[i:]...)
 | |
| 			}
 | |
| 			return newInvalidAny(path[i:])
 | |
| 		default:
 | |
| 			return newInvalidAny(path[i:])
 | |
| 		}
 | |
| 	}
 | |
| 	if iter.Error != nil && iter.Error != io.EOF {
 | |
| 		return &invalidAny{baseAny{}, iter.Error}
 | |
| 	}
 | |
| 	return iter.readAny()
 | |
| }
 | |
| 
 | |
| var anyType = reflect2.TypeOfPtr((*Any)(nil)).Elem()
 | |
| 
 | |
| func createDecoderOfAny(ctx *ctx, typ reflect2.Type) ValDecoder {
 | |
| 	if typ == anyType {
 | |
| 		return &directAnyCodec{}
 | |
| 	}
 | |
| 	if typ.Implements(anyType) {
 | |
| 		return &anyCodec{
 | |
| 			valType: typ,
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func createEncoderOfAny(ctx *ctx, typ reflect2.Type) ValEncoder {
 | |
| 	if typ == anyType {
 | |
| 		return &directAnyCodec{}
 | |
| 	}
 | |
| 	if typ.Implements(anyType) {
 | |
| 		return &anyCodec{
 | |
| 			valType: typ,
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type anyCodec struct {
 | |
| 	valType reflect2.Type
 | |
| }
 | |
| 
 | |
| func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
 | |
| 	panic("not implemented")
 | |
| }
 | |
| 
 | |
| func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 | |
| 	obj := codec.valType.UnsafeIndirect(ptr)
 | |
| 	any := obj.(Any)
 | |
| 	any.WriteTo(stream)
 | |
| }
 | |
| 
 | |
| func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool {
 | |
| 	obj := codec.valType.UnsafeIndirect(ptr)
 | |
| 	any := obj.(Any)
 | |
| 	return any.Size() == 0
 | |
| }
 | |
| 
 | |
| type directAnyCodec struct {
 | |
| }
 | |
| 
 | |
| func (codec *directAnyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
 | |
| 	*(*Any)(ptr) = iter.readAny()
 | |
| }
 | |
| 
 | |
| func (codec *directAnyCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 | |
| 	any := *(*Any)(ptr)
 | |
| 	if any == nil {
 | |
| 		stream.WriteNil()
 | |
| 		return
 | |
| 	}
 | |
| 	any.WriteTo(stream)
 | |
| }
 | |
| 
 | |
| func (codec *directAnyCodec) IsEmpty(ptr unsafe.Pointer) bool {
 | |
| 	any := *(*Any)(ptr)
 | |
| 	return any.Size() == 0
 | |
| }
 |