diff --git a/encoder/assembler_amd64_go116.go b/encoder/assembler_amd64_go116.go index 9b59784..d056259 100644 --- a/encoder/assembler_amd64_go116.go +++ b/encoder/assembler_amd64_go116.go @@ -514,7 +514,8 @@ func (self *_Assembler) call_marshaler(fn obj.Addr, it *rt.GoType, vt reflect.Ty switch vt.Kind() { case reflect.Interface : self.call_marshaler_i(fn, it) case reflect.Ptr, reflect.Map: self.call_marshaler_v(fn, it, vt, true) - default : self.call_marshaler_v(fn, it, vt, false) + // struct/array of 1 direct iface type can be direct + default : self.call_marshaler_v(fn, it, vt, !rt.UnpackType(vt).Indirect()) } } diff --git a/encoder/assembler_amd64_go117.go b/encoder/assembler_amd64_go117.go index 8cd83e8..1f1b280 100644 --- a/encoder/assembler_amd64_go117.go +++ b/encoder/assembler_amd64_go117.go @@ -539,7 +539,8 @@ func (self *_Assembler) call_marshaler(fn obj.Addr, it *rt.GoType, vt reflect.Ty switch vt.Kind() { case reflect.Interface : self.call_marshaler_i(fn, it) case reflect.Ptr, reflect.Map : self.call_marshaler_v(fn, it, vt, true) - default : self.call_marshaler_v(fn, it, vt, false) + // struct/array of 1 direct iface type can be direct + default : self.call_marshaler_v(fn, it, vt, !rt.UnpackType(vt).Indirect()) } } diff --git a/issue_test/issue390_test.go b/issue_test/issue390_test.go new file mode 100644 index 0000000..e4f0b25 --- /dev/null +++ b/issue_test/issue390_test.go @@ -0,0 +1,114 @@ +/* + * Copyright 2023 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package issue_test + +import ( + `testing` + `github.com/bytedance/sonic` + `encoding/json` + `github.com/stretchr/testify/require` +) + +type DirectStruct struct { + Ptr *int +} + +func (d DirectStruct) MarshalJSON() ([]byte, error) { + return json.Marshal((d.Ptr)) +} + +type DirectArray [1]*int + +func (d DirectArray) MarshalJSON() ([]byte, error) { + return json.Marshal(d[0]) +} + +type DirectNested [1]DirectStruct + +func (d DirectNested) MarshalJSON() ([]byte, error) { + return json.Marshal(d[0]) +} + + +type DirectStruct2 struct { + Ptr *int +} + +func (d DirectStruct2) MarshalText() ([]byte, error) { + return json.Marshal((d.Ptr)) +} + +type DirectArray2 [1]*int + +func (d DirectArray2) MarshalText() ([]byte, error) { + return json.Marshal(d[0]) +} + +type DirectNested2 [1]DirectStruct2 + +func (d DirectNested2) MarshalText() ([]byte, error) { + return json.Marshal(d[0]) +} + +func TestDirectStructType(t *testing.T) { + val := 123 + real := &val + realds := DirectStruct{real} + nullds := DirectStruct{} + realda := DirectArray{real} + nullda := DirectArray{} + nested := DirectNested{realds} + + realds2 := DirectStruct2{real} + nullds2 := DirectStruct2{} + realda2 := DirectArray2{real} + nullda2 := DirectArray2{} + nested2 := DirectNested2{realds2} + + tests := []interface{} { + // test direct iface type implemented encoding.JSONMarshaler + &realds, realds, &nullds, nullds, + map[string]DirectStruct{ "a": realds, "b": nullds}, + map[string]*DirectStruct{ "a": &realds, "b": &nullds}, + []DirectStruct{realds, nullds}, + []*DirectStruct{&realds, &nullds}, + &realda, realda, &nullda, nullda, + nested, &nested, + + // test direct iface implemented encoding.TextMarshaler + &realds2, realds2, &nullds2, nullds2, + map[string]DirectStruct2{ "a": realds2, "b": nullds2}, + map[string]*DirectStruct2{ "a": &realds2, "b": &nullds2}, + []DirectStruct2{realds2, nullds2}, + []*DirectStruct2{&realds2, &nullds2}, + &realda2, realda2, &nullda2, nullda2, + nested2, &nested2, + + // test map key implement encoding.TextMarshaler + map[DirectStruct2]DirectArray{ + realds2 : realda, + nullds2 : nullda, + }, + } + for _, tt := range tests { + jout, jerr := json.Marshal(tt) + sout, serr := sonic.ConfigStd.Marshal(tt) + require.Equal(t, string(jout), string(sout)) + require.NoError(t, jerr) + require.Equal(t, jerr, serr) + } +}