diff --git a/config.go b/config.go index b712c836..bd66947d 100644 --- a/config.go +++ b/config.go @@ -2,12 +2,12 @@ package jsoniter import ( "encoding/json" + "github.com/modern-go/concurrent" "github.com/modern-go/reflect2" "io" + "reflect" "sync" "unsafe" - "github.com/modern-go/concurrent" - "reflect" ) // Config customize how the API should behave. @@ -63,7 +63,6 @@ var ConfigFastest = Config{ ObjectFieldMustBeSimpleString: true, // do not unescape object field }.Froze() - type frozenConfig struct { configBeforeFrozen Config sortMapKeys bool diff --git a/extension_tests/extension_test.go b/extension_tests/extension_test.go index 043379ea..836db5bc 100644 --- a/extension_tests/extension_test.go +++ b/extension_tests/extension_test.go @@ -2,8 +2,8 @@ package test import ( "github.com/json-iterator/go" - "github.com/stretchr/testify/require" "github.com/modern-go/reflect2" + "github.com/stretchr/testify/require" "reflect" "strconv" "testing" diff --git a/extra/binary_as_string_codec.go b/extra/binary_as_string_codec.go index f9d8b750..543895be 100644 --- a/extra/binary_as_string_codec.go +++ b/extra/binary_as_string_codec.go @@ -2,9 +2,9 @@ package extra import ( "github.com/json-iterator/go" - "unsafe" - "unicode/utf8" "github.com/modern-go/reflect2" + "unicode/utf8" + "unsafe" ) // safeSet holds the value true if the ASCII character with the given array @@ -171,18 +171,18 @@ func (codec *binaryAsStringCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.St func readHex(iter *jsoniter.Iterator, b1, b2 byte) byte { var ret byte if b1 >= '0' && b1 <= '9' { - ret = b1-'0' + ret = b1 - '0' } else if b1 >= 'a' && b1 <= 'f' { - ret = b1-'a'+10 + ret = b1 - 'a' + 10 } else { iter.ReportError("read hex", "expects 0~9 or a~f, but found "+string([]byte{b1})) return 0 } ret = ret * 16 if b2 >= '0' && b2 <= '9' { - ret = b2-'0' + ret = b2 - '0' } else if b2 >= 'a' && b2 <= 'f' { - ret = b2-'a'+10 + ret = b2 - 'a' + 10 } else { iter.ReportError("read hex", "expects 0~9 or a~f, but found "+string([]byte{b2})) return 0 diff --git a/extra/binary_as_string_codec_test.go b/extra/binary_as_string_codec_test.go index d6771681..a00479e6 100644 --- a/extra/binary_as_string_codec_test.go +++ b/extra/binary_as_string_codec_test.go @@ -1,9 +1,9 @@ package extra import ( - "testing" - "github.com/stretchr/testify/require" "github.com/json-iterator/go" + "github.com/stretchr/testify/require" + "testing" ) func init() { diff --git a/misc_tests/jsoniter_map_test.go b/misc_tests/jsoniter_map_test.go index 3f594b29..b0dde94c 100644 --- a/misc_tests/jsoniter_map_test.go +++ b/misc_tests/jsoniter_map_test.go @@ -31,3 +31,14 @@ func Test_read_map_with_reader(t *testing.T) { should.Equal(m2, m1) should.Equal("1.0.76", m1["note"].(map[string]interface{})["CoreServices"].(map[string]interface{})["version_name"]) } + +func Test_map_eface_of_eface(t *testing.T) { + should := require.New(t) + json := jsoniter.ConfigCompatibleWithStandardLibrary + output, err := json.MarshalToString(map[interface{}]interface{}{ + "1": 2, + 3: "4", + }) + should.NoError(err) + should.Equal(`{"1":2,"3":"4"}`, output) +} diff --git a/reflect_map.go b/reflect_map.go index f34d519f..8812f085 100644 --- a/reflect_map.go +++ b/reflect_map.go @@ -3,6 +3,7 @@ package jsoniter import ( "fmt" "github.com/modern-go/reflect2" + "io" "reflect" "sort" "unsafe" @@ -107,6 +108,9 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), } } + if typ.Kind() == reflect.Interface { + return &dynamicMapKeyEncoder{ctx, typ} + } return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} } } @@ -203,6 +207,21 @@ func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { return false } +type dynamicMapKeyEncoder struct { + ctx *ctx + valType reflect2.Type +} + +func (encoder *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream) +} + +func (encoder *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + obj := encoder.valType.UnsafeIndirect(ptr) + return encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj)) +} + type mapEncoder struct { mapType *reflect2.UnsafeMapType keyEncoder ValEncoder @@ -253,6 +272,9 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { subStream.buf = make([]byte, 0, 64) key, elem := mapIter.UnsafeNext() encoder.keyEncoder.Encode(key, subStream) + if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil { + stream.Error = subStream.Error + } encodedKey := subStream.Buffer() subIter.ResetBytes(encodedKey) decodedKey := subIter.ReadString() diff --git a/value_tests/slice_test.go b/value_tests/slice_test.go index 3e4c3484..f504e851 100644 --- a/value_tests/slice_test.go +++ b/value_tests/slice_test.go @@ -6,7 +6,7 @@ func init() { []interface{}{"hello"}, nilSlice, &nilSlice, - selectedMarshalCase{[]byte{1,2,3}}, + []byte{1, 2, 3}, ) unmarshalCases = append(unmarshalCases, unmarshalCase{ ptr: (*[]string)(nil), @@ -20,6 +20,5 @@ func init() { }, unmarshalCase{ ptr: (*[]byte)(nil), input: `"aGVsbG8="`, - selected: true, }) } diff --git a/value_tests/value_test.go b/value_tests/value_test.go index ec1bed77..95cfdd56 100644 --- a/value_tests/value_test.go +++ b/value_tests/value_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" "github.com/json-iterator/go" - "github.com/stretchr/testify/require" "github.com/modern-go/reflect2" + "github.com/stretchr/testify/require" "testing" )