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