Explorar o código

codec: fix and add tests for PreferArrayOverSlice

Ugorji Nwoke %!s(int64=6) %!d(string=hai) anos
pai
achega
d51d2e5fca
Modificáronse 5 ficheiros con 63 adicións e 5 borrados
  1. 46 0
      codec/codec_test.go
  2. 6 3
      codec/decode.go
  3. 3 1
      codec/helper_not_unsafe.go
  4. 3 1
      codec/helper_unsafe.go
  5. 5 0
      codec/z_all_test.go

+ 46 - 0
codec/codec_test.go

@@ -3087,7 +3087,33 @@ func doTestBufioDecReader(t *testing.T, bufsize int) {
 	// println()
 }
 
+func doTestPreferArrayOverSlice(t *testing.T, h Handle) {
+	testOnce.Do(testInitAll)
+	// encode a slice, decode it with PreferArrayOverSlice
+	// if codecgen, skip the test (as codecgen doesn't work with PreferArrayOverSlice)
+	if codecgen {
+		t.Skip()
+	}
+	bh := basicHandle(h)
+	paos := bh.PreferArrayOverSlice
+	styp := bh.SliceType
+	defer func() {
+		bh.PreferArrayOverSlice = paos
+		bh.SliceType = styp
+	}()
+	bh.PreferArrayOverSlice = true
+	bh.SliceType = reflect.TypeOf(([]bool)(nil))
+
+	s2 := [4]bool{true, false, true, false}
+	s := s2[:]
+	var v interface{}
+	bs := testMarshalErr(s, h, t, t.Name())
+	testUnmarshalErr(&v, bs, h, t, t.Name())
+	testDeepEqualErr(s2, v, t, t.Name())
+}
+
 func TestBufioDecReader(t *testing.T) {
+	testOnce.Do(testInitAll)
 	doTestBufioDecReader(t, 13)
 	doTestBufioDecReader(t, 3)
 	doTestBufioDecReader(t, 5)
@@ -3916,6 +3942,26 @@ func TestSimpleStructKeyType(t *testing.T) {
 	doTestStructKeyType(t, testSimpleH)
 }
 
+func TestJsonPreferArrayOverSlice(t *testing.T) {
+	doTestPreferArrayOverSlice(t, testJsonH)
+}
+
+func TestCborPreferArrayOverSlice(t *testing.T) {
+	doTestPreferArrayOverSlice(t, testCborH)
+}
+
+func TestMsgpackPreferArrayOverSlice(t *testing.T) {
+	doTestPreferArrayOverSlice(t, testMsgpackH)
+}
+
+func TestBincPreferArrayOverSlice(t *testing.T) {
+	doTestPreferArrayOverSlice(t, testBincH)
+}
+
+func TestSimplePreferArrayOverSlice(t *testing.T) {
+	doTestPreferArrayOverSlice(t, testSimpleH)
+}
+
 // --------
 
 func TestMultipleEncDec(t *testing.T) {

+ 6 - 3
codec/decode.go

@@ -269,6 +269,7 @@ type DecodeOptions struct {
 	// PreferArrayOverSlice controls whether to decode to an array or a slice.
 	//
 	// This only impacts decoding into a nil interface{}.
+	//
 	// Consequently, it has no effect on codecgen.
 	//
 	// *Note*: This only applies if using go1.5 and above,
@@ -464,9 +465,6 @@ func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
 			var v2 []interface{}
 			d.decode(&v2)
 			rvn = rv4i(&v2).Elem()
-			if reflectArrayOfSupported && d.stid == 0 && d.h.PreferArrayOverSlice {
-				rvn = rvGetArray4Slice(rvn)
-			}
 		} else {
 			if d.str {
 				rvn = reflect.New(d.h.SliceType)
@@ -477,6 +475,11 @@ func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
 				d.decodeValue(rvn, nil)
 			}
 		}
+		if reflectArrayOfSupported && d.h.PreferArrayOverSlice {
+			// xdebugf("before: rvn: %#v", rvn)
+			rvn = rvGetArray4Slice(rvn)
+			// xdebugf("after:  rvn: %#v", rvn)
+		}
 	case valueTypeExt:
 		tag, bytes := n.u, n.l // calling decode below might taint the values
 		bfn := d.h.getExtForTag(tag)

+ 3 - 1
codec/helper_not_unsafe.go

@@ -308,8 +308,10 @@ func rvGetArrayBytesRO(rv reflect.Value, scratch []byte) (bs []byte) {
 }
 
 func rvGetArray4Slice(rv reflect.Value) (v reflect.Value) {
-	v = rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rv), intfTyp), reflect.Array)
+	v = rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rv), rv.Type().Elem()), reflect.Array)
+	// xdebugf("rvGetArray4Slice: b4 copy: rv: %#v, v: %#v", rv, v)
 	reflect.Copy(v, rv)
+	// xdebugf("rvGetArray4Slice: after copy: v: %#v", v)
 	return
 }
 

+ 3 - 1
codec/helper_unsafe.go

@@ -535,10 +535,12 @@ func rvGetArrayBytesRO(rv reflect.Value, scratch []byte) (bs []byte) {
 }
 
 func rvGetArray4Slice(rv reflect.Value) (v reflect.Value) {
-	v = rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rv), intfTyp), reflect.Array)
+	v = rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rv), rv.Type().Elem()), reflect.Array)
+	// xdebugf("rvGetArray4Slice: b4 copy: rv: %#v, v: %#v", rv, v)
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
 	uv := (*unsafeReflectValue)(unsafe.Pointer(&v))
 	uv.ptr = *(*unsafe.Pointer)(urv.ptr) // slice rv has a ptr to the slice.
+	// xdebugf("rvGetArray4Slice: after copy: v: %#v", v)
 	return
 }
 

+ 5 - 0
codec/z_all_test.go

@@ -179,6 +179,7 @@ func testJsonGroup(t *testing.T) {
 	t.Run("TestJsonMapEncodeForCanonical", TestJsonMapEncodeForCanonical)
 	t.Run("TestJsonRawToStringToRawEtc", TestJsonRawToStringToRawEtc)
 	t.Run("TestJsonStructKeyType", TestJsonStructKeyType)
+	t.Run("TestJsonPreferArrayOverSlice", TestJsonPreferArrayOverSlice)
 
 	t.Run("TestJsonInvalidUnicode", TestJsonInvalidUnicode)
 }
@@ -214,6 +215,7 @@ func testBincGroup(t *testing.T) {
 	t.Run("TestBincMapEncodeForCanonical", TestBincMapEncodeForCanonical)
 	t.Run("TestBincRawToStringToRawEtc", TestBincRawToStringToRawEtc)
 	t.Run("TestBincStructKeyType", TestBincStructKeyType)
+	t.Run("TestBincPreferArrayOverSlice", TestBincPreferArrayOverSlice)
 }
 
 func testCborGroup(t *testing.T) {
@@ -247,6 +249,7 @@ func testCborGroup(t *testing.T) {
 	t.Run("TestCborMapEncodeForCanonical", TestCborMapEncodeForCanonical)
 	t.Run("TestCborRawToStringToRawEtc", TestCborRawToStringToRawEtc)
 	t.Run("TestCborStructKeyType", TestCborStructKeyType)
+	t.Run("TestCborPreferArrayOverSlice", TestCborPreferArrayOverSlice)
 
 	t.Run("TestCborHalfFloat", TestCborHalfFloat)
 	t.Run("TestCborSkipTags", TestCborSkipTags)
@@ -282,6 +285,7 @@ func testMsgpackGroup(t *testing.T) {
 	t.Run("TestMsgpackMapEncodeForCanonical", TestMsgpackMapEncodeForCanonical)
 	t.Run("TestMsgpackRawToStringToRawEtc", TestMsgpackRawToStringToRawEtc)
 	t.Run("TestMsgpackStructKeyType", TestMsgpackStructKeyType)
+	t.Run("TestMsgpackPreferArrayOverSlice", TestMsgpackPreferArrayOverSlice)
 
 	t.Run("TestMsgpackDecodeMapAndExtSizeMismatch", TestMsgpackDecodeMapAndExtSizeMismatch)
 }
@@ -315,6 +319,7 @@ func testSimpleGroup(t *testing.T) {
 	t.Run("TestSimpleMapEncodeForCanonical", TestSimpleMapEncodeForCanonical)
 	t.Run("TestSimpleRawToStringToRawEtc", TestSimpleRawToStringToRawEtc)
 	t.Run("TestSimpleStructKeyType", TestSimpleStructKeyType)
+	t.Run("TestSimplePreferArrayOverSlice", TestSimplePreferArrayOverSlice)
 }
 
 func testSimpleMammothGroup(t *testing.T) {