reflect/protoreflect: add helper methods to FieldDescriptor
Added API:
FieldDescriptor.IsExtension
FieldDescriptor.IsList
FieldDescriptor.MapKey
FieldDescriptor.MapValue
FieldDescriptor.ContainingOneof
FieldDescriptor.ContainingMessage
Deprecated API (to be removed in subsequent CL):
FieldDescriptor.Oneof
FieldDescriptor.Extendee
These methods help cleanup several common usage patterns.
Change-Id: I9a3ffabc2edb2173c536509b22f330f98bba7cf3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/176977
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/cmd/protoc-gen-go/internal_gengo/main.go b/cmd/protoc-gen-go/internal_gengo/main.go
index 9e11fb0..cedda8b 100644
--- a/cmd/protoc-gen-go/internal_gengo/main.go
+++ b/cmd/protoc-gen-go/internal_gengo/main.go
@@ -559,20 +559,21 @@
goType = "[]byte"
pointer = false
case protoreflect.MessageKind, protoreflect.GroupKind:
- if field.Desc.IsMap() {
- keyType, _ := fieldGoType(g, field.Message.Fields[0])
- valType, _ := fieldGoType(g, field.Message.Fields[1])
- return fmt.Sprintf("map[%v]%v", keyType, valType), false
- }
goType = "*" + g.QualifiedGoIdent(field.Message.GoIdent)
pointer = false
}
- if field.Desc.Cardinality() == protoreflect.Repeated {
+ switch {
+ case field.Desc.IsList():
goType = "[]" + goType
pointer = false
+ case field.Desc.IsMap():
+ keyType, _ := fieldGoType(g, field.Message.Fields[0])
+ valType, _ := fieldGoType(g, field.Message.Fields[1])
+ return fmt.Sprintf("map[%v]%v", keyType, valType), false
}
+
// Extension fields always have pointer type, even when defined in a proto3 file.
- if field.Desc.Syntax() == protoreflect.Proto3 && field.Desc.Extendee() == nil {
+ if field.Desc.Syntax() == protoreflect.Proto3 && !field.Desc.IsExtension() {
pointer = false
}
return goType, pointer
@@ -587,7 +588,7 @@
}
func fieldDefaultValue(g *protogen.GeneratedFile, message *protogen.Message, field *protogen.Field) string {
- if field.Desc.Cardinality() == protoreflect.Repeated {
+ if field.Desc.IsList() {
return "nil"
}
if field.Desc.HasDefault() {
@@ -653,7 +654,7 @@
g.P("var (")
for i, extension := range f.allExtensions {
ed := extension.Desc
- targetName := string(ed.Extendee().FullName())
+ targetName := string(ed.ContainingMessage().FullName())
typeName := ed.Kind().String()
switch ed.Kind() {
case protoreflect.EnumKind:
diff --git a/encoding/bench_test.go b/encoding/bench_test.go
index 88f62b7..fdb33d1 100644
--- a/encoding/bench_test.go
+++ b/encoding/bench_test.go
@@ -49,13 +49,12 @@
for i := 0; i < fieldDescs.Len(); i++ {
fd := fieldDescs.Get(i)
num := fd.Number()
- if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
- if !fd.IsMap() {
- setList(knownFields.Get(num).List(), fd, level)
- } else {
- setMap(knownFields.Get(num).Map(), fd, level)
- }
- } else {
+ switch {
+ case fd.IsList():
+ setList(knownFields.Get(num).List(), fd, level)
+ case fd.IsMap():
+ setMap(knownFields.Get(num).Map(), fd, level)
+ default:
setScalarField(knownFields, fd, level)
}
}
diff --git a/encoding/jsonpb/decode.go b/encoding/jsonpb/decode.go
index 7e142c5..1b5a5af 100644
--- a/encoding/jsonpb/decode.go
+++ b/encoding/jsonpb/decode.go
@@ -244,14 +244,20 @@
continue
}
- if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
- // Map or list fields have cardinality of repeated.
- if err := o.unmarshalRepeated(knownFields, fd); !nerr.Merge(err) {
+ switch {
+ case fd.IsList():
+ list := knownFields.Get(fd.Number()).List()
+ if err := o.unmarshalList(list, fd); !nerr.Merge(err) {
return errors.New("%v|%q: %v", fd.FullName(), name, err)
}
- } else {
+ case fd.IsMap():
+ mmap := knownFields.Get(fd.Number()).Map()
+ if err := o.unmarshalMap(mmap, fd); !nerr.Merge(err) {
+ return errors.New("%v|%q: %v", fd.FullName(), name, err)
+ }
+ default:
// If field is a oneof, check if it has already been set.
- if od := fd.Oneof(); od != nil {
+ if od := fd.ContainingOneof(); od != nil {
idx := uint64(od.Index())
if seenOneofs.Has(idx) {
return errors.New("%v: oneof is already set", od.FullName())
@@ -548,24 +554,6 @@
return pref.Value{}, unexpectedJSONError{jval}
}
-// unmarshalRepeated unmarshals into a repeated field.
-func (o UnmarshalOptions) unmarshalRepeated(knownFields pref.KnownFields, fd pref.FieldDescriptor) error {
- var nerr errors.NonFatal
- num := fd.Number()
- val := knownFields.Get(num)
- if !fd.IsMap() {
- if err := o.unmarshalList(val.List(), fd); !nerr.Merge(err) {
- return err
- }
- } else {
- if err := o.unmarshalMap(val.Map(), fd); !nerr.Merge(err) {
- return err
- }
- }
- return nerr.E
-}
-
-// unmarshalList unmarshals into given protoreflect.List.
func (o UnmarshalOptions) unmarshalList(list pref.List, fd pref.FieldDescriptor) error {
var nerr errors.NonFatal
jval, err := o.decoder.Read()
@@ -610,10 +598,8 @@
return nerr.E
}
-// unmarshalMap unmarshals into given protoreflect.Map.
func (o UnmarshalOptions) unmarshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
var nerr errors.NonFatal
-
jval, err := o.decoder.Read()
if !nerr.Merge(err) {
return err
@@ -622,17 +608,11 @@
return unexpectedJSONError{jval}
}
- fields := fd.Message().Fields()
- keyDesc := fields.ByNumber(1)
- valDesc := fields.ByNumber(2)
-
// Determine ahead whether map entry is a scalar type or a message type in
// order to call the appropriate unmarshalMapValue func inside the for loop
// below.
- unmarshalMapValue := func() (pref.Value, error) {
- return o.unmarshalScalar(valDesc)
- }
- switch valDesc.Kind() {
+ var unmarshalMapValue func() (pref.Value, error)
+ switch fd.MapValue().Kind() {
case pref.MessageKind, pref.GroupKind:
unmarshalMapValue = func() (pref.Value, error) {
var nerr errors.NonFatal
@@ -642,6 +622,10 @@
}
return pref.ValueOf(m), nerr.E
}
+ default:
+ unmarshalMapValue = func() (pref.Value, error) {
+ return o.unmarshalScalar(fd.MapValue())
+ }
}
Loop:
@@ -666,7 +650,7 @@
}
// Unmarshal field name.
- pkey, err := unmarshalMapKey(name, keyDesc)
+ pkey, err := unmarshalMapKey(name, fd.MapKey())
if !nerr.Merge(err) {
return err
}
diff --git a/encoding/jsonpb/encode.go b/encoding/jsonpb/encode.go
index 90767ce..256cd74 100644
--- a/encoding/jsonpb/encode.go
+++ b/encoding/jsonpb/encode.go
@@ -118,25 +118,14 @@
// marshalValue marshals the given protoreflect.Value.
func (o MarshalOptions) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
- var nerr errors.NonFatal
- if fd.Cardinality() == pref.Repeated {
- // Map or repeated fields.
- if fd.IsMap() {
- if err := o.marshalMap(val.Map(), fd); !nerr.Merge(err) {
- return err
- }
- } else {
- if err := o.marshalList(val.List(), fd); !nerr.Merge(err) {
- return err
- }
- }
- } else {
- // Required or optional fields.
- if err := o.marshalSingular(val, fd); !nerr.Merge(err) {
- return err
- }
+ switch {
+ case fd.IsList():
+ return o.marshalList(val.List(), fd)
+ case fd.IsMap():
+ return o.marshalMap(val.Map(), fd)
+ default:
+ return o.marshalSingular(val, fd)
}
- return nerr.E
}
// marshalSingular marshals the given non-repeated field value. This includes
@@ -226,17 +215,13 @@
o.encoder.StartObject()
defer o.encoder.EndObject()
- msgFields := fd.Message().Fields()
- keyType := msgFields.ByNumber(1)
- valType := msgFields.ByNumber(2)
-
// Get a sorted list based on keyType first.
entries := make([]mapEntry, 0, mmap.Len())
mmap.Range(func(key pref.MapKey, val pref.Value) bool {
entries = append(entries, mapEntry{key: key, value: val})
return true
})
- sortMap(keyType.Kind(), entries)
+ sortMap(fd.MapKey().Kind(), entries)
// Write out sorted list.
var nerr errors.NonFatal
@@ -244,7 +229,7 @@
if err := o.encoder.WriteName(entry.key.String()); !nerr.Merge(err) {
return err
}
- if err := o.marshalSingular(entry.value, valType); !nerr.Merge(err) {
+ if err := o.marshalSingular(entry.value, fd.MapValue()); !nerr.Merge(err) {
return err
}
}
@@ -333,6 +318,6 @@
if xd.FullName().Parent() != md.FullName() {
return false
}
- xmd, ok := xd.Extendee().(interface{ IsMessageSet() bool })
+ xmd, ok := xd.ContainingMessage().(interface{ IsMessageSet() bool })
return ok && xmd.IsMessageSet()
}
diff --git a/encoding/textpb/decode.go b/encoding/textpb/decode.go
index 38092ac..c586331 100644
--- a/encoding/textpb/decode.go
+++ b/encoding/textpb/decode.go
@@ -159,14 +159,36 @@
return errors.New("%v contains unknown field: %v", messageDesc.FullName(), tkey)
}
- if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
- // Map or list fields have cardinality of repeated.
- if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
+ switch {
+ case fd.IsList():
+ // If input is not a list, turn it into a list.
+ var items []text.Value
+ if tval.Type() != text.List {
+ items = []text.Value{tval}
+ } else {
+ items = tval.List()
+ }
+
+ list := knownFields.Get(fd.Number()).List()
+ if err := o.unmarshalList(items, fd, list); !nerr.Merge(err) {
return err
}
- } else {
+ case fd.IsMap():
+ // If input is not a list, turn it into a list.
+ var items []text.Value
+ if tval.Type() != text.List {
+ items = []text.Value{tval}
+ } else {
+ items = tval.List()
+ }
+
+ mmap := knownFields.Get(fd.Number()).Map()
+ if err := o.unmarshalMap(items, fd, mmap); !nerr.Merge(err) {
+ return err
+ }
+ default:
// If field is a oneof, check if it has already been set.
- if od := fd.Oneof(); od != nil {
+ if od := fd.ContainingOneof(); od != nil {
idx := uint64(od.Index())
if seenOneofs.Has(idx) {
return errors.New("oneof %v is already set", od.FullName())
@@ -232,33 +254,6 @@
return nerr.E
}
-// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
-// call this for cardinality=repeated.
-func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
- var items []text.Value
- // If input is not a list, turn it into a list.
- if input.Type() != text.List {
- items = []text.Value{input}
- } else {
- items = input.List()
- }
-
- var nerr errors.NonFatal
- num := fd.Number()
- val := knownFields.Get(num)
- if !fd.IsMap() {
- if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
- return err
- }
- } else {
- if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
- return err
- }
- }
-
- return nerr.E
-}
-
// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
@@ -358,14 +353,11 @@
// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
var nerr errors.NonFatal
- fields := fd.Message().Fields()
- keyDesc := fields.ByNumber(1)
- valDesc := fields.ByNumber(2)
// Determine ahead whether map entry is a scalar type or a message type in order to call the
// appropriate unmarshalMapValue func inside the for loop below.
unmarshalMapValue := unmarshalMapScalarValue
- switch valDesc.Kind() {
+ switch fd.MapValue().Kind() {
case pref.MessageKind, pref.GroupKind:
unmarshalMapValue = o.unmarshalMapMessageValue
}
@@ -378,11 +370,11 @@
if !nerr.Merge(err) {
return err
}
- pkey, err := unmarshalMapKey(tkey, keyDesc)
+ pkey, err := unmarshalMapKey(tkey, fd.MapKey())
if !nerr.Merge(err) {
return err
}
- err = unmarshalMapValue(tval, pkey, valDesc, mmap)
+ err = unmarshalMapValue(tval, pkey, fd.MapValue(), mmap)
if !nerr.Merge(err) {
return err
}
diff --git a/encoding/textpb/encode.go b/encoding/textpb/encode.go
index b8b2e71..9bd8279 100644
--- a/encoding/textpb/encode.go
+++ b/encoding/textpb/encode.go
@@ -132,28 +132,26 @@
func (o MarshalOptions) appendField(msgFields [][2]text.Value, name text.Value, pval pref.Value, fd pref.FieldDescriptor) ([][2]text.Value, error) {
var nerr errors.NonFatal
- if fd.Cardinality() == pref.Repeated {
- // Map or repeated fields.
- var items []text.Value
- var err error
- if fd.IsMap() {
- items, err = o.marshalMap(pval.Map(), fd)
- if !nerr.Merge(err) {
- return msgFields, err
- }
- } else {
- items, err = o.marshalList(pval.List(), fd)
- if !nerr.Merge(err) {
- return msgFields, err
- }
+ switch {
+ case fd.IsList():
+ items, err := o.marshalList(pval.List(), fd)
+ if !nerr.Merge(err) {
+ return msgFields, err
}
- // Add each item as key: value field.
for _, item := range items {
msgFields = append(msgFields, [2]text.Value{name, item})
}
- } else {
- // Required or optional fields.
+ case fd.IsMap():
+ items, err := o.marshalMap(pval.Map(), fd)
+ if !nerr.Merge(err) {
+ return msgFields, err
+ }
+
+ for _, item := range items {
+ msgFields = append(msgFields, [2]text.Value{name, item})
+ }
+ default:
tval, err := o.marshalSingular(pval, fd)
if !nerr.Merge(err) {
return msgFields, err
@@ -231,19 +229,16 @@
var nerr errors.NonFatal
// values is a list of messages.
values := make([]text.Value, 0, mmap.Len())
- msgFields := fd.Message().Fields()
- keyType := msgFields.ByNumber(1)
- valType := msgFields.ByNumber(2)
var err error
- mapsort.Range(mmap, keyType.Kind(), func(key pref.MapKey, val pref.Value) bool {
+ mapsort.Range(mmap, fd.MapKey().Kind(), func(key pref.MapKey, val pref.Value) bool {
var keyTxtVal text.Value
- keyTxtVal, err = o.marshalSingular(key.Value(), keyType)
+ keyTxtVal, err = o.marshalSingular(key.Value(), fd.MapKey())
if !nerr.Merge(err) {
return false
}
var valTxtVal text.Value
- valTxtVal, err = o.marshalSingular(val, valType)
+ valTxtVal, err = o.marshalSingular(val, fd.MapValue())
if !nerr.Merge(err) {
return false
}
@@ -314,7 +309,7 @@
if xd.FullName().Parent() != md.FullName() {
return false
}
- xmd, ok := xd.Extendee().(interface{ IsMessageSet() bool })
+ xmd, ok := xd.ContainingMessage().(interface{ IsMessageSet() bool })
return ok && xmd.IsMessageSet()
}
diff --git a/internal/encoding/tag/tag.go b/internal/encoding/tag/tag.go
index 72499c1..d4e868f 100644
--- a/internal/encoding/tag/tag.go
+++ b/internal/encoding/tag/tag.go
@@ -175,13 +175,13 @@
// The previous implementation does not tag extension fields as proto3,
// even when the field is defined in a proto3 file. Match that behavior
// for consistency.
- if fd.Syntax() == pref.Proto3 && fd.Extendee() == nil {
+ if fd.Syntax() == pref.Proto3 && !fd.IsExtension() {
tag = append(tag, "proto3")
}
if fd.Kind() == pref.EnumKind && enumName != "" {
tag = append(tag, "enum="+enumName)
}
- if fd.Oneof() != nil {
+ if fd.ContainingOneof() != nil {
tag = append(tag, "oneof")
}
// This must appear last in the tag, since commas in strings aren't escaped.
diff --git a/internal/fileinit/desc.go b/internal/fileinit/desc.go
index 2729da6..8854cab 100644
--- a/internal/fileinit/desc.go
+++ b/internal/fileinit/desc.go
@@ -431,23 +431,43 @@
func (fd *fieldDesc) Options() pref.ProtoMessage {
return unmarshalOptions(descopts.Field, fd.options)
}
-func (fd *fieldDesc) Number() pref.FieldNumber { return fd.number }
-func (fd *fieldDesc) Cardinality() pref.Cardinality { return fd.cardinality }
-func (fd *fieldDesc) Kind() pref.Kind { return fd.kind }
-func (fd *fieldDesc) HasJSONName() bool { return fd.hasJSONName }
-func (fd *fieldDesc) JSONName() string { return fd.jsonName }
-func (fd *fieldDesc) IsPacked() bool { return fd.isPacked }
-func (fd *fieldDesc) IsWeak() bool { return fd.isWeak }
-func (fd *fieldDesc) IsMap() bool { return fd.isMap }
+func (fd *fieldDesc) Number() pref.FieldNumber { return fd.number }
+func (fd *fieldDesc) Cardinality() pref.Cardinality { return fd.cardinality }
+func (fd *fieldDesc) Kind() pref.Kind { return fd.kind }
+func (fd *fieldDesc) HasJSONName() bool { return fd.hasJSONName }
+func (fd *fieldDesc) JSONName() string { return fd.jsonName }
+func (fd *fieldDesc) IsPacked() bool { return fd.isPacked }
+func (fd *fieldDesc) IsExtension() bool { return false }
+func (fd *fieldDesc) IsWeak() bool { return fd.isWeak }
+func (fd *fieldDesc) IsList() bool { return fd.cardinality == pref.Repeated && !fd.IsMap() }
+func (fd *fieldDesc) IsMap() bool { return fd.isMap }
+func (fd *fieldDesc) MapKey() pref.FieldDescriptor {
+ if !fd.isMap {
+ return nil
+ }
+ return fd.Message().Fields().ByNumber(1)
+}
+func (fd *fieldDesc) MapValue() pref.FieldDescriptor {
+ if !fd.isMap {
+ return nil
+ }
+ return fd.Message().Fields().ByNumber(2)
+}
func (fd *fieldDesc) HasDefault() bool { return fd.defVal.has }
func (fd *fieldDesc) Default() pref.Value { return fd.defVal.get() }
func (fd *fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return fd.defVal.enum }
-func (fd *fieldDesc) Oneof() pref.OneofDescriptor { return fd.oneofType }
-func (fd *fieldDesc) Extendee() pref.MessageDescriptor { return nil }
-func (fd *fieldDesc) Enum() pref.EnumDescriptor { return fd.enumType }
-func (fd *fieldDesc) Message() pref.MessageDescriptor { return fd.messageType }
-func (fd *fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
-func (fd *fieldDesc) ProtoType(pref.FieldDescriptor) {}
+func (fd *fieldDesc) ContainingOneof() pref.OneofDescriptor { return fd.oneofType }
+func (fd *fieldDesc) ContainingMessage() pref.MessageDescriptor {
+ return fd.parent.(pref.MessageDescriptor)
+}
+func (fd *fieldDesc) Enum() pref.EnumDescriptor { return fd.enumType }
+func (fd *fieldDesc) Message() pref.MessageDescriptor { return fd.messageType }
+func (fd *fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
+func (fd *fieldDesc) ProtoType(pref.FieldDescriptor) {}
+
+// TODO: Remove this.
+func (fd *fieldDesc) Oneof() pref.OneofDescriptor { return fd.oneofType }
+func (fd *fieldDesc) Extendee() pref.MessageDescriptor { return nil }
func (od *oneofDesc) Options() pref.ProtoMessage {
return unmarshalOptions(descopts.Oneof, od.options)
@@ -505,13 +525,17 @@
func (xd *extensionDesc) HasJSONName() bool { return xd.lazyInit().hasJSONName }
func (xd *extensionDesc) JSONName() string { return xd.lazyInit().jsonName }
func (xd *extensionDesc) IsPacked() bool { return xd.lazyInit().isPacked }
+func (xd *extensionDesc) IsExtension() bool { return true }
func (xd *extensionDesc) IsWeak() bool { return false }
+func (xd *extensionDesc) IsList() bool { return xd.Cardinality() == pref.Repeated }
func (xd *extensionDesc) IsMap() bool { return false }
+func (xd *extensionDesc) MapKey() pref.FieldDescriptor { return nil }
+func (xd *extensionDesc) MapValue() pref.FieldDescriptor { return nil }
func (xd *extensionDesc) HasDefault() bool { return xd.lazyInit().defVal.has }
func (xd *extensionDesc) Default() pref.Value { return xd.lazyInit().defVal.get() }
func (xd *extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().defVal.enum }
-func (xd *extensionDesc) Oneof() pref.OneofDescriptor { return nil }
-func (xd *extensionDesc) Extendee() pref.MessageDescriptor { return xd.extendedType }
+func (xd *extensionDesc) ContainingOneof() pref.OneofDescriptor { return nil }
+func (xd *extensionDesc) ContainingMessage() pref.MessageDescriptor { return xd.extendedType }
func (xd *extensionDesc) Enum() pref.EnumDescriptor { return xd.lazyInit().enumType }
func (xd *extensionDesc) Message() pref.MessageDescriptor { return xd.lazyInit().messageType }
func (xd *extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, xd) }
@@ -531,6 +555,10 @@
return xd.legacyDesc
}
+// TODO: Remove this.
+func (xd *extensionDesc) Oneof() pref.OneofDescriptor { return nil }
+func (xd *extensionDesc) Extendee() pref.MessageDescriptor { return xd.extendedType }
+
type (
serviceDesc struct {
baseDesc
diff --git a/internal/fileinit/fileinit_test.go b/internal/fileinit/fileinit_test.go
index ac1c5e2..dd58fd0 100644
--- a/internal/fileinit/fileinit_test.go
+++ b/internal/fileinit/fileinit_test.go
@@ -88,7 +88,7 @@
f(field)
switch field.Kind() {
case protoreflect.MessageKind, protoreflect.GroupKind:
- if field.Cardinality() == protoreflect.Repeated {
+ if field.IsList() {
for i, list := 0, value.List(); i < list.Len(); i++ {
visitFields(list.Get(i).Message(), f)
}
diff --git a/internal/impl/legacy_extension.go b/internal/impl/legacy_extension.go
index a0ae3f0..7a8fea7 100644
--- a/internal/impl/legacy_extension.go
+++ b/internal/impl/legacy_extension.go
@@ -64,7 +64,7 @@
}
t := extensionTypeFromDesc(x.Desc)
d := t.Descriptor()
- if d.Cardinality() == pref.Repeated {
+ if d.IsList() {
return t.ValueOf(x.Value).List().Len() > 0
}
return true
@@ -105,7 +105,7 @@
}
t := extensionTypeFromDesc(x.Desc)
d := t.Descriptor()
- if d.Cardinality() == pref.Repeated {
+ if d.IsList() {
t.ValueOf(x.Value).List().Truncate(0)
return
}
@@ -153,7 +153,7 @@
func (p legacyExtensionTypes) Register(t pref.ExtensionType) {
d := t.Descriptor()
- if p.mi.PBType.Descriptor().FullName() != d.Extendee().FullName() {
+ if p.mi.PBType.Descriptor().FullName() != d.ContainingMessage().FullName() {
panic("extended type mismatch")
}
if !p.mi.PBType.Descriptor().ExtensionRanges().Has(d.Number()) {
@@ -164,7 +164,7 @@
panic("extension descriptor already registered")
}
x.Desc = extensionDescFromType(t)
- if d.Cardinality() == pref.Repeated {
+ if d.IsList() {
// If the field is repeated, initialize the entry with an empty list
// so that future Get operations can return a mutable and concrete list.
x.Value = t.InterfaceOf(t.New())
@@ -178,7 +178,7 @@
return
}
x := p.x.Get(d.Number())
- if d.Cardinality() == pref.Repeated {
+ if d.IsList() {
// Treat an empty repeated field as unpopulated.
v := reflect.ValueOf(x.Value)
if x.Value == nil || v.IsNil() || v.Elem().Len() == 0 {
diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go
index 28ab672..d5d4e54 100644
--- a/internal/impl/legacy_test.go
+++ b/internal/impl/legacy_test.go
@@ -685,7 +685,7 @@
// Ignore New since it a constructor.
case "Options":
// Ignore descriptor options since protos are not cmperable.
- case "Oneof", "Extendee", "Enum", "Message":
+ case "ContainingOneof", "ContainingMessage", "Enum", "Message":
// Avoid descending into a dependency to avoid a cycle.
// Just record the full name if available.
//
@@ -694,6 +694,8 @@
if !v.IsNil() {
out[name] = v.Interface().(pref.Descriptor).FullName()
}
+ case "Oneof", "Extendee":
+ // TODO: Remove this.
default:
out[name] = m.Call(nil)[0].Interface()
}
diff --git a/internal/impl/message.go b/internal/impl/message.go
index 5c2ae28..a98e7bb 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -118,11 +118,11 @@
fs := si.fieldsByNumber[fd.Number()]
var fi fieldInfo
switch {
- case fd.Oneof() != nil:
- fi = fieldInfoForOneof(fd, si.oneofsByName[fd.Oneof().Name()], si.oneofWrappersByNumber[fd.Number()])
+ case fd.ContainingOneof() != nil:
+ fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], si.oneofWrappersByNumber[fd.Number()])
case fd.IsMap():
fi = fieldInfoForMap(fd, fs)
- case fd.Cardinality() == pref.Repeated:
+ case fd.IsList():
fi = fieldInfoForList(fd, fs)
case fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind:
fi = fieldInfoForMessage(fd, fs)
diff --git a/internal/impl/message_field.go b/internal/impl/message_field.go
index 8cd82fe..10405d0 100644
--- a/internal/impl/message_field.go
+++ b/internal/impl/message_field.go
@@ -90,8 +90,8 @@
if ft.Kind() != reflect.Map {
panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
}
- keyConv := pvalue.NewLegacyConverter(ft.Key(), fd.Message().Fields().ByNumber(1).Kind(), legacyWrapper)
- valConv := pvalue.NewLegacyConverter(ft.Elem(), fd.Message().Fields().ByNumber(2).Kind(), legacyWrapper)
+ keyConv := pvalue.NewLegacyConverter(ft.Key(), fd.MapKey().Kind(), legacyWrapper)
+ valConv := pvalue.NewLegacyConverter(ft.Elem(), fd.MapValue().Kind(), legacyWrapper)
fieldOffset := offsetOf(fs)
// TODO: Implement unsafe fast path?
return fieldInfo{
diff --git a/internal/legacy/extension.go b/internal/legacy/extension.go
index 9174555..b700a7f 100644
--- a/internal/legacy/extension.go
+++ b/internal/legacy/extension.go
@@ -65,7 +65,8 @@
// Determine the parent type if possible.
var parent piface.MessageV1
- if mt, _ := preg.GlobalTypes.FindMessageByName(xt.Descriptor().Extendee().FullName()); mt != nil {
+ messageName := xt.Descriptor().ContainingMessage().FullName()
+ if mt, _ := preg.GlobalTypes.FindMessageByName(messageName); mt != nil {
// Create a new parent message and unwrap it if possible.
mv := mt.New().Interface()
t := reflect.TypeOf(mv)
diff --git a/internal/legacy/file_test.go b/internal/legacy/file_test.go
index 9a9a3fc..c8d9af5 100644
--- a/internal/legacy/file_test.go
+++ b/internal/legacy/file_test.go
@@ -433,7 +433,7 @@
case "HasJSONName":
// Ignore this since the semantics of the field has
// changed across protoc and protoc-gen-go releases.
- case "Oneof", "Extendee", "Enum", "Message":
+ case "ContainingOneof", "ContainingMessage", "Enum", "Message":
// Avoid descending into a dependency to avoid a cycle.
// Just record the full name if available.
//
@@ -442,6 +442,8 @@
if !v.IsNil() {
out[name] = v.Interface().(pref.Descriptor).FullName()
}
+ case "Oneof", "Extendee":
+ // TODO: Remove this.
default:
out[name] = m.Call(nil)[0].Interface()
}
diff --git a/internal/prototype/go_type.go b/internal/prototype/go_type.go
index 6c88a7c..6110e95 100644
--- a/internal/prototype/go_type.go
+++ b/internal/prototype/go_type.go
@@ -124,7 +124,7 @@
// The type M is the concrete message type returned by NewMessage,
// which is often, but not required to be, a pointer to a named struct type.
func GoExtension(xd protoreflect.ExtensionDescriptor, et protoreflect.EnumType, mt protoreflect.MessageType) protoreflect.ExtensionType {
- if xd.Extendee() == nil {
+ if !xd.IsExtension() {
panic("field descriptor does not extend a message")
}
switch xd.Kind() {
diff --git a/internal/prototype/protofile_list.go b/internal/prototype/protofile_list.go
index 426e695..99f1cc0 100644
--- a/internal/prototype/protofile_list.go
+++ b/internal/prototype/protofile_list.go
@@ -114,7 +114,7 @@
md, _ := parent.Parent()
fs := md.(pref.MessageDescriptor).Fields()
for i := 0; i < fs.Len(); i++ {
- if f := fs.Get(i); od == f.Oneof() {
+ if f := fs.Get(i); od == f.ContainingOneof() {
p.typs = append(p.typs, f)
}
}
diff --git a/internal/prototype/protofile_type.go b/internal/prototype/protofile_type.go
index 4e3416f..a9d7bc3 100644
--- a/internal/prototype/protofile_type.go
+++ b/internal/prototype/protofile_type.go
@@ -171,21 +171,43 @@
func (t fieldDesc) IsPacked() bool {
return isPacked(t.f.IsPacked, t.f.syntax, t.f.Cardinality, t.f.Kind)
}
-func (t fieldDesc) IsWeak() bool { return t.f.IsWeak }
+func (t fieldDesc) IsExtension() bool { return false }
+func (t fieldDesc) IsWeak() bool { return t.f.IsWeak }
+func (t fieldDesc) IsList() bool {
+ return t.f.Cardinality == pref.Repeated && !t.IsMap()
+}
func (t fieldDesc) IsMap() bool {
mt := t.Message()
return mt != nil && mt.IsMapEntry()
}
+func (t fieldDesc) MapKey() pref.FieldDescriptor {
+ if !t.IsMap() {
+ return nil
+ }
+ return t.Message().Fields().ByNumber(1)
+}
+func (t fieldDesc) MapValue() pref.FieldDescriptor {
+ if !t.IsMap() {
+ return nil
+ }
+ return t.Message().Fields().ByNumber(2)
+}
func (t fieldDesc) HasDefault() bool { return t.f.Default.IsValid() }
func (t fieldDesc) Default() pref.Value { return t.f.dv.value(t, t.f.Default) }
func (t fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.f.dv.enum(t, t.f.Default) }
-func (t fieldDesc) Oneof() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
-func (t fieldDesc) Extendee() pref.MessageDescriptor { return nil }
-func (t fieldDesc) Enum() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) }
-func (t fieldDesc) Message() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) }
-func (t fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) }
-func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
-func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
+func (t fieldDesc) ContainingOneof() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
+func (t fieldDesc) ContainingMessage() pref.MessageDescriptor {
+ return t.f.parent.(pref.MessageDescriptor)
+}
+func (t fieldDesc) Enum() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) }
+func (t fieldDesc) Message() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) }
+func (t fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) }
+func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
+func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
+
+// TODO: Remove this.
+func (t fieldDesc) Oneof() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
+func (t fieldDesc) Extendee() pref.MessageDescriptor { return nil }
func isPacked(packed OptionalBool, s pref.Syntax, c pref.Cardinality, k pref.Kind) bool {
if packed == False || (packed == DefaultBool && s == pref.Proto2) {
@@ -299,18 +321,28 @@
// Extensions always use proto2 defaults for packing.
return isPacked(t.x.IsPacked, pref.Proto2, t.x.Cardinality, t.x.Kind)
}
+func (t extensionDesc) IsExtension() bool { return true }
func (t extensionDesc) IsWeak() bool { return false }
+func (t extensionDesc) IsList() bool { return t.x.Cardinality == pref.Repeated }
func (t extensionDesc) IsMap() bool { return false }
+func (t extensionDesc) MapKey() pref.FieldDescriptor { return nil }
+func (t extensionDesc) MapValue() pref.FieldDescriptor { return nil }
func (t extensionDesc) HasDefault() bool { return t.x.Default.IsValid() }
func (t extensionDesc) Default() pref.Value { return t.x.dv.value(t, t.x.Default) }
func (t extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.x.dv.enum(t, t.x.Default) }
-func (t extensionDesc) Oneof() pref.OneofDescriptor { return nil }
-func (t extensionDesc) Extendee() pref.MessageDescriptor { return t.x.xt.lazyInit(t, &t.x.ExtendedType) }
-func (t extensionDesc) Enum() pref.EnumDescriptor { return t.x.et.lazyInit(t, &t.x.EnumType) }
-func (t extensionDesc) Message() pref.MessageDescriptor { return t.x.mt.lazyInit(t, &t.x.MessageType) }
-func (t extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) }
-func (t extensionDesc) ProtoType(pref.FieldDescriptor) {}
-func (t extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
+func (t extensionDesc) ContainingOneof() pref.OneofDescriptor { return nil }
+func (t extensionDesc) ContainingMessage() pref.MessageDescriptor {
+ return t.x.xt.lazyInit(t, &t.x.ExtendedType)
+}
+func (t extensionDesc) Enum() pref.EnumDescriptor { return t.x.et.lazyInit(t, &t.x.EnumType) }
+func (t extensionDesc) Message() pref.MessageDescriptor { return t.x.mt.lazyInit(t, &t.x.MessageType) }
+func (t extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) }
+func (t extensionDesc) ProtoType(pref.FieldDescriptor) {}
+func (t extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
+
+// TODO: Remove this.
+func (t extensionDesc) Oneof() pref.OneofDescriptor { return nil }
+func (t extensionDesc) Extendee() pref.MessageDescriptor { return t.x.xt.lazyInit(t, &t.x.ExtendedType) }
type enumMeta struct {
inheritedMeta
diff --git a/internal/prototype/standalone_type.go b/internal/prototype/standalone_type.go
index 3bf4115..a9b54e9 100644
--- a/internal/prototype/standalone_type.go
+++ b/internal/prototype/standalone_type.go
@@ -85,17 +85,25 @@
func (t standaloneExtension) IsPacked() bool {
return isPacked(t.x.IsPacked, pref.Proto2, t.x.Cardinality, t.x.Kind)
}
-func (t standaloneExtension) IsWeak() bool { return false }
-func (t standaloneExtension) IsMap() bool { return false }
-func (t standaloneExtension) HasDefault() bool { return t.x.Default.IsValid() }
-func (t standaloneExtension) Default() pref.Value { return t.x.dv.value(t, t.x.Default) }
+func (t standaloneExtension) IsExtension() bool { return true }
+func (t standaloneExtension) IsWeak() bool { return false }
+func (t standaloneExtension) IsList() bool { return t.x.Cardinality == pref.Repeated }
+func (t standaloneExtension) IsMap() bool { return false }
+func (t standaloneExtension) MapKey() pref.FieldDescriptor { return nil }
+func (t standaloneExtension) MapValue() pref.FieldDescriptor { return nil }
+func (t standaloneExtension) HasDefault() bool { return t.x.Default.IsValid() }
+func (t standaloneExtension) Default() pref.Value { return t.x.dv.value(t, t.x.Default) }
func (t standaloneExtension) DefaultEnumValue() pref.EnumValueDescriptor {
return t.x.dv.enum(t, t.x.Default)
}
-func (t standaloneExtension) Oneof() pref.OneofDescriptor { return nil }
-func (t standaloneExtension) Extendee() pref.MessageDescriptor { return t.x.ExtendedType }
-func (t standaloneExtension) Enum() pref.EnumDescriptor { return t.x.EnumType }
-func (t standaloneExtension) Message() pref.MessageDescriptor { return t.x.MessageType }
-func (t standaloneExtension) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) }
-func (t standaloneExtension) ProtoType(pref.FieldDescriptor) {}
-func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement) {}
+func (t standaloneExtension) ContainingOneof() pref.OneofDescriptor { return nil }
+func (t standaloneExtension) ContainingMessage() pref.MessageDescriptor { return t.x.ExtendedType }
+func (t standaloneExtension) Enum() pref.EnumDescriptor { return t.x.EnumType }
+func (t standaloneExtension) Message() pref.MessageDescriptor { return t.x.MessageType }
+func (t standaloneExtension) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, t) }
+func (t standaloneExtension) ProtoType(pref.FieldDescriptor) {}
+func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement) {}
+
+// TODO: Remove this.
+func (t standaloneExtension) Oneof() pref.OneofDescriptor { return nil }
+func (t standaloneExtension) Extendee() pref.MessageDescriptor { return t.x.ExtendedType }
diff --git a/internal/prototype/type_test.go b/internal/prototype/type_test.go
index a8c171b..c00a816 100644
--- a/internal/prototype/type_test.go
+++ b/internal/prototype/type_test.go
@@ -18,6 +18,7 @@
scalar "github.com/golang/protobuf/v2/internal/scalar"
pdesc "github.com/golang/protobuf/v2/reflect/protodesc"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+ "github.com/google/go-cmp/cmp"
descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
)
@@ -391,42 +392,46 @@
"Fields": M{
"Len": 2,
"ByNumber:1": M{
- "Parent": M{"FullName": pref.FullName("test.A")},
- "Index": 0,
- "Name": pref.Name("key"),
- "FullName": pref.FullName("test.A.key"),
- "Number": pref.FieldNumber(1),
- "Cardinality": pref.Optional,
- "Kind": pref.StringKind,
- "Options": &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
- "HasJSONName": false,
- "JSONName": "key",
- "IsPacked": false,
- "IsMap": false,
- "IsWeak": false,
- "Default": "",
- "Oneof": nil,
- "Extendee": nil,
- "Message": nil,
- "Enum": nil,
+ "Parent": M{"FullName": pref.FullName("test.A")},
+ "Index": 0,
+ "Name": pref.Name("key"),
+ "FullName": pref.FullName("test.A.key"),
+ "Number": pref.FieldNumber(1),
+ "Cardinality": pref.Optional,
+ "Kind": pref.StringKind,
+ "Options": &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
+ "HasJSONName": false,
+ "JSONName": "key",
+ "IsPacked": false,
+ "IsList": false,
+ "IsMap": false,
+ "IsExtension": false,
+ "IsWeak": false,
+ "Default": "",
+ "ContainingOneof": nil,
+ "ContainingMessage": M{"FullName": pref.FullName("test.A")},
+ "Message": nil,
+ "Enum": nil,
},
"ByNumber:2": M{
- "Parent": M{"FullName": pref.FullName("test.A")},
- "Index": 1,
- "Name": pref.Name("value"),
- "FullName": pref.FullName("test.A.value"),
- "Number": pref.FieldNumber(2),
- "Cardinality": pref.Optional,
- "Kind": pref.MessageKind,
- "JSONName": "value",
- "IsPacked": false,
- "IsMap": false,
- "IsWeak": false,
- "Default": nil,
- "Oneof": nil,
- "Extendee": nil,
- "Message": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
- "Enum": nil,
+ "Parent": M{"FullName": pref.FullName("test.A")},
+ "Index": 1,
+ "Name": pref.Name("value"),
+ "FullName": pref.FullName("test.A.value"),
+ "Number": pref.FieldNumber(2),
+ "Cardinality": pref.Optional,
+ "Kind": pref.MessageKind,
+ "JSONName": "value",
+ "IsPacked": false,
+ "IsList": false,
+ "IsMap": false,
+ "IsExtension": false,
+ "IsWeak": false,
+ "Default": nil,
+ "ContainingOneof": nil,
+ "ContainingMessage": M{"FullName": pref.FullName("test.A")},
+ "Message": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
+ "Enum": nil,
},
"ByNumber:3": nil,
},
@@ -444,31 +449,40 @@
"Len": 6,
"ByJSONName:field_one": nil,
"ByJSONName:fieldOne": M{
- "Name": pref.Name("field_one"),
- "Index": 0,
- "JSONName": "fieldOne",
- "Default": "hello, \"world!\"\n",
- "Oneof": M{"Name": pref.Name("O1"), "IsPlaceholder": false},
+ "Name": pref.Name("field_one"),
+ "Index": 0,
+ "JSONName": "fieldOne",
+ "Default": "hello, \"world!\"\n",
+ "ContainingOneof": M{"Name": pref.Name("O1"), "IsPlaceholder": false},
+ "ContainingMessage": M{"FullName": pref.FullName("test.B")},
},
"ByJSONName:fieldTwo": nil,
"ByJSONName:Field2": M{
- "Name": pref.Name("field_two"),
- "Index": 1,
- "HasJSONName": true,
- "JSONName": "Field2",
- "Default": pref.EnumNumber(1),
- "Oneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
+ "Name": pref.Name("field_two"),
+ "Index": 1,
+ "HasJSONName": true,
+ "JSONName": "Field2",
+ "Default": pref.EnumNumber(1),
+ "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
},
"ByName:fieldThree": nil,
"ByName:field_three": M{
- "IsMap": false,
- "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
- "Oneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
+ "IsExtension": false,
+ "IsMap": false,
+ "MapKey": nil,
+ "MapValue": nil,
+ "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
+ "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
+ "ContainingMessage": M{"FullName": pref.FullName("test.B")},
},
"ByNumber:12": nil,
"ByNumber:4": M{
"Cardinality": pref.Repeated,
+ "IsExtension": false,
+ "IsList": false,
"IsMap": true,
+ "MapKey": M{"Kind": pref.StringKind},
+ "MapValue": M{"Kind": pref.MessageKind, "Message": M{"FullName": pref.FullName("test.B")}},
"Default": nil,
"Message": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
},
@@ -476,12 +490,14 @@
"Cardinality": pref.Repeated,
"Kind": pref.Int32Kind,
"IsPacked": true,
+ "IsList": true,
+ "IsMap": false,
"Default": int32(0),
},
"ByNumber:6": M{
- "Cardinality": pref.Required,
- "Default": []byte(nil),
- "Oneof": nil,
+ "Cardinality": pref.Required,
+ "Default": []byte(nil),
+ "ContainingOneof": nil,
},
},
"Oneofs": M{
@@ -601,14 +617,20 @@
"Extensions": M{
"Len": 1,
"ByName:X": M{
- "Name": pref.Name("X"),
- "Number": pref.FieldNumber(1000),
- "Cardinality": pref.Repeated,
- "Kind": pref.MessageKind,
- "IsPacked": false,
- "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
- "Extendee": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
- "Options": &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
+ "Name": pref.Name("X"),
+ "Number": pref.FieldNumber(1000),
+ "Cardinality": pref.Repeated,
+ "Kind": pref.MessageKind,
+ "IsExtension": true,
+ "IsPacked": false,
+ "IsList": true,
+ "IsMap": false,
+ "MapKey": nil,
+ "MapValue": nil,
+ "ContainingOneof": nil,
+ "ContainingMessage": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
+ "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
+ "Options": &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
},
},
"Services": M{
@@ -768,7 +790,8 @@
HasJSONName: true
JSONName: "Field4"
IsMap: true
- Message: test.A
+ MapKey: string
+ MapValue: test.B
}, {
Name: field_five
Number: 5
@@ -776,6 +799,7 @@
Kind: int32
JSONName: "fieldFive"
IsPacked: true
+ IsList: true
}, {
Name: field_six
Number: 6
@@ -821,6 +845,8 @@
Number: 1000
Cardinality: repeated
Kind: message
+ IsExtension: true
+ IsList: true
Extendee: test.B
Message: test.C
}]
@@ -839,6 +865,8 @@
Number: 1000
Cardinality: repeated
Kind: message
+ IsExtension: true
+ IsList: true
Extendee: test.B
Message: test.C
}]
@@ -856,8 +884,8 @@
tests := []struct{ fmt, want string }{{"%v", compactMultiFormat(want)}, {"%+v", want}}
for _, tt := range tests {
got := fmt.Sprintf(tt.fmt, fd)
- if got != tt.want {
- t.Errorf("fmt.Sprintf(%q, fd):\ngot: %s\nwant: %s", tt.fmt, got, tt.want)
+ if diff := cmp.Diff(got, tt.want); diff != "" {
+ t.Errorf("fmt.Sprintf(%q, fd) mismatch (-got +want):\n%s", tt.fmt, diff)
}
}
}
diff --git a/internal/typefmt/desc_test.go b/internal/typefmt/desc_test.go
index 296131c..ab3f9b4 100644
--- a/internal/typefmt/desc_test.go
+++ b/internal/typefmt/desc_test.go
@@ -23,6 +23,12 @@
"DescriptorByName": true, // specific to FileDescriptor
"DefaultEnumValue": true, // specific to FieldDescriptor
+ "MapKey": true, // specific to FieldDescriptor
+ "MapValue": true, // specific to FieldDescriptor
+
+ // TODO: Remove this.
+ "Oneof": true, // specific to FieldDescriptor
+ "Extendee": true, // specific to FieldDescriptor
// TODO: These should be removed or handled.
"DescriptorProto": true,
diff --git a/internal/typefmt/stringer.go b/internal/typefmt/stringer.go
index eec6fd2..fdb1bdc 100644
--- a/internal/typefmt/stringer.go
+++ b/internal/typefmt/stringer.go
@@ -106,7 +106,7 @@
var descriptorAccessors = map[reflect.Type][]string{
reflect.TypeOf((*pref.FileDescriptor)(nil)).Elem(): {"Path", "Package", "Imports", "Messages", "Enums", "Extensions", "Services"},
reflect.TypeOf((*pref.MessageDescriptor)(nil)).Elem(): {"IsMapEntry", "Fields", "Oneofs", "ReservedNames", "ReservedRanges", "RequiredNumbers", "ExtensionRanges", "Messages", "Enums", "Extensions"},
- reflect.TypeOf((*pref.FieldDescriptor)(nil)).Elem(): {"Number", "Cardinality", "Kind", "HasJSONName", "JSONName", "IsPacked", "IsMap", "IsWeak", "HasDefault", "Default", "Oneof", "Extendee", "Message", "Enum"},
+ reflect.TypeOf((*pref.FieldDescriptor)(nil)).Elem(): {"Number", "Cardinality", "Kind", "HasJSONName", "JSONName", "IsPacked", "IsExtension", "IsWeak", "IsList", "IsMap", "MapKey", "MapValue", "HasDefault", "Default", "ContainingOneof", "ContainingMessage", "Message", "Enum"},
reflect.TypeOf((*pref.OneofDescriptor)(nil)).Elem(): {"Fields"}, // not directly used; must keep in sync with formatDescOpt
reflect.TypeOf((*pref.EnumDescriptor)(nil)).Elem(): {"Values", "ReservedNames", "ReservedRanges"},
reflect.TypeOf((*pref.EnumValueDescriptor)(nil)).Elem(): {"Number"},
@@ -143,7 +143,42 @@
default:
rs.Append(rv, "Name")
}
- if t, ok := t.(pref.OneofDescriptor); ok {
+ switch t := t.(type) {
+ case pref.FieldDescriptor:
+ for _, s := range descriptorAccessors[rt] {
+ switch s {
+ case "MapKey":
+ if k := t.MapKey(); k != nil {
+ rs.recs = append(rs.recs, [2]string{"MapKey", k.Kind().String()})
+ }
+ case "MapValue":
+ if v := t.MapValue(); v != nil {
+ switch v.Kind() {
+ case pref.EnumKind:
+ rs.recs = append(rs.recs, [2]string{"MapValue", string(v.Enum().FullName())})
+ case pref.MessageKind, pref.GroupKind:
+ rs.recs = append(rs.recs, [2]string{"MapValue", string(v.Message().FullName())})
+ default:
+ rs.recs = append(rs.recs, [2]string{"MapValue", v.Kind().String()})
+ }
+ }
+ case "ContainingOneof":
+ if od := t.ContainingOneof(); od != nil {
+ rs.recs = append(rs.recs, [2]string{"Oneof", string(od.Name())})
+ }
+ case "ContainingMessage":
+ if t.IsExtension() {
+ rs.recs = append(rs.recs, [2]string{"Extendee", string(t.ContainingMessage().FullName())})
+ }
+ case "Message":
+ if !t.IsMap() {
+ rs.Append(rv, s)
+ }
+ default:
+ rs.Append(rv, s)
+ }
+ }
+ case pref.OneofDescriptor:
var ss []string
fs := t.Fields()
for i := 0; i < fs.Len(); i++ {
@@ -152,7 +187,7 @@
if len(ss) > 0 {
rs.recs = append(rs.recs, [2]string{"Fields", "[" + joinStrings(ss, false) + "]"})
}
- } else {
+ default:
rs.Append(rv, descriptorAccessors[rt]...)
}
if rv.MethodByName("GoType").IsValid() {
diff --git a/proto/decode.go b/proto/decode.go
index 51b2068..37334be 100644
--- a/proto/decode.go
+++ b/proto/decode.go
@@ -105,12 +105,12 @@
switch {
case fieldDesc == nil:
err = errUnknown
- case fieldDesc.Cardinality() != protoreflect.Repeated:
- valLen, err = o.unmarshalScalarField(b[tagLen:], wtyp, num, knownFields, fieldDesc)
- case !fieldDesc.IsMap():
+ case fieldDesc.IsList():
valLen, err = o.unmarshalList(b[tagLen:], wtyp, num, knownFields.Get(num).List(), fieldDesc)
- default:
+ case fieldDesc.IsMap():
valLen, err = o.unmarshalMap(b[tagLen:], wtyp, num, knownFields.Get(num).Map(), fieldDesc)
+ default:
+ valLen, err = o.unmarshalScalarField(b[tagLen:], wtyp, num, knownFields, fieldDesc)
}
if err == errUnknown {
valLen = wire.ConsumeFieldValue(num, wtyp, b[tagLen:])
@@ -140,7 +140,7 @@
// TODO: C++ merges into oneofs, while v1 does not.
// Evaluate which behavior to pick.
var m protoreflect.Message
- if knownFields.Has(num) && field.Oneof() == nil {
+ if knownFields.Has(num) && field.ContainingOneof() == nil {
m = knownFields.Get(num).Message()
} else {
m = knownFields.NewMessage(num)
@@ -166,8 +166,8 @@
return 0, wire.ParseError(n)
}
var (
- keyField = field.Message().Fields().ByNumber(1)
- valField = field.Message().Fields().ByNumber(2)
+ keyField = field.MapKey()
+ valField = field.MapValue()
key protoreflect.Value
val protoreflect.Value
haveKey bool
diff --git a/proto/encode.go b/proto/encode.go
index 255d0a3..96d6799 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -176,25 +176,52 @@
}
}
-func (o MarshalOptions) marshalField(b []byte, field protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
- num := field.Number()
- kind := field.Kind()
+func (o MarshalOptions) marshalField(b []byte, fd protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
+ num := fd.Number()
+ kind := fd.Kind()
switch {
- case field.Cardinality() != protoreflect.Repeated:
- b = wire.AppendTag(b, num, wireTypes[kind])
- return o.marshalSingular(b, num, field, value)
- case field.IsMap():
- return o.marshalMap(b, num, kind, field.Message(), value.Map())
- case field.IsPacked():
- return o.marshalPacked(b, num, field, value.List())
+ case fd.IsList():
+ return o.marshalList(b, num, fd, value.List())
+ case fd.IsMap():
+ return o.marshalMap(b, num, fd, value.Map())
default:
- return o.marshalList(b, num, field, value.List())
+ b = wire.AppendTag(b, num, wireTypes[kind])
+ return o.marshalSingular(b, num, fd, value)
}
}
-func (o MarshalOptions) marshalMap(b []byte, num wire.Number, kind protoreflect.Kind, mdesc protoreflect.MessageDescriptor, mapv protoreflect.Map) ([]byte, error) {
- keyf := mdesc.Fields().ByNumber(1)
- valf := mdesc.Fields().ByNumber(2)
+func (o MarshalOptions) marshalList(b []byte, num wire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) ([]byte, error) {
+ if fd.IsPacked() {
+ b = wire.AppendTag(b, num, wire.BytesType)
+ b, pos := appendSpeculativeLength(b)
+ var nerr errors.NonFatal
+ for i, llen := 0, list.Len(); i < llen; i++ {
+ var err error
+ b, err = o.marshalSingular(b, num, fd, list.Get(i))
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ }
+ b = finishSpeculativeLength(b, pos)
+ return b, nerr.E
+ }
+
+ kind := fd.Kind()
+ var nerr errors.NonFatal
+ for i, llen := 0, list.Len(); i < llen; i++ {
+ var err error
+ b = wire.AppendTag(b, num, wireTypes[kind])
+ b, err = o.marshalSingular(b, num, fd, list.Get(i))
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ }
+ return b, nerr.E
+}
+
+func (o MarshalOptions) marshalMap(b []byte, num wire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) ([]byte, error) {
+ keyf := fd.MapKey()
+ valf := fd.MapValue()
var nerr errors.NonFatal
var err error
o.rangeMap(mapv, keyf.Kind(), func(key protoreflect.MapKey, value protoreflect.Value) bool {
@@ -229,35 +256,6 @@
mapsort.Range(mapv, kind, f)
}
-func (o MarshalOptions) marshalPacked(b []byte, num wire.Number, field protoreflect.FieldDescriptor, list protoreflect.List) ([]byte, error) {
- b = wire.AppendTag(b, num, wire.BytesType)
- b, pos := appendSpeculativeLength(b)
- var nerr errors.NonFatal
- for i, llen := 0, list.Len(); i < llen; i++ {
- var err error
- b, err = o.marshalSingular(b, num, field, list.Get(i))
- if !nerr.Merge(err) {
- return b, err
- }
- }
- b = finishSpeculativeLength(b, pos)
- return b, nerr.E
-}
-
-func (o MarshalOptions) marshalList(b []byte, num wire.Number, field protoreflect.FieldDescriptor, list protoreflect.List) ([]byte, error) {
- kind := field.Kind()
- var nerr errors.NonFatal
- for i, llen := 0, list.Len(); i < llen; i++ {
- var err error
- b = wire.AppendTag(b, num, wireTypes[kind])
- b, err = o.marshalSingular(b, num, field, list.Get(i))
- if !nerr.Merge(err) {
- return b, err
- }
- }
- return b, nerr.E
-}
-
// When encoding length-prefixed fields, we speculatively set aside some number of bytes
// for the length, encode the data, and then encode the length (shifting the data if necessary
// to make room).
diff --git a/proto/equal.go b/proto/equal.go
index 1b3c868..3931b1a 100644
--- a/proto/equal.go
+++ b/proto/equal.go
@@ -98,10 +98,10 @@
// equalFields compares two fields.
func equalFields(fd pref.FieldDescriptor, a, b pref.Value) bool {
switch {
+ case fd.IsList():
+ return equalList(fd, a.List(), b.List())
case fd.IsMap():
return equalMap(fd, a.Map(), b.Map())
- case fd.Cardinality() == pref.Repeated:
- return equalList(fd, a.List(), b.List())
default:
return equalValue(fd, a, b)
}
@@ -109,7 +109,6 @@
// equalMap compares a map field.
func equalMap(fd pref.FieldDescriptor, a, b pref.Map) bool {
- fdv := fd.Message().Fields().ByNumber(2)
alen := a.Len()
if alen != b.Len() {
return false
@@ -117,7 +116,7 @@
equal := true
a.Range(func(k pref.MapKey, va pref.Value) bool {
vb := b.Get(k)
- if !vb.IsValid() || !equalValue(fdv, va, vb) {
+ if !vb.IsValid() || !equalValue(fd.MapValue(), va, vb) {
equal = false
return false
}
diff --git a/proto/isinit.go b/proto/isinit.go
index 199f181..01f956d 100644
--- a/proto/isinit.go
+++ b/proto/isinit.go
@@ -53,20 +53,14 @@
return true
}
if field.IsMap() {
- if md.Fields().ByNumber(2).Message() == nil {
+ if field.MapValue().Message() == nil {
return true
}
}
// Recurse into the field
stack := append(stack, field.Name())
switch {
- case field.IsMap():
- v.Map().Range(func(key pref.MapKey, v pref.Value) bool {
- stack := append(stack, "[", key, "].")
- err = isInitialized(v.Message(), stack)
- return err == nil
- })
- case field.Cardinality() == pref.Repeated:
+ case field.IsList():
for i, list := 0, v.List(); i < list.Len(); i++ {
stack := append(stack, "[", i, "].")
err = isInitialized(list.Get(i).Message(), stack)
@@ -74,6 +68,12 @@
break
}
}
+ case field.IsMap():
+ v.Map().Range(func(key pref.MapKey, v pref.Value) bool {
+ stack := append(stack, "[", key, "].")
+ err = isInitialized(v.Message(), stack)
+ return err == nil
+ })
default:
stack := append(stack, ".")
err = isInitialized(v.Message(), stack)
diff --git a/proto/size.go b/proto/size.go
index b881653..e2a75b6 100644
--- a/proto/size.go
+++ b/proto/size.go
@@ -54,43 +54,38 @@
return size
}
-func sizeField(field protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
- num := field.Number()
- kind := field.Kind()
+func sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
+ num := fd.Number()
switch {
- case field.Cardinality() != protoreflect.Repeated:
- return wire.SizeTag(num) + sizeSingular(num, kind, value)
- case field.IsMap():
- return sizeMap(num, kind, field.Message(), value.Map())
- case field.IsPacked():
- return sizePacked(num, kind, value.List())
+ case fd.IsList():
+ return sizeList(num, fd, value.List())
+ case fd.IsMap():
+ return sizeMap(num, fd, value.Map())
default:
- return sizeList(num, kind, value.List())
+ return wire.SizeTag(num) + sizeSingular(num, fd.Kind(), value)
}
}
-func sizeMap(num wire.Number, kind protoreflect.Kind, mdesc protoreflect.MessageDescriptor, mapv protoreflect.Map) (size int) {
- keyf := mdesc.Fields().ByNumber(1)
- valf := mdesc.Fields().ByNumber(2)
- mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
- size += wire.SizeTag(num)
- size += wire.SizeBytes(sizeField(keyf, key.Value()) + sizeField(valf, value))
- return true
- })
+func sizeList(num wire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) {
+ if fd.IsPacked() {
+ content := 0
+ for i, llen := 0, list.Len(); i < llen; i++ {
+ content += sizeSingular(num, fd.Kind(), list.Get(i))
+ }
+ return wire.SizeTag(num) + wire.SizeBytes(content)
+ }
+
+ for i, llen := 0, list.Len(); i < llen; i++ {
+ size += wire.SizeTag(num) + sizeSingular(num, fd.Kind(), list.Get(i))
+ }
return size
}
-func sizePacked(num wire.Number, kind protoreflect.Kind, list protoreflect.List) (size int) {
- content := 0
- for i, llen := 0, list.Len(); i < llen; i++ {
- content += sizeSingular(num, kind, list.Get(i))
- }
- return wire.SizeTag(num) + wire.SizeBytes(content)
-}
-
-func sizeList(num wire.Number, kind protoreflect.Kind, list protoreflect.List) (size int) {
- for i, llen := 0, list.Len(); i < llen; i++ {
- size += wire.SizeTag(num) + sizeSingular(num, kind, list.Get(i))
- }
+func sizeMap(num wire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) {
+ mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
+ size += wire.SizeTag(num)
+ size += wire.SizeBytes(sizeField(fd.MapKey(), key.Value()) + sizeField(fd.MapValue(), value))
+ return true
+ })
return size
}
diff --git a/protogen/protogen.go b/protogen/protogen.go
index 41c2392..d84c6d0 100644
--- a/protogen/protogen.go
+++ b/protogen/protogen.go
@@ -637,9 +637,9 @@
func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDescriptor) *Field {
var loc Location
switch {
- case desc.Extendee() != nil && message == nil:
+ case desc.IsExtension() && message == nil:
loc = f.location(fieldnum.FileDescriptorProto_Extension, int32(desc.Index()))
- case desc.Extendee() != nil && message != nil:
+ case desc.IsExtension() && message != nil:
loc = message.Location.appendPath(fieldnum.DescriptorProto_Extension, int32(desc.Index()))
default:
loc = message.Location.appendPath(fieldnum.DescriptorProto_Field, int32(desc.Index()))
@@ -650,8 +650,8 @@
Parent: message,
Location: loc,
}
- if desc.Oneof() != nil {
- field.Oneof = message.Oneofs[desc.Oneof().Index()]
+ if desc.ContainingOneof() != nil {
+ field.Oneof = message.Oneofs[desc.ContainingOneof().Index()]
}
return field
}
@@ -677,8 +677,8 @@
}
field.Enum = enum
}
- if desc.Extendee() != nil {
- mname := desc.Extendee().FullName()
+ if desc.IsExtension() {
+ mname := desc.ContainingMessage().FullName()
message, ok := gen.messagesByName[mname]
if !ok {
return fmt.Errorf("field %v: no descriptor for type %v", desc.FullName(), mname)
diff --git a/reflect/protodesc/toproto.go b/reflect/protodesc/toproto.go
index ad288a2..cba59db 100644
--- a/reflect/protodesc/toproto.go
+++ b/reflect/protodesc/toproto.go
@@ -96,12 +96,14 @@
// google.protobuf.FieldDescriptorProto.
func ToFieldDescriptorProto(field protoreflect.FieldDescriptor) *descriptorpb.FieldDescriptorProto {
p := &descriptorpb.FieldDescriptorProto{
- Name: scalar.String(string(field.Name())),
- Number: scalar.Int32(int32(field.Number())),
- Label: descriptorpb.FieldDescriptorProto_Label(field.Cardinality()).Enum(),
- Type: descriptorpb.FieldDescriptorProto_Type(field.Kind()).Enum(),
- Extendee: fullNameOf(field.Extendee()),
- Options: field.Options().(*descriptorpb.FieldOptions),
+ Name: scalar.String(string(field.Name())),
+ Number: scalar.Int32(int32(field.Number())),
+ Label: descriptorpb.FieldDescriptorProto_Label(field.Cardinality()).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(field.Kind()).Enum(),
+ Options: field.Options().(*descriptorpb.FieldOptions),
+ }
+ if field.IsExtension() {
+ p.Extendee = fullNameOf(field.ContainingMessage())
}
switch field.Kind() {
case protoreflect.EnumKind:
@@ -125,7 +127,7 @@
p.DefaultValue = scalar.String(def)
}
}
- if oneof := field.Oneof(); oneof != nil {
+ if oneof := field.ContainingOneof(); oneof != nil {
p.OneofIndex = scalar.Int32(int32(oneof.Index()))
}
return p
diff --git a/reflect/protoreflect/type.go b/reflect/protoreflect/type.go
index 3971b44..231c18e 100644
--- a/reflect/protoreflect/type.go
+++ b/reflect/protoreflect/type.go
@@ -285,23 +285,41 @@
// It is usually the camel-cased form of the field name.
JSONName() string
- // IsPacked reports whether repeated primitive numeric kinds should be
- // serialized using a packed encoding.
- // If true, then it implies Cardinality is Repeated.
- IsPacked() bool
+ // IsExtension reports whether this is an extension field. If false,
+ // then Parent and ContainingMessage refer to the same message.
+ // Otherwise, ContainingMessage and Parent almost certainly differ.
+ IsExtension() bool
// IsWeak reports whether this is a weak field, which does not impose a
// direct dependency on the target type.
// If true, then MessageDescriptor returns a placeholder type.
IsWeak() bool
- // IsMap reports whether this field represents a map.
- // The value type for the associated field is a Map instead of a List.
- //
- // If true, it implies that Kind is MessageKind, Cardinality is Repeated,
- // and MessageDescriptor.IsMapEntry is true.
+ // IsPacked reports whether repeated primitive numeric kinds should be
+ // serialized using a packed encoding.
+ // If true, then it implies Cardinality is Repeated.
+ IsPacked() bool
+
+ // IsList reports whether this field represents a list,
+ // where the value type for the associated field is a List.
+ // It is equivalent to checking whether Cardinality is Repeated and
+ // that IsMap reports false.
+ IsList() bool
+
+ // IsMap reports whether this field represents a map,
+ // where the value type for the associated field is a Map.
+ // It is equivalent to checking whether Cardinality is Repeated,
+ // that the Kind is MessageKind, and that Message.IsMapEntry reports true.
IsMap() bool
+ // MapKey returns the field descriptor for the key in the map entry.
+ // It returns nil if IsMap reports false.
+ MapKey() FieldDescriptor
+
+ // MapValue returns the field descriptor for the value in the map entry.
+ // It returns nil if IsMap reports false.
+ MapValue() FieldDescriptor
+
// HasDefault reports whether this field has a default value.
HasDefault() bool
@@ -312,19 +330,26 @@
// The Value type is determined by the Kind.
Default() Value
- // DefaultEnumValue returns the EnumValueDescriptor for the default value
+ // DefaultEnumValue returns the enum value descriptor for the default value
// of an enum field, and is nil for any other kind of field.
DefaultEnumValue() EnumValueDescriptor
- // Oneof is the containing oneof that this field belongs to,
- // and is nil if this field is not part of a oneof.
+ // TODO: Remove this.
+ // Deprecated: Use ContainingOneof instead.
Oneof() OneofDescriptor
-
- // Extendee returns a message descriptor for the extended message
- // that this extension field belongs in.
- // It returns nil if this field is not an extension.
+ // TODO: Remove this.
+ // Deprecated: Use ContainingMessage instead.
Extendee() MessageDescriptor
+ // ContainingOneof is the containing oneof that this field belongs to,
+ // and is nil if this field is not part of a oneof.
+ ContainingOneof() OneofDescriptor
+
+ // ContainingMessage is the containing message that this field belongs to.
+ // For extension fields, this may not necessarily be the parent message
+ // that the field is declared within.
+ ContainingMessage() MessageDescriptor
+
// Enum is the enum descriptor if Kind is EnumKind.
// It returns nil for any other Kind.
Enum() EnumDescriptor
diff --git a/reflect/protoregistry/registry.go b/reflect/protoregistry/registry.go
index 84e276a..9d021de 100644
--- a/reflect/protoregistry/registry.go
+++ b/reflect/protoregistry/registry.go
@@ -381,7 +381,7 @@
// Check for conflicts in extensionsByMessage.
if xt, _ := typ.(protoreflect.ExtensionType); xt != nil {
field := xt.Descriptor().Number()
- message := xt.Descriptor().Extendee().FullName()
+ message := xt.Descriptor().ContainingMessage().FullName()
if r.extensionsByMessage[message][field] != nil {
if firstErr == nil {
firstErr = errors.New("extension %v is already registered on message %v", name, message)
diff --git a/testing/prototest/prototest.go b/testing/prototest/prototest.go
index f3a1a9f..058ef24 100644
--- a/testing/prototest/prototest.go
+++ b/testing/prototest/prototest.go
@@ -26,10 +26,10 @@
for i := 0; i < md.Fields().Len(); i++ {
fd := md.Fields().Get(i)
switch {
+ case fd.IsList():
+ testFieldList(t, m, fd)
case fd.IsMap():
testFieldMap(t, m, fd)
- case fd.Cardinality() == pref.Repeated:
- testFieldList(t, m, fd)
case fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind:
testFieldFloat(t, m, fd)
}
@@ -105,7 +105,7 @@
if fd.Cardinality() == pref.Repeated {
wantHas = false
}
- if fd.Oneof() != nil {
+ if fd.ContainingOneof() != nil {
wantHas = true
}
}
@@ -122,12 +122,12 @@
t.Errorf("after clearing %q:\nHas(%v) = %v, want %v", name, num, got, want)
}
switch {
- case fd.IsMap():
- if got := known.Get(num); got.Map().Len() != 0 {
+ case fd.IsList():
+ if got := known.Get(num); got.List().Len() != 0 {
t.Errorf("after clearing %q:\nGet(%v) = %v, want empty list", name, num, formatValue(got))
}
- case fd.Cardinality() == pref.Repeated:
- if got := known.Get(num); got.List().Len() != 0 {
+ case fd.IsMap():
+ if got := known.Get(num); got.Map().Len() != 0 {
t.Errorf("after clearing %q:\nGet(%v) = %v, want empty list", name, num, formatValue(got))
}
default:
@@ -421,6 +421,16 @@
func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
num := fd.Number()
switch {
+ case fd.IsList():
+ list := m.New().KnownFields().Get(num).List()
+ if n == 0 {
+ return pref.ValueOf(list)
+ }
+ list.Append(newListElement(fd, list, 0, stack))
+ list.Append(newListElement(fd, list, minVal, stack))
+ list.Append(newListElement(fd, list, maxVal, stack))
+ list.Append(newListElement(fd, list, n, stack))
+ return pref.ValueOf(list)
case fd.IsMap():
mapv := m.New().KnownFields().Get(num).Map()
if n == 0 {
@@ -431,16 +441,6 @@
mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, 10*n, stack))
return pref.ValueOf(mapv)
- case fd.Cardinality() == pref.Repeated:
- list := m.New().KnownFields().Get(num).List()
- if n == 0 {
- return pref.ValueOf(list)
- }
- list.Append(newListElement(fd, list, 0, stack))
- list.Append(newListElement(fd, list, minVal, stack))
- list.Append(newListElement(fd, list, maxVal, stack))
- list.Append(newListElement(fd, list, n, stack))
- return pref.ValueOf(list)
case fd.Message() != nil:
return populateMessage(m.KnownFields().NewMessage(num), n, stack)
default:
@@ -456,12 +456,12 @@
}
func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
- kd := fd.Message().Fields().ByNumber(1)
+ kd := fd.MapKey()
return newScalarValue(kd, n).MapKey()
}
func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
- vd := fd.Message().Fields().ByNumber(2)
+ vd := fd.MapValue()
if vd.Message() == nil {
return newScalarValue(vd, n)
}