diff --git a/adapter.go b/adapter.go index 92d2cc4a..ba960ae8 100644 --- a/adapter.go +++ b/adapter.go @@ -100,7 +100,7 @@ func (adapter *Decoder) Buffered() io.Reader { func (adapter *Decoder) UseNumber() { cfg := adapter.iter.cfg.configBeforeFrozen cfg.UseNumber = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) + adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg) } // DisallowUnknownFields causes the Decoder to return an error when the destination @@ -109,7 +109,7 @@ func (adapter *Decoder) UseNumber() { func (adapter *Decoder) DisallowUnknownFields() { cfg := adapter.iter.cfg.configBeforeFrozen cfg.DisallowUnknownFields = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) + adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg) } // NewEncoder same as json.NewEncoder @@ -134,14 +134,14 @@ func (adapter *Encoder) Encode(val interface{}) error { func (adapter *Encoder) SetIndent(prefix, indent string) { config := adapter.stream.cfg.configBeforeFrozen config.IndentionStep = len(indent) - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) + adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg) } // SetEscapeHTML escape html by default, set to false to disable func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { config := adapter.stream.cfg.configBeforeFrozen config.EscapeHTML = escapeHTML - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) + adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg) } // Valid reports whether data is a valid JSON encoding. diff --git a/config.go b/config.go index 2adcdc3b..5d24da62 100644 --- a/config.go +++ b/config.go @@ -113,16 +113,21 @@ func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { var cfgCache = concurrent.NewMap() -func getFrozenConfigFromCache(cfg Config) *frozenConfig { - obj, found := cfgCache.Load(cfg) +type cfgKey struct { + Config + cause *frozenConfig +} + +func getFrozenConfigFromCache(key cfgKey) *frozenConfig { + obj, found := cfgCache.Load(key) if found { return obj.(*frozenConfig) } return nil } -func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { - cfgCache.Store(cfg, frozenConfig) +func addFrozenConfigToCache(key cfgKey, frozenConfig *frozenConfig) { + cfgCache.Store(key, frozenConfig) } // Froze forge API from config @@ -166,16 +171,17 @@ func (cfg Config) Froze() API { return api } -func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig { - api := getFrozenConfigFromCache(cfg) +func (cfg Config) frozeWithCacheReuse(cause *frozenConfig) *frozenConfig { + key := cfgKey{cfg, cause} + api := getFrozenConfigFromCache(key) if api != nil { return api } api = cfg.Froze().(*frozenConfig) - for _, extension := range extraExtensions { + for _, extension := range cause.extraExtensions { api.RegisterExtension(extension) } - addFrozenConfigToCache(cfg, api) + addFrozenConfigToCache(key, api) return api } @@ -317,7 +323,7 @@ func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([] } newCfg := cfg.configBeforeFrozen newCfg.IndentionStep = len(indent) - return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v) + return newCfg.frozeWithCacheReuse(cfg).Marshal(v) } func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { @@ -373,3 +379,7 @@ func (cfg *frozenConfig) Valid(data []byte) bool { iter.Skip() return iter.Error == nil } + +func (cfg *frozenConfig) GetConfig() Config { + return cfg.configBeforeFrozen +} diff --git a/extension_tests/extension_test.go b/extension_tests/extension_test.go index 836db5bc..26fd9b12 100644 --- a/extension_tests/extension_test.go +++ b/extension_tests/extension_test.go @@ -1,13 +1,14 @@ package test import ( - "github.com/json-iterator/go" - "github.com/modern-go/reflect2" - "github.com/stretchr/testify/require" "reflect" "strconv" "testing" "unsafe" + + jsoniter "github.com/json-iterator/go" + "github.com/modern-go/reflect2" + "github.com/stretchr/testify/require" ) type TestObject1 struct { @@ -59,6 +60,19 @@ func Test_customize_map_key_encoder(t *testing.T) { m = map[int]int{} should.NoError(cfg.UnmarshalFromString(output, &m)) should.Equal(map[int]int{1: 2}, m) + + b, err := cfg.MarshalIndent(m, "", " ") + should.NoError(err) + should.Equal(`{ + "2": 2 +}`, string(b)) + + cfg = jsoniter.Config{}.Froze() // without testMapKeyExtension + b, err = cfg.MarshalIndent(m, "", " ") + should.NoError(err) + should.Equal(`{ + "1": 2 +}`, string(b)) } type testMapKeyExtension struct { diff --git a/go.mod b/go.mod index 19e1ca94..81b0f762 100644 --- a/go.mod +++ b/go.mod @@ -8,4 +8,5 @@ require ( github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 github.com/modern-go/reflect2 v1.0.2 github.com/stretchr/testify v1.8.0 + github.com/valyala/bytebufferpool v1.0.0 ) diff --git a/go.sum b/go.sum index 85a994f1..5bcfbbc7 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/iter.go b/iter.go index 29b31cf7..c01720ec 100644 --- a/iter.go +++ b/iter.go @@ -122,6 +122,11 @@ func ParseString(cfg API, input string) *Iterator { return ParseBytes(cfg, []byte(input)) } +// API returns API +func (iter *Iterator) API() API { + return iter.cfg +} + // Pool returns a pool can provide more iterator with same configuration func (iter *Iterator) Pool() IteratorPool { return iter.cfg @@ -249,6 +254,15 @@ func (iter *Iterator) readByte() (ret byte) { return ret } +func (iter *Iterator) NextToken() (ret byte) { + return iter.nextToken() +} + +func (iter *Iterator) UnreadByte() error { + iter.unreadByte() + return nil +} + func (iter *Iterator) loadMore() bool { if iter.reader == nil { if iter.Error == nil { diff --git a/iter_str.go b/iter_str.go index adc487ea..811db851 100644 --- a/iter_str.go +++ b/iter_str.go @@ -3,6 +3,8 @@ package jsoniter import ( "fmt" "unicode/utf16" + + "github.com/valyala/bytebufferpool" ) // ReadString read string from iterator @@ -32,19 +34,24 @@ func (iter *Iterator) ReadString() (ret string) { return } +var byteBufPool = bytebufferpool.Pool{} + func (iter *Iterator) readStringSlowPath() (ret string) { - var str []byte + // reduce runtime.growslice + b := byteBufPool.Get() + defer byteBufPool.Put(b) + var c byte for iter.Error == nil { c = iter.readByte() if c == '"' { - return string(str) + return string(b.B) } if c == '\\' { c = iter.readByte() - str = iter.readEscapedChar(c, str) + b.B = iter.readEscapedChar(c, b.B) } else { - str = append(str, c) + b.WriteByte(c) } } iter.ReportError("readStringSlowPath", "unexpected end of input") diff --git a/reflect_array.go b/reflect_array.go index 13a0b7b0..bc982ccd 100644 --- a/reflect_array.go +++ b/reflect_array.go @@ -2,9 +2,10 @@ package jsoniter import ( "fmt" - "github.com/modern-go/reflect2" "io" "unsafe" + + "github.com/modern-go/reflect2" ) func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { @@ -13,13 +14,43 @@ func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { return &arrayDecoder{arrayType, decoder} } +type ArrayEncoderConstructor struct { + ArrayType *reflect2.UnsafeArrayType + ElemEncoder ValEncoder + API API + DecorateFunc func(arrayEncoder ValEncoder) ValEncoder +} + +func updateArrayEncoderConstructor(v *ArrayEncoderConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateArrayEncoderConstructor(v *ArrayEncoderConstructor) + }); ok { + e.UpdateArrayEncoderConstructor(v) + } + } +} + func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder { arrayType := typ.(*reflect2.UnsafeArrayType) if arrayType.Len() == 0 { return emptyArrayEncoder{} } - encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) - return &arrayEncoder{arrayType, encoder} + elemEncoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) + + c := &ArrayEncoderConstructor{ + ArrayType: arrayType, + ElemEncoder: elemEncoder, + API: ctx, + DecorateFunc: func(arrayEncoder ValEncoder) ValEncoder { + return arrayEncoder + }, + } + updateArrayEncoderConstructor(c, extensions...) + updateArrayEncoderConstructor(c, ctx.encoderExtension) + updateArrayEncoderConstructor(c, ctx.extraExtensions...) + enc := &arrayEncoder{arrayType, c.ElemEncoder} + return c.DecorateFunc(enc) } type emptyArrayEncoder struct{} diff --git a/reflect_extension.go b/reflect_extension.go index 74a97bfe..9cc9905e 100644 --- a/reflect_extension.go +++ b/reflect_extension.go @@ -2,12 +2,13 @@ package jsoniter import ( "fmt" - "github.com/modern-go/reflect2" "reflect" "sort" "strings" "unicode" "unsafe" + + "github.com/modern-go/reflect2" ) var typeDecoders = map[string]ValDecoder{} @@ -35,7 +36,7 @@ func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding { // Binding describe how should we encode/decode the struct field type Binding struct { - levels []int + Levels []int Field reflect2.StructField FromNames []string ToNames []string @@ -349,10 +350,10 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { if field.Type().Kind() == reflect.Struct { structDescriptor := describeStruct(ctx, field.Type()) for _, binding := range structDescriptor.Fields { - binding.levels = append([]int{i}, binding.levels...) - omitempty := binding.Encoder.(*structFieldEncoder).omitempty - binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} - binding.Decoder = &structFieldDecoder{field, binding.Decoder} + binding.Levels = append([]int{i}, binding.Levels...) + omitempty := binding.Encoder.(*StructFieldEncoder).OmitEmpty + binding.Encoder = &StructFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &StructFieldDecoder{field, binding.Decoder} embeddedBindings = append(embeddedBindings, binding) } continue @@ -361,12 +362,12 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { if ptrType.Elem().Kind() == reflect.Struct { structDescriptor := describeStruct(ctx, ptrType.Elem()) for _, binding := range structDescriptor.Fields { - binding.levels = append([]int{i}, binding.levels...) - omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Levels = append([]int{i}, binding.Levels...) + omitempty := binding.Encoder.(*StructFieldEncoder).OmitEmpty binding.Encoder = &dereferenceEncoder{binding.Encoder} - binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Encoder = &StructFieldEncoder{field, binding.Encoder, omitempty} binding.Decoder = &dereferenceDecoder{ptrType.Elem(), binding.Decoder} - binding.Decoder = &structFieldDecoder{field, binding.Decoder} + binding.Decoder = &StructFieldDecoder{field, binding.Decoder} embeddedBindings = append(embeddedBindings, binding) } continue @@ -390,15 +391,54 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { Decoder: decoder, Encoder: encoder, } - binding.levels = []int{i} + binding.Levels = []int{i} bindings = append(bindings, binding) } return createStructDescriptor(ctx, typ, bindings, embeddedBindings) } + +type StructDescriptorConstructor struct { + Type reflect2.Type + Bindings []*Binding + EmbeddedBindings []*Binding + API API + DescribeStructFunc func(typ reflect2.Type) *StructDescriptor +} + +func updateStructDescriptorConstructor(v *StructDescriptorConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateStructDescriptorConstructor(v *StructDescriptorConstructor) + }); ok { + e.UpdateStructDescriptorConstructor(v) + } + } +} + +func createStructDescriptorConstructor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptorConstructor { + v := &StructDescriptorConstructor{ + Type: typ, + Bindings: bindings, + EmbeddedBindings: embeddedBindings, + + API: ctx, + DescribeStructFunc: func(typ reflect2.Type) *StructDescriptor { + return describeStruct(ctx, typ) + }, + } + updateStructDescriptorConstructor(v, extensions...) + updateStructDescriptorConstructor(v, ctx.encoderExtension) + updateStructDescriptorConstructor(v, ctx.decoderExtension) + updateStructDescriptorConstructor(v, ctx.extraExtensions...) + return v +} + func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { + constructor := createStructDescriptorConstructor(ctx, typ, bindings, embeddedBindings) + structDescriptor := &StructDescriptor{ - Type: typ, - Fields: bindings, + Type: constructor.Type, + Fields: constructor.Bindings, } for _, extension := range extensions { extension.UpdateStructDescriptor(structDescriptor) @@ -410,7 +450,7 @@ func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, em } processTags(structDescriptor, ctx.frozenConfig) // merge normal & embedded bindings & sort with original order - allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) + allBindings := sortableBindings(append(constructor.EmbeddedBindings, structDescriptor.Fields...)) sort.Sort(allBindings) structDescriptor.Fields = allBindings return structDescriptor @@ -423,8 +463,8 @@ func (bindings sortableBindings) Len() int { } func (bindings sortableBindings) Less(i, j int) bool { - left := bindings[i].levels - right := bindings[j].levels + left := bindings[i].Levels + right := bindings[j].Levels k := 0 for { if left[k] < right[k] { @@ -453,12 +493,12 @@ func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) { binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg} } else { binding.Decoder = &stringModeNumberDecoder{binding.Decoder} - binding.Encoder = &stringModeNumberEncoder{binding.Encoder} + binding.Encoder = &stringModeNumberEncoder{binding.Encoder, cfg} } } } - binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} - binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} + binding.Decoder = &StructFieldDecoder{binding.Field, binding.Decoder} + binding.Encoder = &StructFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} } } diff --git a/reflect_map.go b/reflect_map.go index 4e479c8a..623ef28d 100644 --- a/reflect_map.go +++ b/reflect_map.go @@ -23,20 +23,57 @@ func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { } } +type MapEncoderConstructor struct { + MapType *reflect2.UnsafeMapType + KeyEncoder ValEncoder + ElemEncoder ValEncoder + API API + DecorateFunc func(mapEncoder ValEncoder) ValEncoder +} + +func updateMapEncoderConstructor(v *MapEncoderConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateMapEncoderConstructor(v *MapEncoderConstructor) + }); ok { + e.UpdateMapEncoderConstructor(v) + } + } +} + func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder { mapType := typ.(*reflect2.UnsafeMapType) + + keyEncoder := encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()) + elemEncoder := encoderOfType(ctx.append("[mapElem]"), mapType.Elem()) + c := &MapEncoderConstructor{ + MapType: mapType, + KeyEncoder: keyEncoder, + ElemEncoder: elemEncoder, + API: ctx, + DecorateFunc: func(mapEncoder ValEncoder) ValEncoder { + return mapEncoder + }, + } + updateMapEncoderConstructor(c, extensions...) + updateMapEncoderConstructor(c, ctx.encoderExtension) + updateMapEncoderConstructor(c, ctx.extraExtensions...) + + var enc ValEncoder if ctx.sortMapKeys { - return &sortKeysMapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), + enc = &SortKeysMapEncoder{ + MapType: c.MapType, + KeyEncoder: c.KeyEncoder, + ElemEncoder: c.ElemEncoder, + } + } else { + enc = &mapEncoder{ + mapType: c.MapType, + keyEncoder: c.KeyEncoder, + elemEncoder: c.ElemEncoder, } } - return &mapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), - } + return c.DecorateFunc(enc) } func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { @@ -279,19 +316,20 @@ func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { return !iter.HasNext() } -type sortKeysMapEncoder struct { - mapType *reflect2.UnsafeMapType - keyEncoder ValEncoder - elemEncoder ValEncoder +type SortKeysMapEncoder struct { + MapType *reflect2.UnsafeMapType + KeyEncoder ValEncoder + ElemEncoder ValEncoder + KeyLess func(ki, kj string) bool } -func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { +func (encoder *SortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { if *(*unsafe.Pointer)(ptr) == nil { stream.WriteNil() return } stream.WriteObjectStart() - mapIter := encoder.mapType.UnsafeIterate(ptr) + mapIter := encoder.MapType.UnsafeIterate(ptr) subStream := stream.cfg.BorrowStream(nil) subStream.Attachment = stream.Attachment subIter := stream.cfg.BorrowIterator(nil) @@ -299,7 +337,7 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { for mapIter.HasNext() { key, elem := mapIter.UnsafeNext() subStreamIndex := subStream.Buffered() - encoder.keyEncoder.Encode(key, subStream) + encoder.KeyEncoder.Encode(key, subStream) if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil { stream.Error = subStream.Error } @@ -311,13 +349,19 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { } else { subStream.writeByte(':') } - encoder.elemEncoder.Encode(elem, subStream) + encoder.ElemEncoder.Encode(elem, subStream) keyValues = append(keyValues, encodedKV{ key: decodedKey, keyValue: subStream.Buffer()[subStreamIndex:], }) } - sort.Sort(keyValues) + if encoder.KeyLess == nil { + sort.Sort(keyValues) + } else { + sort.Slice(keyValues, func(i, j int) bool { + return encoder.KeyLess(keyValues[i].key, keyValues[j].key) + }) + } for i, keyValue := range keyValues { if i != 0 { stream.WriteMore() @@ -332,8 +376,8 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { stream.cfg.ReturnIterator(subIter) } -func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { - iter := encoder.mapType.UnsafeIterate(ptr) +func (encoder *SortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + iter := encoder.MapType.UnsafeIterate(ptr) return !iter.HasNext() } diff --git a/reflect_slice.go b/reflect_slice.go index 9441d79d..aa290bcf 100644 --- a/reflect_slice.go +++ b/reflect_slice.go @@ -2,9 +2,10 @@ package jsoniter import ( "fmt" - "github.com/modern-go/reflect2" "io" "unsafe" + + "github.com/modern-go/reflect2" ) func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { @@ -13,10 +14,39 @@ func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { return &sliceDecoder{sliceType, decoder} } +type SliceEncoderConstructor struct { + SliceType *reflect2.UnsafeSliceType + ElemEncoder ValEncoder + API API + DecorateFunc func(sliceEncoder ValEncoder) ValEncoder +} + +func updateSliceEncoderConstructor(v *SliceEncoderConstructor, exts ...Extension) { + for _, ext := range exts { + if e, ok := ext.(interface { + UpdateSliceEncoderConstructor(v *SliceEncoderConstructor) + }); ok { + e.UpdateSliceEncoderConstructor(v) + } + } +} + func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder { sliceType := typ.(*reflect2.UnsafeSliceType) - encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) - return &sliceEncoder{sliceType, encoder} + elemEncoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) + c := &SliceEncoderConstructor{ + SliceType: sliceType, + ElemEncoder: elemEncoder, + API: ctx, + DecorateFunc: func(sliceEncoder ValEncoder) ValEncoder { + return sliceEncoder + }, + } + updateSliceEncoderConstructor(c, extensions...) + updateSliceEncoderConstructor(c, ctx.encoderExtension) + updateSliceEncoderConstructor(c, ctx.extraExtensions...) + enc := &sliceEncoder{sliceType, c.ElemEncoder} + return c.DecorateFunc(enc) } type sliceEncoder struct { diff --git a/reflect_struct_decoder.go b/reflect_struct_decoder.go index 92ae912d..5ee0850d 100644 --- a/reflect_struct_decoder.go +++ b/reflect_struct_decoder.go @@ -28,15 +28,15 @@ func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder { } } } - fields := map[string]*structFieldDecoder{} + fields := map[string]*StructFieldDecoder{} for k, binding := range bindings { - fields[k] = binding.Decoder.(*structFieldDecoder) + fields[k] = binding.Decoder.(*StructFieldDecoder) } if !ctx.caseSensitive() { for k, binding := range bindings { if _, found := fields[strings.ToLower(k)]; !found { - fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder) + fields[strings.ToLower(k)] = binding.Decoder.(*StructFieldDecoder) } } } @@ -44,7 +44,7 @@ func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder { return createStructDecoder(ctx, typ, fields) } -func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structFieldDecoder) ValDecoder { +func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*StructFieldDecoder) ValDecoder { if ctx.disallowUnknownFields { return &generalStructDecoder{typ: typ, fields: fields, disallowUnknownFields: true} } @@ -68,8 +68,8 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF case 2: var fieldHash1 int64 var fieldHash2 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -90,9 +90,9 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName1 int64 var fieldName2 int64 var fieldName3 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -120,10 +120,10 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName2 int64 var fieldName3 int64 var fieldName4 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder + var fieldDecoder4 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -156,11 +156,11 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName3 int64 var fieldName4 int64 var fieldName5 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder + var fieldDecoder4 *StructFieldDecoder + var fieldDecoder5 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -198,12 +198,12 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName4 int64 var fieldName5 int64 var fieldName6 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder + var fieldDecoder4 *StructFieldDecoder + var fieldDecoder5 *StructFieldDecoder + var fieldDecoder6 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -246,13 +246,13 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName5 int64 var fieldName6 int64 var fieldName7 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder + var fieldDecoder4 *StructFieldDecoder + var fieldDecoder5 *StructFieldDecoder + var fieldDecoder6 *StructFieldDecoder + var fieldDecoder7 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -300,14 +300,14 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName6 int64 var fieldName7 int64 var fieldName8 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder + var fieldDecoder4 *StructFieldDecoder + var fieldDecoder5 *StructFieldDecoder + var fieldDecoder6 *StructFieldDecoder + var fieldDecoder7 *StructFieldDecoder + var fieldDecoder8 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -360,15 +360,15 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName7 int64 var fieldName8 int64 var fieldName9 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - var fieldDecoder9 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder + var fieldDecoder4 *StructFieldDecoder + var fieldDecoder5 *StructFieldDecoder + var fieldDecoder6 *StructFieldDecoder + var fieldDecoder7 *StructFieldDecoder + var fieldDecoder8 *StructFieldDecoder + var fieldDecoder9 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -426,16 +426,16 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF var fieldName8 int64 var fieldName9 int64 var fieldName10 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - var fieldDecoder9 *structFieldDecoder - var fieldDecoder10 *structFieldDecoder + var fieldDecoder1 *StructFieldDecoder + var fieldDecoder2 *StructFieldDecoder + var fieldDecoder3 *StructFieldDecoder + var fieldDecoder4 *StructFieldDecoder + var fieldDecoder5 *StructFieldDecoder + var fieldDecoder6 *StructFieldDecoder + var fieldDecoder7 *StructFieldDecoder + var fieldDecoder8 *StructFieldDecoder + var fieldDecoder9 *StructFieldDecoder + var fieldDecoder10 *StructFieldDecoder for fieldName, fieldDecoder := range fields { fieldHash := calcHash(fieldName, ctx.caseSensitive()) _, known := knownHash[fieldHash] @@ -492,7 +492,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF type generalStructDecoder struct { typ reflect2.Type - fields map[string]*structFieldDecoder + fields map[string]*StructFieldDecoder disallowUnknownFields bool } @@ -518,7 +518,7 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) { var field string - var fieldDecoder *structFieldDecoder + var fieldDecoder *StructFieldDecoder if iter.cfg.objectFieldMustBeSimpleString { fieldBytes := iter.ReadStringAsSlice() field = *(*string)(unsafe.Pointer(&fieldBytes)) @@ -568,7 +568,7 @@ func (decoder *skipObjectDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { type oneFieldStructDecoder struct { typ reflect2.Type fieldHash int64 - fieldDecoder *structFieldDecoder + fieldDecoder *StructFieldDecoder } func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -597,9 +597,9 @@ func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) type twoFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder } func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -631,11 +631,11 @@ func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator type threeFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder } func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -669,13 +669,13 @@ func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat type fourFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder fieldHash4 int64 - fieldDecoder4 *structFieldDecoder + fieldDecoder4 *StructFieldDecoder } func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -711,15 +711,15 @@ func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato type fiveFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder fieldHash4 int64 - fieldDecoder4 *structFieldDecoder + fieldDecoder4 *StructFieldDecoder fieldHash5 int64 - fieldDecoder5 *structFieldDecoder + fieldDecoder5 *StructFieldDecoder } func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -757,17 +757,17 @@ func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato type sixFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder fieldHash4 int64 - fieldDecoder4 *structFieldDecoder + fieldDecoder4 *StructFieldDecoder fieldHash5 int64 - fieldDecoder5 *structFieldDecoder + fieldDecoder5 *StructFieldDecoder fieldHash6 int64 - fieldDecoder6 *structFieldDecoder + fieldDecoder6 *StructFieldDecoder } func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -807,19 +807,19 @@ func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator type sevenFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder fieldHash4 int64 - fieldDecoder4 *structFieldDecoder + fieldDecoder4 *StructFieldDecoder fieldHash5 int64 - fieldDecoder5 *structFieldDecoder + fieldDecoder5 *StructFieldDecoder fieldHash6 int64 - fieldDecoder6 *structFieldDecoder + fieldDecoder6 *StructFieldDecoder fieldHash7 int64 - fieldDecoder7 *structFieldDecoder + fieldDecoder7 *StructFieldDecoder } func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -861,21 +861,21 @@ func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat type eightFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder fieldHash4 int64 - fieldDecoder4 *structFieldDecoder + fieldDecoder4 *StructFieldDecoder fieldHash5 int64 - fieldDecoder5 *structFieldDecoder + fieldDecoder5 *StructFieldDecoder fieldHash6 int64 - fieldDecoder6 *structFieldDecoder + fieldDecoder6 *StructFieldDecoder fieldHash7 int64 - fieldDecoder7 *structFieldDecoder + fieldDecoder7 *StructFieldDecoder fieldHash8 int64 - fieldDecoder8 *structFieldDecoder + fieldDecoder8 *StructFieldDecoder } func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -919,23 +919,23 @@ func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat type nineFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder fieldHash4 int64 - fieldDecoder4 *structFieldDecoder + fieldDecoder4 *StructFieldDecoder fieldHash5 int64 - fieldDecoder5 *structFieldDecoder + fieldDecoder5 *StructFieldDecoder fieldHash6 int64 - fieldDecoder6 *structFieldDecoder + fieldDecoder6 *StructFieldDecoder fieldHash7 int64 - fieldDecoder7 *structFieldDecoder + fieldDecoder7 *StructFieldDecoder fieldHash8 int64 - fieldDecoder8 *structFieldDecoder + fieldDecoder8 *StructFieldDecoder fieldHash9 int64 - fieldDecoder9 *structFieldDecoder + fieldDecoder9 *StructFieldDecoder } func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -981,25 +981,25 @@ func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato type tenFieldsStructDecoder struct { typ reflect2.Type fieldHash1 int64 - fieldDecoder1 *structFieldDecoder + fieldDecoder1 *StructFieldDecoder fieldHash2 int64 - fieldDecoder2 *structFieldDecoder + fieldDecoder2 *StructFieldDecoder fieldHash3 int64 - fieldDecoder3 *structFieldDecoder + fieldDecoder3 *StructFieldDecoder fieldHash4 int64 - fieldDecoder4 *structFieldDecoder + fieldDecoder4 *StructFieldDecoder fieldHash5 int64 - fieldDecoder5 *structFieldDecoder + fieldDecoder5 *StructFieldDecoder fieldHash6 int64 - fieldDecoder6 *structFieldDecoder + fieldDecoder6 *StructFieldDecoder fieldHash7 int64 - fieldDecoder7 *structFieldDecoder + fieldDecoder7 *StructFieldDecoder fieldHash8 int64 - fieldDecoder8 *structFieldDecoder + fieldDecoder8 *StructFieldDecoder fieldHash9 int64 - fieldDecoder9 *structFieldDecoder + fieldDecoder9 *StructFieldDecoder fieldHash10 int64 - fieldDecoder10 *structFieldDecoder + fieldDecoder10 *StructFieldDecoder } func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -1044,16 +1044,16 @@ func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator iter.decrementDepth() } -type structFieldDecoder struct { - field reflect2.StructField - fieldDecoder ValDecoder +type StructFieldDecoder struct { + Field reflect2.StructField + FieldDecoder ValDecoder } -func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - fieldPtr := decoder.field.UnsafeGet(ptr) - decoder.fieldDecoder.Decode(fieldPtr, iter) +func (decoder *StructFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + fieldPtr := decoder.Field.UnsafeGet(ptr) + decoder.FieldDecoder.Decode(fieldPtr, iter) if iter.Error != nil && iter.Error != io.EOF { - iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error()) + iter.Error = fmt.Errorf("%s: %s", decoder.Field.Name(), iter.Error.Error()) } } diff --git a/reflect_struct_encoder.go b/reflect_struct_encoder.go index 152e3ef5..0bfcc1a2 100644 --- a/reflect_struct_encoder.go +++ b/reflect_struct_encoder.go @@ -2,10 +2,11 @@ package jsoniter import ( "fmt" - "github.com/modern-go/reflect2" "io" "reflect" "unsafe" + + "github.com/modern-go/reflect2" ) func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { @@ -38,7 +39,7 @@ func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { for _, bindingTo := range orderedBindings { if !bindingTo.ignored { finalOrderedFields = append(finalOrderedFields, structFieldTo{ - encoder: bindingTo.binding.Encoder.(*structFieldEncoder), + encoder: bindingTo.binding.Encoder.(*StructFieldEncoder), toName: bindingTo.toName, }) } @@ -75,9 +76,9 @@ func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ig oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != "" if newTagged { if oldTagged { - if len(old.levels) > len(new.levels) { + if len(old.Levels) > len(new.Levels) { return true, false - } else if len(new.levels) > len(old.levels) { + } else if len(new.Levels) > len(old.Levels) { return false, true } else { return true, true @@ -89,9 +90,9 @@ func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ig if oldTagged { return true, false } - if len(old.levels) > len(new.levels) { + if len(old.Levels) > len(new.Levels) { return true, false - } else if len(new.levels) > len(old.levels) { + } else if len(new.Levels) > len(old.Levels) { return false, true } else { return true, true @@ -99,31 +100,31 @@ func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ig } } -type structFieldEncoder struct { - field reflect2.StructField - fieldEncoder ValEncoder - omitempty bool +type StructFieldEncoder struct { + Field reflect2.StructField + FieldEncoder ValEncoder + OmitEmpty bool } -func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - fieldPtr := encoder.field.UnsafeGet(ptr) - encoder.fieldEncoder.Encode(fieldPtr, stream) +func (encoder *StructFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + fieldPtr := encoder.Field.UnsafeGet(ptr) + encoder.FieldEncoder.Encode(fieldPtr, stream) if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error()) + stream.Error = fmt.Errorf("%s: %s", encoder.Field.Name(), stream.Error.Error()) } } -func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { - fieldPtr := encoder.field.UnsafeGet(ptr) - return encoder.fieldEncoder.IsEmpty(fieldPtr) +func (encoder *StructFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { + fieldPtr := encoder.Field.UnsafeGet(ptr) + return encoder.FieldEncoder.IsEmpty(fieldPtr) } -func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { - isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil) +func (encoder *StructFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + isEmbeddedPtrNil, converted := encoder.FieldEncoder.(IsEmbeddedPtrNil) if !converted { return false } - fieldPtr := encoder.field.UnsafeGet(ptr) + fieldPtr := encoder.Field.UnsafeGet(ptr) return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) } @@ -137,7 +138,7 @@ type structEncoder struct { } type structFieldTo struct { - encoder *structFieldEncoder + encoder *StructFieldEncoder toName string } @@ -145,7 +146,7 @@ func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteObjectStart() isNotFirst := false for _, field := range encoder.fields { - if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { + if field.encoder.OmitEmpty && field.encoder.IsEmpty(ptr) { continue } if field.encoder.IsEmbeddedPtrNil(ptr) { @@ -181,12 +182,22 @@ func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { type stringModeNumberEncoder struct { elemEncoder ValEncoder + cfg *frozenConfig } func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.writeByte('"') - encoder.elemEncoder.Encode(ptr, stream) - stream.writeByte('"') + tempStream := encoder.cfg.BorrowStream(nil) + tempStream.Attachment = stream.Attachment + defer encoder.cfg.ReturnStream(tempStream) + encoder.elemEncoder.Encode(ptr, tempStream) + buf := tempStream.Buffer() + if len(buf) >= 2 && buf[0] == '"' && buf[len(buf)-1] == '"' { + stream.Write(buf) + } else { + stream.writeByte('"') + stream.Write(buf) + stream.writeByte('"') + } } func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool { diff --git a/stream.go b/stream.go index 23d8a3ad..4359ee76 100644 --- a/stream.go +++ b/stream.go @@ -29,6 +29,11 @@ func NewStream(cfg API, out io.Writer, bufSize int) *Stream { } } +// API returns API +func (stream *Stream) API() API { + return stream.cfg +} + // Pool returns a pool can provide more stream with same configuration func (stream *Stream) Pool() StreamPool { return stream.cfg