1
0
mirror of https://github.com/json-iterator/go.git synced 2025-06-24 23:16:47 +02:00

Merge pull request #173 from toffaletti/more-nil-interface-fixes

More nil interface fixes
This commit is contained in:
Tao Wen
2017-09-16 18:36:43 -05:00
committed by GitHub
4 changed files with 92 additions and 16 deletions

View File

@ -391,15 +391,20 @@ func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator)
e.typ = nonEmptyInterface.itab.typ e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word e.word = nonEmptyInterface.word
iter.ReadVal(&i) iter.ReadVal(&i)
if e.word == nil {
nonEmptyInterface.itab = nil
}
nonEmptyInterface.word = e.word nonEmptyInterface.word = e.word
} }
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
nonEmptyInterface := (*nonEmptyInterface)(ptr) nonEmptyInterface := (*nonEmptyInterface)(ptr)
var i interface{} var i interface{}
if nonEmptyInterface.itab != nil {
e := (*emptyInterface)(unsafe.Pointer(&i)) e := (*emptyInterface)(unsafe.Pointer(&i))
e.typ = nonEmptyInterface.itab.typ e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word e.word = nonEmptyInterface.word
}
stream.WriteVal(i) stream.WriteVal(i)
} }
@ -660,7 +665,11 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
templateInterface := encoder.templateInterface templateInterface := encoder.templateInterface
templateInterface.word = ptr templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(json.Marshaler) marshaler, ok := (*realInterface).(json.Marshaler)
if !ok {
stream.WriteVal(nil)
return
}
bytes, err := marshaler.MarshalJSON() bytes, err := marshaler.MarshalJSON()
if err != nil { if err != nil {

View File

@ -92,22 +92,22 @@ func Test_bool_can_be_null(t *testing.T) {
obj := TestData{} obj := TestData{}
data1 := []byte(`{"field": true}`) data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj) err := Unmarshal(data1, &obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, obj.Field) should.Equal(true, obj.Field)
data2 := []byte(`{"field": null}`) data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj) err = Unmarshal(data2, &obj)
should.Equal(nil, err) should.NoError(err)
// Same behavior as stdlib, not touching the existing value. // Same behavior as stdlib, not touching the existing value.
should.Equal(true, obj.Field) should.Equal(true, obj.Field)
// Checking stdlib behavior as well // Checking stdlib behavior as well
obj2 := TestData{} obj2 := TestData{}
err = json.Unmarshal(data1, &obj2) err = json.Unmarshal(data1, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, obj2.Field) should.Equal(true, obj2.Field)
err = json.Unmarshal(data2, &obj2) err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, obj2.Field) should.Equal(true, obj2.Field)
} }

View File

@ -40,11 +40,11 @@ func Test_custom_marshaler_on_enum(t *testing.T) {
w := Wrapper{Payload: MyEnumB} w := Wrapper{Payload: MyEnumB}
jb, err := Marshal(w) jb, err := Marshal(w)
should.Equal(nil, err) should.NoError(err)
should.Equal(`{"Payload":"foo-1"}`, string(jb)) should.Equal(`{"Payload":"foo-1"}`, string(jb))
var w2 Wrapper2 var w2 Wrapper2
err = Unmarshal(jb, &w2) err = Unmarshal(jb, &w2)
should.Equal(nil, err) should.NoError(err)
should.Equal(MyEnumB, w2.Payload) should.Equal(MyEnumB, w2.Payload)
} }

View File

@ -329,13 +329,13 @@ func Test_nil_out_null_interface(t *testing.T) {
data1 := []byte(`{"field": true}`) data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj) err := Unmarshal(data1, &obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, *(obj.Field.(*bool))) should.Equal(true, *(obj.Field.(*bool)))
data2 := []byte(`{"field": null}`) data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj) err = Unmarshal(data2, &obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(nil, obj.Field) should.Equal(nil, obj.Field)
// Checking stdlib behavior matches. // Checking stdlib behavior matches.
@ -344,11 +344,11 @@ func Test_nil_out_null_interface(t *testing.T) {
} }
err = json.Unmarshal(data1, &obj2) err = json.Unmarshal(data1, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, *(obj2.Field.(*bool))) should.Equal(true, *(obj2.Field.(*bool)))
err = json.Unmarshal(data2, &obj2) err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(nil, obj2.Field) should.Equal(nil, obj2.Field)
} }
@ -363,10 +363,77 @@ func Test_omitempty_nil_interface(t *testing.T) {
} }
js, err := json.Marshal(obj) js, err := json.Marshal(obj)
should.Equal(nil, err) should.NoError(err)
should.Equal("{}", string(js)) should.Equal("{}", string(js))
str, err := MarshalToString(obj) str, err := MarshalToString(obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(string(js), str) should.Equal(string(js), str)
} }
func Test_omitempty_nil_nonempty_interface(t *testing.T) {
type TestData struct {
Field MyInterface `json:"field,omitempty"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal("{}", string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
obj.Field = MyString("hello")
err = UnmarshalFromString(`{"field":null}`, &obj)
should.NoError(err)
should.Equal(nil, obj.Field)
}
func Test_marshal_nil_marshaler_interface(t *testing.T) {
type TestData struct {
Field json.Marshaler `json:"field"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal(`{"field":null}`, string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
}
func Test_marshal_nil_nonempty_interface(t *testing.T) {
type TestData struct {
Field MyInterface `json:"field"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal(`{"field":null}`, string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
obj.Field = MyString("hello")
err = Unmarshal(js, &obj)
should.NoError(err)
should.Equal(nil, obj.Field)
}