// Copyright 2019-present Facebook Inc. All rights reserved. // This source code is licensed under the Apache 2.0 license found // in the LICENSE file in the root directory of this source tree. package graphson import ( "bytes" "fmt" "io" "reflect" "unsafe" "github.com/json-iterator/go" "github.com/modern-go/reflect2" "github.com/pkg/errors" ) // DecoratorOfInterface decorates a value decoder of an interface type. func (decodeExtension) DecoratorOfInterface(typ reflect2.Type, dec jsoniter.ValDecoder) jsoniter.ValDecoder { if _, ok := typ.(*reflect2.UnsafeEFaceType); ok { return efaceDecoder{typ, dec} } return dec } type efaceDecoder struct { typ reflect2.Type jsoniter.ValDecoder } func (dec efaceDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { switch next := iter.WhatIsNext(); next { case jsoniter.StringValue, jsoniter.BoolValue, jsoniter.NilValue: dec.ValDecoder.Decode(ptr, iter) case jsoniter.ObjectValue: dec.decode(ptr, iter) default: iter.ReportError("decode empty interface", fmt.Sprintf("unexpected value type: %d", next)) } } func (dec efaceDecoder) decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { data := iter.SkipAndReturnBytes() if iter.Error != nil && iter.Error != io.EOF { return } rtype, err := dec.reflectBytes(data) if err != nil { iter.ReportError("decode empty interface", err.Error()) return } it := config.BorrowIterator(data) defer config.ReturnIterator(it) var val interface{} if rtype != nil { val = rtype.New() it.ReadVal(val) val = rtype.Indirect(val) } else { if jsoniter.Get(data, TypeKey).LastError() == nil { vk := jsoniter.Get(data, ValueKey) if vk.LastError() == nil { val = vk.GetInterface() } } if val == nil { val = it.Read() } } if it.Error != nil && it.Error != io.EOF { iter.ReportError("decode empty interface", it.Error.Error()) return } // nolint: gas dec.typ.UnsafeSet(ptr, unsafe.Pointer(&val)) } func (dec efaceDecoder) reflectBytes(data []byte) (reflect2.Type, error) { typ := Type(jsoniter.Get(data, TypeKey).ToString()) rtype := dec.reflectType(typ) if rtype != nil { return rtype, nil } switch typ { case listType: return dec.reflectSlice(data) case mapType: return dec.reflectMap(data) default: return nil, nil } } func (efaceDecoder) reflectType(typ Type) reflect2.Type { switch typ { case doubleType: return reflect2.TypeOf(float64(0)) case floatType: return reflect2.TypeOf(float32(0)) case byteType: return reflect2.TypeOf(uint8(0)) case int16Type: return reflect2.TypeOf(int16(0)) case int32Type: return reflect2.TypeOf(int32(0)) case int64Type, bigIntegerType: return reflect2.TypeOf(int64(0)) case byteBufferType: return reflect2.TypeOf([]byte{}) default: return nil } } func (efaceDecoder) reflectSlice(data []byte) (reflect2.Type, error) { var elem interface{} if err := Unmarshal(data, &[...]*interface{}{&elem}); err != nil { return nil, errors.Wrap(err, "cannot read first list element") } if elem == nil { return reflect2.TypeOf([]interface{}{}), nil } sliceType := reflect.SliceOf(reflect.TypeOf(elem)) return reflect2.Type2(sliceType), nil } func (efaceDecoder) reflectMap(data []byte) (reflect2.Type, error) { var key, elem interface{} if err := Unmarshal( bytes.Replace(data, []byte(mapType), []byte(listType), 1), &[...]*interface{}{&key, &elem}, ); err != nil { return nil, errors.Wrap(err, "cannot unmarshal first map item") } if key == nil { return reflect2.TypeOf(map[interface{}]interface{}{}), nil } else if elem == nil { return nil, errors.New("expect map element, but found only key") } mapType := reflect.MapOf(reflect.TypeOf(key), reflect.TypeOf(elem)) return reflect2.Type2(mapType), nil }