diff --git a/any.go b/any.go index 1b237ed..ad8892e 100644 --- a/any.go +++ b/any.go @@ -247,7 +247,7 @@ func locatePath(iter *Iterator, path []interface{}) Any { var anyType = reflect.TypeOf((*Any)(nil)).Elem() -func createDecoderOfAny(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func createDecoderOfAny(ctx *ctx, typ reflect.Type) ValDecoder { if typ == anyType { return &directAnyCodec{} } @@ -259,7 +259,7 @@ func createDecoderOfAny(cfg *frozenConfig, prefix string, typ reflect.Type) ValD return nil } -func createEncoderOfAny(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func createEncoderOfAny(ctx *ctx, typ reflect.Type) ValEncoder { if typ == anyType { return &directAnyCodec{} } diff --git a/reflect.go b/reflect.go index a39785b..d151bb6 100644 --- a/reflect.go +++ b/reflect.go @@ -33,6 +33,22 @@ type checkIsEmpty interface { IsEmpty(ptr unsafe.Pointer) bool } +type ctx struct { + *frozenConfig + prefix string + encoders map[reflect.Type]ValEncoder + decoders map[reflect.Type]ValDecoder +} + +func (b *ctx) append(prefix string) *ctx { + return &ctx{ + frozenConfig: b.frozenConfig, + prefix: b.prefix + " " + prefix, + encoders: b.encoders, + decoders: b.decoders, + } +} + // ReadVal copy the underlying JSON into go interface, same as json.Unmarshal func (iter *Iterator) ReadVal(obj interface{}) { typ := reflect.TypeOf(obj) @@ -66,44 +82,62 @@ func (cfg *frozenConfig) DecoderOf(typ reflect.Type) ValDecoder { if decoder != nil { return decoder } - decoder = decoderOfType(cfg, "", typ.Elem()) + ctx := &ctx{ + frozenConfig: cfg, + prefix: "", + decoders: map[reflect.Type]ValDecoder{}, + encoders: map[reflect.Type]ValEncoder{}, + } + decoder = decoderOfType(ctx, typ.Elem()) cfg.addDecoderToCache(cacheKey, decoder) return decoder } -func decoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { - decoder := getTypeDecoderFromExtension(cfg, typ) +func decoderOfType(ctx *ctx, typ reflect.Type) ValDecoder { + decoder := getTypeDecoderFromExtension(ctx, typ) if decoder != nil { return decoder } - decoder = createDecoderOfType(cfg, prefix, typ) + decoder = createDecoderOfType(ctx, typ) for _, extension := range extensions { decoder = extension.DecorateDecoder(typ, decoder) } - for _, extension := range cfg.extensions { + for _, extension := range ctx.extensions { decoder = extension.DecorateDecoder(typ, decoder) } return decoder } -func createDecoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { - decoder := createDecoderOfJsonRawMessage(cfg, prefix, typ) +func createDecoderOfType(ctx *ctx, typ reflect.Type) ValDecoder { + decoder := ctx.decoders[typ] if decoder != nil { return decoder } - decoder = createDecoderOfJsonNumber(cfg, prefix, typ) + placeholder := &placeholderDecoder{} + ctx.decoders[typ] = placeholder + decoder = _createDecoderOfType(ctx, typ) + placeholder.decoder = decoder + return decoder +} + +func _createDecoderOfType(ctx *ctx, typ reflect.Type) ValDecoder { + decoder := createDecoderOfJsonRawMessage(ctx, typ) if decoder != nil { return decoder } - decoder = createDecoderOfMarshaler(cfg, prefix, typ) + decoder = createDecoderOfJsonNumber(ctx, typ) if decoder != nil { return decoder } - decoder = createDecoderOfAny(cfg, prefix, typ) + decoder = createDecoderOfMarshaler(ctx, typ) if decoder != nil { return decoder } - decoder = createDecoderOfNative(cfg, prefix, typ) + decoder = createDecoderOfAny(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfNative(ctx, typ) if decoder != nil { return decoder } @@ -115,17 +149,17 @@ func createDecoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val } return &efaceDecoder{} case reflect.Struct: - return decoderOfStruct(cfg, prefix, typ) + return decoderOfStruct(ctx, typ) case reflect.Array: - return decoderOfArray(cfg, prefix, typ) + return decoderOfArray(ctx, typ) case reflect.Slice: - return decoderOfSlice(cfg, prefix, typ) + return decoderOfSlice(ctx, typ) case reflect.Map: - return decoderOfMap(cfg, prefix, typ) + return decoderOfMap(ctx, typ) case reflect.Ptr: - return decoderOfOptional(cfg, prefix, typ) + return decoderOfOptional(ctx, typ) default: - return &lazyErrorDecoder{err: fmt.Errorf("%s%s is unsupported type", prefix, typ.String())} + return &lazyErrorDecoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} } } @@ -135,7 +169,13 @@ func (cfg *frozenConfig) EncoderOf(typ reflect.Type) ValEncoder { if encoder != nil { return encoder } - encoder = encoderOfType(cfg, "", typ) + ctx := &ctx{ + frozenConfig: cfg, + prefix: "", + decoders: map[reflect.Type]ValDecoder{}, + encoders: map[reflect.Type]ValEncoder{}, + } + encoder = encoderOfType(ctx, typ) if shouldFixOnePtr(typ) { encoder = &onePtrEncoder{encoder} } @@ -159,39 +199,50 @@ func shouldFixOnePtr(typ reflect.Type) bool { return reflect2.Type2(typ).LikePtr() } -func encoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { - encoder := getTypeEncoderFromExtension(cfg, typ) +func encoderOfType(ctx *ctx, typ reflect.Type) ValEncoder { + encoder := getTypeEncoderFromExtension(ctx, typ) if encoder != nil { return encoder } - encoder = createEncoderOfType(cfg, prefix, typ) + encoder = createEncoderOfType(ctx, typ) for _, extension := range extensions { encoder = extension.DecorateEncoder(typ, encoder) } - for _, extension := range cfg.extensions { + for _, extension := range ctx.extensions { encoder = extension.DecorateEncoder(typ, encoder) } return encoder } -func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { - encoder := createEncoderOfJsonRawMessage(cfg, prefix, typ) +func createEncoderOfType(ctx *ctx, typ reflect.Type) ValEncoder { + encoder := ctx.encoders[typ] if encoder != nil { return encoder } - encoder = createEncoderOfJsonNumber(cfg, prefix, typ) + placeholder := &placeholderEncoder{} + ctx.encoders[typ] = placeholder + encoder = _createEncoderOfType(ctx, typ) + placeholder.encoder = encoder + return encoder +} +func _createEncoderOfType(ctx *ctx, typ reflect.Type) ValEncoder { + encoder := createEncoderOfJsonRawMessage(ctx, typ) if encoder != nil { return encoder } - encoder = createEncoderOfMarshaler(cfg, prefix, typ) + encoder = createEncoderOfJsonNumber(ctx, typ) if encoder != nil { return encoder } - encoder = createEncoderOfAny(cfg, prefix, typ) + encoder = createEncoderOfMarshaler(ctx, typ) if encoder != nil { return encoder } - encoder = createEncoderOfNative(cfg, prefix, typ) + encoder = createEncoderOfAny(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfNative(ctx, typ) if encoder != nil { return encoder } @@ -200,17 +251,17 @@ func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val case reflect.Interface: return &dynamicEncoder{reflect2.Type2(typ)} case reflect.Struct: - return encoderOfStruct(cfg, prefix, typ) + return encoderOfStruct(ctx, typ) case reflect.Array: - return encoderOfArray(cfg, prefix, typ) + return encoderOfArray(ctx, typ) case reflect.Slice: - return encoderOfSlice(cfg, prefix, typ) + return encoderOfSlice(ctx, typ) case reflect.Map: - return encoderOfMap(cfg, prefix, typ) + return encoderOfMap(ctx, typ) case reflect.Ptr: - return encoderOfOptional(cfg, prefix, typ) + return encoderOfOptional(ctx, typ) default: - return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", prefix, typ.String())} + return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} } } @@ -243,3 +294,23 @@ func (encoder *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool { return false } + +type placeholderDecoder struct { + decoder ValDecoder +} + +func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.decoder.Decode(ptr, iter) +} + +type placeholderEncoder struct { + encoder ValEncoder +} + +func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.encoder.Encode(ptr, stream) +} + +func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(ptr) +} diff --git a/reflect_array.go b/reflect_array.go index ce8397b..440d111 100644 --- a/reflect_array.go +++ b/reflect_array.go @@ -7,16 +7,16 @@ import ( "unsafe" ) -func decoderOfArray(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { - decoder := decoderOfType(cfg, prefix+"[array]->", typ.Elem()) +func decoderOfArray(ctx *ctx, typ reflect.Type) ValDecoder { + decoder := decoderOfType(ctx.append("[arrayElem]"), typ.Elem()) return &arrayDecoder{typ, typ.Elem(), decoder} } -func encoderOfArray(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func encoderOfArray(ctx *ctx, typ reflect.Type) ValEncoder { if typ.Len() == 0 { return emptyArrayEncoder{} } - encoder := encoderOfType(cfg, prefix+"[array]->", typ.Elem()) + encoder := encoderOfType(ctx.append("[arrayElem]"), typ.Elem()) return &arrayEncoder{typ, typ.Elem(), encoder} } diff --git a/reflect_extension.go b/reflect_extension.go index 48f6b75..502ac09 100644 --- a/reflect_extension.go +++ b/reflect_extension.go @@ -208,26 +208,26 @@ func RegisterExtension(extension Extension) { extensions = append(extensions, extension) } -func getTypeDecoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValDecoder { - decoder := _getTypeDecoderFromExtension(cfg, typ) +func getTypeDecoderFromExtension(ctx *ctx, typ reflect.Type) ValDecoder { + decoder := _getTypeDecoderFromExtension(ctx, typ) if decoder != nil { for _, extension := range extensions { decoder = extension.DecorateDecoder(typ, decoder) } - for _, extension := range cfg.extensions { + for _, extension := range ctx.extensions { decoder = extension.DecorateDecoder(typ, decoder) } } return decoder } -func _getTypeDecoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValDecoder { +func _getTypeDecoderFromExtension(ctx *ctx, typ reflect.Type) ValDecoder { for _, extension := range extensions { decoder := extension.CreateDecoder(typ) if decoder != nil { return decoder } } - for _, extension := range cfg.extensions { + for _, extension := range ctx.extensions { decoder := extension.CreateDecoder(typ) if decoder != nil { return decoder @@ -247,27 +247,27 @@ func _getTypeDecoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValDecode return nil } -func getTypeEncoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValEncoder { - encoder := _getTypeEncoderFromExtension(cfg, typ) +func getTypeEncoderFromExtension(ctx *ctx, typ reflect.Type) ValEncoder { + encoder := _getTypeEncoderFromExtension(ctx, typ) if encoder != nil { for _, extension := range extensions { encoder = extension.DecorateEncoder(typ, encoder) } - for _, extension := range cfg.extensions { + for _, extension := range ctx.extensions { encoder = extension.DecorateEncoder(typ, encoder) } } return encoder } -func _getTypeEncoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValEncoder { +func _getTypeEncoderFromExtension(ctx *ctx, typ reflect.Type) ValEncoder { for _, extension := range extensions { encoder := extension.CreateEncoder(typ) if encoder != nil { return encoder } } - for _, extension := range cfg.extensions { + for _, extension := range ctx.extensions { encoder := extension.CreateEncoder(typ) if encoder != nil { return encoder @@ -287,13 +287,13 @@ func _getTypeEncoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValEncode return nil } -func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructDescriptor { +func describeStruct(ctx *ctx, typ reflect.Type) *StructDescriptor { embeddedBindings := []*Binding{} bindings := []*Binding{} for i := 0; i < typ.NumField(); i++ { field := typ.Field(i) - tag, hastag := field.Tag.Lookup(cfg.getTagKey()) - if cfg.onlyTaggedField && !hastag { + tag, hastag := field.Tag.Lookup(ctx.getTagKey()) + if ctx.onlyTaggedField && !hastag { continue } tagParts := strings.Split(tag, ",") @@ -302,7 +302,7 @@ func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructD } if field.Anonymous && (tag == "" || tagParts[0] == "") { if field.Type.Kind() == reflect.Struct { - structDescriptor := describeStruct(cfg, prefix, field.Type) + structDescriptor := describeStruct(ctx, field.Type) for _, binding := range structDescriptor.Fields { binding.levels = append([]int{i}, binding.levels...) omitempty := binding.Encoder.(*structFieldEncoder).omitempty @@ -312,7 +312,7 @@ func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructD } continue } else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { - structDescriptor := describeStruct(cfg, prefix, field.Type.Elem()) + structDescriptor := describeStruct(ctx, field.Type.Elem()) for _, binding := range structDescriptor.Fields { binding.levels = append([]int{i}, binding.levels...) omitempty := binding.Encoder.(*structFieldEncoder).omitempty @@ -329,11 +329,11 @@ func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructD fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) decoder := fieldDecoders[fieldCacheKey] if decoder == nil { - decoder = decoderOfType(cfg, prefix+typ.String()+"."+field.Name+"->", field.Type) + decoder = decoderOfType(ctx.append(field.Name), field.Type) } encoder := fieldEncoders[fieldCacheKey] if encoder == nil { - encoder = encoderOfType(cfg, prefix+typ.String()+"."+field.Name+"->", field.Type) + encoder = encoderOfType(ctx.append(field.Name), field.Type) } binding := &Binding{ Field: &field, @@ -345,9 +345,9 @@ func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructD binding.levels = []int{i} bindings = append(bindings, binding) } - return createStructDescriptor(cfg, typ, bindings, embeddedBindings) + return createStructDescriptor(ctx, typ, bindings, embeddedBindings) } -func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { +func createStructDescriptor(ctx *ctx, typ reflect.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { structDescriptor := &StructDescriptor{ Type: typ, Fields: bindings, @@ -355,10 +355,10 @@ func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Bin for _, extension := range extensions { extension.UpdateStructDescriptor(structDescriptor) } - for _, extension := range cfg.extensions { + for _, extension := range ctx.extensions { extension.UpdateStructDescriptor(structDescriptor) } - processTags(structDescriptor, cfg) + processTags(structDescriptor, ctx.frozenConfig) // merge normal & embedded bindings & sort with original order allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) sort.Sort(allBindings) diff --git a/reflect_json_number.go b/reflect_json_number.go index e8fdf53..0debd5d 100644 --- a/reflect_json_number.go +++ b/reflect_json_number.go @@ -35,7 +35,7 @@ func CastJsonNumber(val interface{}) (string, bool) { var jsonNumberType = reflect.TypeOf((*json.Number)(nil)).Elem() var jsoniterNumberType = reflect.TypeOf((*Number)(nil)).Elem() -func createDecoderOfJsonNumber(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func createDecoderOfJsonNumber(ctx *ctx, typ reflect.Type) ValDecoder { if typ.AssignableTo(jsonNumberType) { return &jsonNumberCodec{} } @@ -45,7 +45,7 @@ func createDecoderOfJsonNumber(cfg *frozenConfig, prefix string, typ reflect.Typ return nil } -func createEncoderOfJsonNumber(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func createEncoderOfJsonNumber(ctx *ctx, typ reflect.Type) ValEncoder { if typ.AssignableTo(jsonNumberType) { return &jsonNumberCodec{} } diff --git a/reflect_json_raw_message.go b/reflect_json_raw_message.go index 1216419..6c583a6 100644 --- a/reflect_json_raw_message.go +++ b/reflect_json_raw_message.go @@ -9,7 +9,7 @@ import ( var jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem() var jsoniterRawMessageType = reflect.TypeOf((*RawMessage)(nil)).Elem() -func createEncoderOfJsonRawMessage(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func createEncoderOfJsonRawMessage(ctx *ctx, typ reflect.Type) ValEncoder { if typ == jsonRawMessageType { return &jsonRawMessageCodec{} } @@ -19,7 +19,7 @@ func createEncoderOfJsonRawMessage(cfg *frozenConfig, prefix string, typ reflect return nil } -func createDecoderOfJsonRawMessage(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func createDecoderOfJsonRawMessage(ctx *ctx, typ reflect.Type) ValDecoder { if typ == jsonRawMessageType { return &jsonRawMessageCodec{} } diff --git a/reflect_map.go b/reflect_map.go index 8e34353..c98140d 100644 --- a/reflect_map.go +++ b/reflect_map.go @@ -8,9 +8,9 @@ import ( "fmt" ) -func decoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { - keyDecoder := decoderOfMapKey(cfg, prefix+" [mapKey]", typ.Key()) - elemDecoder := decoderOfType(cfg, prefix+" [mapElem]", typ.Elem()) +func decoderOfMap(ctx *ctx, typ reflect.Type) ValDecoder { + keyDecoder := decoderOfMapKey(ctx.append("[mapKey]"), typ.Key()) + elemDecoder := decoderOfType(ctx.append("[mapElem]"), typ.Elem()) mapType := reflect2.Type2(typ).(*reflect2.UnsafeMapType) return &mapDecoder{ mapType: mapType, @@ -21,25 +21,25 @@ func decoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder } } -func encoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { - if cfg.sortMapKeys { +func encoderOfMap(ctx *ctx, typ reflect.Type) ValEncoder { + if ctx.sortMapKeys { return &sortKeysMapEncoder{ mapType: reflect2.Type2(typ).(*reflect2.UnsafeMapType), - keyEncoder: encoderOfMapKey(cfg, prefix+" [mapKey]", typ.Key()), - elemEncoder: encoderOfType(cfg, prefix+" [mapElem]", typ.Elem()), + keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), typ.Key()), + elemEncoder: encoderOfType(ctx.append("[mapElem]"), typ.Elem()), } } return &mapEncoder{ mapType: reflect2.Type2(typ).(*reflect2.UnsafeMapType), - keyEncoder: encoderOfMapKey(cfg, prefix+" [mapKey]", typ.Key()), - elemEncoder: encoderOfType(cfg, prefix+" [mapElem]", typ.Elem()), + keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), typ.Key()), + elemEncoder: encoderOfType(ctx.append("[mapElem]"), typ.Elem()), } } -func decoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func decoderOfMapKey(ctx *ctx, typ reflect.Type) ValDecoder { switch typ.Kind() { case reflect.String: - return decoderOfType(cfg, prefix, reflect2.DefaultTypeOfKind(reflect.String).Type1()) + return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String).Type1()) case reflect.Bool, reflect.Uint8, reflect.Int8, reflect.Uint16, reflect.Int16, @@ -49,7 +49,7 @@ func decoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValDeco reflect.Float32, reflect.Float64, reflect.Uintptr: typ = reflect2.DefaultTypeOfKind(typ.Kind()).Type1() - return &numericMapKeyDecoder{decoderOfType(cfg, prefix, typ)} + return &numericMapKeyDecoder{decoderOfType(ctx, typ)} default: ptrType := reflect.PtrTo(typ) if ptrType.Implements(textMarshalerType) { @@ -68,10 +68,10 @@ func decoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValDeco } } -func encoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func encoderOfMapKey(ctx *ctx, typ reflect.Type) ValEncoder { switch typ.Kind() { case reflect.String: - return encoderOfType(cfg, prefix, reflect2.DefaultTypeOfKind(reflect.String).Type1()) + return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String).Type1()) case reflect.Bool, reflect.Uint8, reflect.Int8, reflect.Uint16, reflect.Int16, @@ -81,17 +81,17 @@ func encoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValEnco reflect.Float32, reflect.Float64, reflect.Uintptr: typ = reflect2.DefaultTypeOfKind(typ.Kind()).Type1() - return &numericMapKeyEncoder{encoderOfType(cfg, prefix, typ)} + return &numericMapKeyEncoder{encoderOfType(ctx, typ)} default: if typ == textMarshalerType { return &directTextMarshalerEncoder{ - stringEncoder: cfg.EncoderOf(reflect.TypeOf("")), + stringEncoder: ctx.EncoderOf(reflect.TypeOf("")), } } if typ.Implements(textMarshalerType) { return &textMarshalerEncoder{ valType: reflect2.Type2(typ), - stringEncoder: cfg.EncoderOf(reflect.TypeOf("")), + stringEncoder: ctx.EncoderOf(reflect.TypeOf("")), } } return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} diff --git a/reflect_marshaler.go b/reflect_marshaler.go index 17d60a8..abcd92a 100644 --- a/reflect_marshaler.go +++ b/reflect_marshaler.go @@ -13,7 +13,7 @@ var unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() -func createDecoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func createDecoderOfMarshaler(ctx *ctx, typ reflect.Type) ValDecoder { ptrType := reflect.PtrTo(typ) if ptrType.Implements(unmarshalerType) { return &referenceDecoder{ @@ -28,16 +28,16 @@ func createDecoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type return nil } -func createEncoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func createEncoderOfMarshaler(ctx *ctx, typ reflect.Type) ValEncoder { if typ == marshalerType { - checkIsEmpty := createCheckIsEmpty(cfg, typ) + checkIsEmpty := createCheckIsEmpty(ctx, typ) var encoder ValEncoder = &directMarshalerEncoder{ checkIsEmpty: checkIsEmpty, } return encoder } if typ.Implements(marshalerType) { - checkIsEmpty := createCheckIsEmpty(cfg, typ) + checkIsEmpty := createCheckIsEmpty(ctx, typ) var encoder ValEncoder = &marshalerEncoder{ valType: reflect2.Type2(typ), checkIsEmpty: checkIsEmpty, @@ -45,8 +45,8 @@ func createEncoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type return encoder } ptrType := reflect.PtrTo(typ) - if prefix != "" && ptrType.Implements(marshalerType) { - checkIsEmpty := createCheckIsEmpty(cfg, ptrType) + if ctx.prefix != "" && ptrType.Implements(marshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, ptrType) var encoder ValEncoder = &marshalerEncoder{ valType: reflect2.Type2(ptrType), checkIsEmpty: checkIsEmpty, @@ -54,28 +54,28 @@ func createEncoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type return &referenceEncoder{encoder} } if typ == textMarshalerType { - checkIsEmpty := createCheckIsEmpty(cfg, typ) + checkIsEmpty := createCheckIsEmpty(ctx, typ) var encoder ValEncoder = &directTextMarshalerEncoder{ checkIsEmpty: checkIsEmpty, - stringEncoder: cfg.EncoderOf(reflect.TypeOf("")), + stringEncoder: ctx.EncoderOf(reflect.TypeOf("")), } return encoder } if typ.Implements(textMarshalerType) { - checkIsEmpty := createCheckIsEmpty(cfg, typ) + checkIsEmpty := createCheckIsEmpty(ctx, typ) var encoder ValEncoder = &textMarshalerEncoder{ valType: reflect2.Type2(typ), - stringEncoder: cfg.EncoderOf(reflect.TypeOf("")), + stringEncoder: ctx.EncoderOf(reflect.TypeOf("")), checkIsEmpty: checkIsEmpty, } return encoder } // if prefix is empty, the type is the root type - if prefix != "" && ptrType.Implements(textMarshalerType) { - checkIsEmpty := createCheckIsEmpty(cfg, ptrType) + if ctx.prefix != "" && ptrType.Implements(textMarshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, ptrType) var encoder ValEncoder = &textMarshalerEncoder{ valType: reflect2.Type2(ptrType), - stringEncoder: cfg.EncoderOf(reflect.TypeOf("")), + stringEncoder: ctx.EncoderOf(reflect.TypeOf("")), checkIsEmpty: checkIsEmpty, } return &referenceEncoder{encoder} diff --git a/reflect_native.go b/reflect_native.go index 6cbede6..99e3f58 100644 --- a/reflect_native.go +++ b/reflect_native.go @@ -7,9 +7,9 @@ import ( "github.com/v2pro/plz/reflect2" ) -func createEncoderOfNative(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func createEncoderOfNative(ctx *ctx, typ reflect.Type) ValEncoder { if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { - sliceDecoder := decoderOfSlice(cfg, prefix, typ) + sliceDecoder := decoderOfSlice(ctx, typ) return &base64Codec{sliceDecoder: sliceDecoder} } typeName := typ.String() @@ -17,163 +17,163 @@ func createEncoderOfNative(cfg *frozenConfig, prefix string, typ reflect.Type) V switch kind { case reflect.String: if typeName != "string" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*string)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*string)(nil)).Elem()) } return &stringCodec{} case reflect.Int: if typeName != "int" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*int)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*int)(nil)).Elem()) } return &intCodec{} case reflect.Int8: if typeName != "int8" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*int8)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*int8)(nil)).Elem()) } return &int8Codec{} case reflect.Int16: if typeName != "int16" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*int16)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*int16)(nil)).Elem()) } return &int16Codec{} case reflect.Int32: if typeName != "int32" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*int32)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*int32)(nil)).Elem()) } return &int32Codec{} case reflect.Int64: if typeName != "int64" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*int64)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*int64)(nil)).Elem()) } return &int64Codec{} case reflect.Uint: if typeName != "uint" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*uint)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*uint)(nil)).Elem()) } return &uintCodec{} case reflect.Uint8: if typeName != "uint8" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*uint8)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*uint8)(nil)).Elem()) } return &uint8Codec{} case reflect.Uint16: if typeName != "uint16" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*uint16)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*uint16)(nil)).Elem()) } return &uint16Codec{} case reflect.Uint32: if typeName != "uint32" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*uint32)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*uint32)(nil)).Elem()) } return &uint32Codec{} case reflect.Uintptr: if typeName != "uintptr" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*uintptr)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*uintptr)(nil)).Elem()) } return &uintptrCodec{} case reflect.Uint64: if typeName != "uint64" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*uint64)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*uint64)(nil)).Elem()) } return &uint64Codec{} case reflect.Float32: if typeName != "float32" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*float32)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*float32)(nil)).Elem()) } return &float32Codec{} case reflect.Float64: if typeName != "float64" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*float64)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*float64)(nil)).Elem()) } return &float64Codec{} case reflect.Bool: if typeName != "bool" { - return encoderOfType(cfg, prefix, reflect.TypeOf((*bool)(nil)).Elem()) + return encoderOfType(ctx, reflect.TypeOf((*bool)(nil)).Elem()) } return &boolCodec{} } return nil } -func createDecoderOfNative(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func createDecoderOfNative(ctx *ctx, typ reflect.Type) ValDecoder { if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { - sliceDecoder := decoderOfSlice(cfg, prefix, typ) + sliceDecoder := decoderOfSlice(ctx, typ) return &base64Codec{sliceDecoder: sliceDecoder} } typeName := typ.String() switch typ.Kind() { case reflect.String: if typeName != "string" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*string)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*string)(nil)).Elem()) } return &stringCodec{} case reflect.Int: if typeName != "int" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*int)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*int)(nil)).Elem()) } return &intCodec{} case reflect.Int8: if typeName != "int8" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*int8)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*int8)(nil)).Elem()) } return &int8Codec{} case reflect.Int16: if typeName != "int16" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*int16)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*int16)(nil)).Elem()) } return &int16Codec{} case reflect.Int32: if typeName != "int32" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*int32)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*int32)(nil)).Elem()) } return &int32Codec{} case reflect.Int64: if typeName != "int64" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*int64)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*int64)(nil)).Elem()) } return &int64Codec{} case reflect.Uint: if typeName != "uint" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*uint)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*uint)(nil)).Elem()) } return &uintCodec{} case reflect.Uint8: if typeName != "uint8" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*uint8)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*uint8)(nil)).Elem()) } return &uint8Codec{} case reflect.Uint16: if typeName != "uint16" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*uint16)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*uint16)(nil)).Elem()) } return &uint16Codec{} case reflect.Uint32: if typeName != "uint32" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*uint32)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*uint32)(nil)).Elem()) } return &uint32Codec{} case reflect.Uintptr: if typeName != "uintptr" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*uintptr)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*uintptr)(nil)).Elem()) } return &uintptrCodec{} case reflect.Uint64: if typeName != "uint64" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*uint64)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*uint64)(nil)).Elem()) } return &uint64Codec{} case reflect.Float32: if typeName != "float32" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*float32)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*float32)(nil)).Elem()) } return &float32Codec{} case reflect.Float64: if typeName != "float64" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*float64)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*float64)(nil)).Elem()) } return &float64Codec{} case reflect.Bool: if typeName != "bool" { - return decoderOfType(cfg, prefix, reflect.TypeOf((*bool)(nil)).Elem()) + return decoderOfType(ctx, reflect.TypeOf((*bool)(nil)).Elem()) } return &boolCodec{} } diff --git a/reflect_optional.go b/reflect_optional.go index 86dd15f..94225a8 100644 --- a/reflect_optional.go +++ b/reflect_optional.go @@ -6,18 +6,18 @@ import ( "github.com/v2pro/plz/reflect2" ) -func decoderOfOptional(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func decoderOfOptional(ctx *ctx, typ reflect.Type) ValDecoder { elemType := typ.Elem() - decoder := decoderOfType(cfg, prefix, elemType) - if prefix == "" && elemType.Kind() == reflect.Ptr { + decoder := decoderOfType(ctx, elemType) + if ctx.prefix == "" && elemType.Kind() == reflect.Ptr { return &dereferenceDecoder{reflect2.Type2(elemType), decoder} } return &OptionalDecoder{reflect2.Type2(elemType), decoder} } -func encoderOfOptional(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func encoderOfOptional(ctx *ctx, typ reflect.Type) ValEncoder { elemType := typ.Elem() - elemEncoder := encoderOfType(cfg, prefix, elemType) + elemEncoder := encoderOfType(ctx, elemType) encoder := &OptionalEncoder{elemEncoder} return encoder } diff --git a/reflect_slice.go b/reflect_slice.go index 92a97b8..e04e69f 100644 --- a/reflect_slice.go +++ b/reflect_slice.go @@ -8,14 +8,14 @@ import ( "github.com/v2pro/plz/reflect2" ) -func decoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { - decoder := decoderOfType(cfg, prefix+"[slice]->", typ.Elem()) +func decoderOfSlice(ctx *ctx, typ reflect.Type) ValDecoder { + decoder := decoderOfType(ctx.append("[sliceElem]"), typ.Elem()) sliceType := reflect2.Type2(typ).(*reflect2.UnsafeSliceType) return &sliceDecoder{sliceType, decoder} } -func encoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { - encoder := encoderOfType(cfg, prefix+"[slice]->", typ.Elem()) +func encoderOfSlice(ctx *ctx, typ reflect.Type) ValEncoder { + encoder := encoderOfType(ctx.append("[sliceElem]"), typ.Elem()) sliceType := reflect2.Type2(typ).(*reflect2.UnsafeSliceType) return &sliceEncoder{sliceType, encoder} } diff --git a/reflect_struct_decoder.go b/reflect_struct_decoder.go index 5ba650d..71d0700 100644 --- a/reflect_struct_decoder.go +++ b/reflect_struct_decoder.go @@ -8,9 +8,9 @@ import ( "unsafe" ) -func decoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { +func decoderOfStruct(ctx *ctx, typ reflect.Type) ValDecoder { bindings := map[string]*Binding{} - structDescriptor := describeStruct(cfg, prefix, typ) + structDescriptor := describeStruct(ctx, typ) for _, binding := range structDescriptor.Fields { for _, fromName := range binding.FromNames { old := bindings[fromName] @@ -18,7 +18,7 @@ func decoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValDeco bindings[fromName] = binding continue } - ignoreOld, ignoreNew := resolveConflictBinding(cfg, old, binding) + ignoreOld, ignoreNew := resolveConflictBinding(ctx.frozenConfig, old, binding) if ignoreOld { delete(bindings, fromName) } @@ -31,11 +31,11 @@ func decoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValDeco for k, binding := range bindings { fields[k] = binding.Decoder.(*structFieldDecoder) } - return createStructDecoder(cfg, typ, fields) + return createStructDecoder(ctx, typ, fields) } -func createStructDecoder(cfg *frozenConfig, typ reflect.Type, fields map[string]*structFieldDecoder) ValDecoder { - if cfg.disallowUnknownFields { +func createStructDecoder(ctx *ctx, typ reflect.Type, fields map[string]*structFieldDecoder) ValDecoder { + if ctx.disallowUnknownFields { return &generalStructDecoder{typ: typ, fields: fields, disallowUnknownFields: true} } knownHash := map[int64]struct{}{ diff --git a/reflect_struct_encoder.go b/reflect_struct_encoder.go index b856441..cfb7628 100644 --- a/reflect_struct_encoder.go +++ b/reflect_struct_encoder.go @@ -8,14 +8,14 @@ import ( "github.com/v2pro/plz/reflect2" ) -func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { +func encoderOfStruct(ctx *ctx, typ reflect.Type) ValEncoder { type bindingTo struct { binding *Binding toName string ignored bool } orderedBindings := []*bindingTo{} - structDescriptor := describeStruct(cfg, prefix, typ) + structDescriptor := describeStruct(ctx, typ) for _, binding := range structDescriptor.Fields { for _, toName := range binding.ToNames { new := &bindingTo{ @@ -26,7 +26,7 @@ func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEnco if old.toName != toName { continue } - old.ignored, new.ignored = resolveConflictBinding(cfg, old.binding, new.binding) + old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding) } orderedBindings = append(orderedBindings, new) } @@ -46,7 +46,7 @@ func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEnco return &structEncoder{typ, finalOrderedFields} } -func createCheckIsEmpty(cfg *frozenConfig, typ reflect.Type) checkIsEmpty { +func createCheckIsEmpty(ctx *ctx, typ reflect.Type) checkIsEmpty { kind := typ.Kind() switch kind { case reflect.String: @@ -88,7 +88,7 @@ func createCheckIsEmpty(cfg *frozenConfig, typ reflect.Type) checkIsEmpty { case reflect.Slice: return &sliceEncoder{} case reflect.Map: - return encoderOfMap(cfg, "", typ) + return encoderOfMap(ctx, typ) case reflect.Ptr: return &OptionalEncoder{} default: diff --git a/value_tests/struct_test.go b/value_tests/struct_test.go index 0f0cc03..1a01260 100644 --- a/value_tests/struct_test.go +++ b/value_tests/struct_test.go @@ -120,8 +120,7 @@ func init() { Field1 string `json:"field-1,omitempty"` Field2 func() `json:"-"` }{}, - // TODO: fix me - //structRecursive{}, + structRecursive{}, struct { *CacheItem