| 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 | |
| } |