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 }