internal/impl: change Go representation of extension lists to []T
Change-Id: Iebcefe0330c8f858c7735f9362abfd87043ee39d
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/192458
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/codec_tables.go b/internal/impl/codec_tables.go
index 31fc412..a332922 100644
--- a/internal/impl/codec_tables.go
+++ b/internal/impl/codec_tables.go
@@ -431,10 +431,13 @@
func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) valueCoderFuncs {
switch {
case fd.Cardinality() == pref.Repeated && !fd.IsPacked():
- if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
+ if ft.Kind() == reflect.Ptr {
+ ft = ft.Elem()
+ }
+ if ft.Kind() != reflect.Slice {
break
}
- ft := ft.Elem().Elem()
+ ft := ft.Elem()
switch fd.Kind() {
case pref.BoolKind:
if ft.Kind() == reflect.Bool {
@@ -512,10 +515,13 @@
return coderGroupSliceValue
}
case fd.Cardinality() == pref.Repeated && fd.IsPacked():
- if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
+ if ft.Kind() == reflect.Ptr {
+ ft = ft.Elem()
+ }
+ if ft.Kind() != reflect.Slice {
break
}
- ft := ft.Elem().Elem()
+ ft := ft.Elem()
switch fd.Kind() {
case pref.BoolKind:
if ft.Kind() == reflect.Bool {
diff --git a/internal/impl/convert_list.go b/internal/impl/convert_list.go
index 19748b4..fa3a400 100644
--- a/internal/impl/convert_list.go
+++ b/internal/impl/convert_list.go
@@ -11,27 +11,36 @@
pref "google.golang.org/protobuf/reflect/protoreflect"
)
+func newListConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
+ switch {
+ case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Slice:
+ return &listPtrConverter{t, newSingularConverter(t.Elem().Elem(), fd)}
+ case t.Kind() == reflect.Slice:
+ return &listConverter{t, newSingularConverter(t.Elem(), fd)}
+ }
+ panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
+}
+
type listConverter struct {
goType reflect.Type
c Converter
}
-func newListConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
- if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
- panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
- }
- return &listConverter{t, newSingularConverter(t.Elem().Elem(), fd)}
-}
-
func (c *listConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
- return pref.ValueOf(&listReflect{v, c.c})
+ pv := reflect.New(c.goType)
+ pv.Elem().Set(v)
+ return pref.ValueOf(&listReflect{pv, c.c})
}
func (c *listConverter) GoValueOf(v pref.Value) reflect.Value {
- return v.List().(*listReflect).v
+ rv := v.List().(*listReflect).v
+ if rv.IsNil() {
+ return reflect.Zero(c.goType)
+ }
+ return rv.Elem()
}
func (c *listConverter) IsValidPB(v pref.Value) bool {
@@ -39,7 +48,7 @@
if !ok {
return false
}
- return list.v.Type() == c.goType
+ return list.v.Type().Elem() == c.goType
}
func (c *listConverter) IsValidGo(v reflect.Value) bool {
@@ -47,10 +56,46 @@
}
func (c *listConverter) New() pref.Value {
- return c.PBValueOf(reflect.New(c.goType.Elem()))
+ return pref.ValueOf(&listReflect{reflect.New(c.goType), c.c})
}
func (c *listConverter) Zero() pref.Value {
+ return pref.ValueOf(&listReflect{reflect.Zero(reflect.PtrTo(c.goType)), c.c})
+}
+
+type listPtrConverter struct {
+ goType reflect.Type
+ c Converter
+}
+
+func (c *listPtrConverter) PBValueOf(v reflect.Value) pref.Value {
+ if v.Type() != c.goType {
+ panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
+ }
+ return pref.ValueOf(&listReflect{v, c.c})
+}
+
+func (c *listPtrConverter) GoValueOf(v pref.Value) reflect.Value {
+ return v.List().(*listReflect).v
+}
+
+func (c *listPtrConverter) IsValidPB(v pref.Value) bool {
+ list, ok := v.Interface().(*listReflect)
+ if !ok {
+ return false
+ }
+ return list.v.Type() == c.goType
+}
+
+func (c *listPtrConverter) IsValidGo(v reflect.Value) bool {
+ return v.Type() == c.goType
+}
+
+func (c *listPtrConverter) New() pref.Value {
+ return c.PBValueOf(reflect.New(c.goType.Elem()))
+}
+
+func (c *listPtrConverter) Zero() pref.Value {
return c.PBValueOf(reflect.Zero(c.goType))
}
diff --git a/internal/impl/extension.go b/internal/impl/extension.go
index 8192223..c64f8f5 100644
--- a/internal/impl/extension.go
+++ b/internal/impl/extension.go
@@ -151,7 +151,7 @@
xi.initFromLegacy()
} else if xi.desc.Cardinality() == pref.Repeated {
// Cardinality is initialized lazily, so we defer consulting it until here.
- xi.goType = reflect.PtrTo(reflect.SliceOf(xi.goType))
+ xi.goType = reflect.SliceOf(xi.goType)
}
xi.conv = NewConverter(xi.goType, xi.desc)
xi.tdesc.ExtensionDescriptor = xi.desc
diff --git a/internal/impl/legacy_extension.go b/internal/impl/legacy_extension.go
index 02e021b..b845f35 100644
--- a/internal/impl/legacy_extension.go
+++ b/internal/impl/legacy_extension.go
@@ -71,10 +71,6 @@
switch extType.Kind() {
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
extType = reflect.PtrTo(extType) // T -> *T for singular scalar fields
- case reflect.Ptr:
- if extType.Elem().Kind() == reflect.Slice {
- extType = extType.Elem() // *[]T -> []T for repeated fields
- }
}
// Reconstruct the legacy enum full name.
@@ -154,8 +150,6 @@
tt := reflect.TypeOf(xi.ExtensionType)
if isOptional {
tt = tt.Elem()
- } else if isRepeated {
- tt = reflect.PtrTo(tt)
}
xi.desc = xd
xi.goType = tt
diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go
index 08daace..3ff3f3c 100644
--- a/internal/impl/legacy_test.go
+++ b/internal/impl/legacy_test.go
@@ -392,16 +392,16 @@
7: m1a,
8: EnumProto2(0xbeef),
9: m2a,
- 10: &[]bool{true},
- 11: &[]int32{-1000},
- 12: &[]uint32{1280},
- 13: &[]float32{1.6180},
- 14: &[]string{"zero"},
- 15: &[][]byte{[]byte("zero")},
- 16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
- 17: &[]*proto2_20180125.Message_ChildMessage{m1b},
- 18: &[]EnumProto2{0xdead},
- 19: &[]*EnumMessages{m2b},
+ 10: []bool{true},
+ 11: []int32{-1000},
+ 12: []uint32{1280},
+ 13: []float32{1.6180},
+ 14: []string{"zero"},
+ 15: [][]byte{[]byte("zero")},
+ 16: []proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
+ 17: []*proto2_20180125.Message_ChildMessage{m1b},
+ 18: []EnumProto2{0xdead},
+ 19: []*EnumMessages{m2b},
}
for i, xt := range extensionTypes {
m.Set(xt.TypeDescriptor(), xt.ValueOf(setValues[i]))
@@ -423,16 +423,16 @@
7: m1a,
8: EnumProto2(0xbeef),
9: m2a,
- 10: &[]bool{true, false},
- 11: &[]int32{-1000, -54321},
- 12: &[]uint32{1280, 6400},
- 13: &[]float32{1.6180, 2.71828},
- 14: &[]string{"zero", "goodbye, \"world!\"\n"},
- 15: &[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
- 16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
- 17: &[]*proto2_20180125.Message_ChildMessage{m1b, m1a},
- 18: &[]EnumProto2{0xdead, 0xbeef},
- 19: &[]*EnumMessages{m2b, m2a},
+ 10: []bool{true, false},
+ 11: []int32{-1000, -54321},
+ 12: []uint32{1280, 6400},
+ 13: []float32{1.6180, 2.71828},
+ 14: []string{"zero", "goodbye, \"world!\"\n"},
+ 15: [][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
+ 16: []proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
+ 17: []*proto2_20180125.Message_ChildMessage{m1b, m1a},
+ 18: []EnumProto2{0xdead, 0xbeef},
+ 19: []*EnumMessages{m2b, m2a},
}
for i, xt := range extensionTypes {
xd := xt.TypeDescriptor()