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>
This commit is contained in:
Joe Tsai 2019-05-13 14:32:56 -07:00 committed by Joe Tsai
parent 67c1d9b2c1
commit ac31a352ca
32 changed files with 519 additions and 402 deletions

View File

@ -559,20 +559,21 @@ func fieldGoType(g *protogen.GeneratedFile, field *protogen.Field) (goType strin
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 fieldProtobufTag(field *protogen.Field) string {
}
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 @@ func genExtensions(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo)
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:

View File

@ -49,13 +49,12 @@ func fillMessage(m pref.Message, level int) {
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)
}
}

View File

@ -244,14 +244,20 @@ Loop:
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 @@ func unmarshalEnum(jval json.Value, fd pref.FieldDescriptor) (pref.Value, error)
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 @@ func (o UnmarshalOptions) unmarshalList(list pref.List, fd pref.FieldDescriptor)
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 @@ func (o UnmarshalOptions) unmarshalMap(mmap pref.Map, fd pref.FieldDescriptor) e
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 @@ func (o UnmarshalOptions) unmarshalMap(mmap pref.Map, fd pref.FieldDescriptor) e
}
return pref.ValueOf(m), nerr.E
}
default:
unmarshalMapValue = func() (pref.Value, error) {
return o.unmarshalScalar(fd.MapValue())
}
}
Loop:
@ -666,7 +650,7 @@ Loop:
}
// Unmarshal field name.
pkey, err := unmarshalMapKey(name, keyDesc)
pkey, err := unmarshalMapKey(name, fd.MapKey())
if !nerr.Merge(err) {
return err
}

View File

@ -118,25 +118,14 @@ func (o MarshalOptions) marshalFields(m pref.Message) error {
// 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 @@ func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error
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 @@ func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error
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 @@ func isMessageSetExtension(xt pref.ExtensionType) bool {
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()
}

View File

@ -159,14 +159,36 @@ func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message)
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 @@ func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescr
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 @@ func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDes
// 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 @@ func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescript
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
}

View File

@ -132,28 +132,26 @@ func (o MarshalOptions) marshalMessage(m pref.Message) (text.Value, error) {
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 @@ func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) ([]te
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 @@ func isMessageSetExtension(xt pref.ExtensionType) bool {
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()
}

View File

@ -175,13 +175,13 @@ func Marshal(fd pref.FieldDescriptor, enumName string) string {
// 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.

View File

@ -431,23 +431,43 @@ func (md messageDescriptor) Options() pref.ProtoMessage { return md.options()
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) Kind() pref.Kind { return xd
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 @@ func (xd *extensionDesc) ProtoLegacyExtensionDesc() *piface.ExtensionDescV1 {
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

View File

@ -88,7 +88,7 @@ func visitFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor)) {
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)
}

View File

@ -64,7 +64,7 @@ func (p legacyExtensionFields) Has(n pref.FieldNumber) bool {
}
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 @@ func (p legacyExtensionFields) Clear(n pref.FieldNumber) {
}
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) Len() (n int) {
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 @@ func (p legacyExtensionTypes) Register(t pref.ExtensionType) {
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 @@ func (p legacyExtensionTypes) Remove(t pref.ExtensionType) {
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 {

View File

@ -685,7 +685,7 @@ func TestExtensionConvert(t *testing.T) {
// 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 @@ func TestExtensionConvert(t *testing.T) {
if !v.IsNil() {
out[name] = v.Interface().(pref.Descriptor).FullName()
}
case "Oneof", "Extendee":
// TODO: Remove this.
default:
out[name] = m.Call(nil)[0].Interface()
}

View File

@ -118,11 +118,11 @@ func (mi *MessageType) makeKnownFieldsFunc(si structInfo) {
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)

View File

@ -90,8 +90,8 @@ func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo
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{

View File

@ -65,7 +65,8 @@ func extensionDescFromType(xt pref.ExtensionType) *piface.ExtensionDescV1 {
// 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)

View File

@ -433,7 +433,7 @@ func TestDescriptor(t *testing.T) {
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 @@ func TestDescriptor(t *testing.T) {
if !v.IsNil() {
out[name] = v.Interface().(pref.Descriptor).FullName()
}
case "Oneof", "Extendee":
// TODO: Remove this.
default:
out[name] = m.Call(nil)[0].Interface()
}

View File

@ -124,7 +124,7 @@ func (t *goMessage) Format(s fmt.State, r rune) {
// 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() {

View File

@ -114,7 +114,7 @@ func (p *oneofFieldsMeta) lazyInit(parent pref.Descriptor) *oneofFields {
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)
}
}

View File

@ -171,21 +171,43 @@ func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f
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 @@ func (t extensionDesc) IsPacked() bool {
// 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

View File

@ -85,17 +85,25 @@ func (t standaloneExtension) JSONName() string { return "" }
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 }

View File

@ -18,6 +18,7 @@ import (
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 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"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 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"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 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"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 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"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 @@ func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
HasJSONName: true
JSONName: "Field4"
IsMap: true
Message: test.A
MapKey: string
MapValue: test.B
}, {
Name: field_five
Number: 5
@ -776,6 +799,7 @@ func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
Kind: int32
JSONName: "fieldFive"
IsPacked: true
IsList: true
}, {
Name: field_six
Number: 6
@ -821,6 +845,8 @@ func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
Number: 1000
Cardinality: repeated
Kind: message
IsExtension: true
IsList: true
Extendee: test.B
Message: test.C
}]
@ -839,6 +865,8 @@ func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
Number: 1000
Cardinality: repeated
Kind: message
IsExtension: true
IsList: true
Extendee: test.B
Message: test.C
}]
@ -856,8 +884,8 @@ func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
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)
}
}
}

View File

@ -23,6 +23,12 @@ func TestDescriptorAccessors(t *testing.T) {
"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,

View File

@ -106,7 +106,7 @@ func formatListOpt(vs list, isRoot, allowMulti bool) string {
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 @@ func formatDescOpt(t pref.Descriptor, isRoot, allowMulti bool) string {
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 @@ func formatDescOpt(t pref.Descriptor, isRoot, allowMulti bool) string {
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() {

View File

@ -105,12 +105,12 @@ func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) err
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 @@ func (o UnmarshalOptions) unmarshalScalarField(b []byte, wtyp wire.Type, num wir
// 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 @@ func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp wire.Type, num wire.Number
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

View File

@ -176,25 +176,52 @@ func (o MarshalOptions) rangeKnown(knownFields protoreflect.KnownFields, f func(
}
}
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 @@ func (o MarshalOptions) rangeMap(mapv protoreflect.Map, kind protoreflect.Kind,
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).

View File

@ -98,10 +98,10 @@ func equalMessage(a, b pref.Message) bool {
// 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 @@ func equalFields(fd pref.FieldDescriptor, a, b pref.Value) bool {
// 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 @@ func equalMap(fd pref.FieldDescriptor, a, b pref.Map) bool {
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
}

View File

@ -53,20 +53,14 @@ func isInitialized(m pref.Message, stack []interface{}) error {
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 @@ func isInitialized(m pref.Message, stack []interface{}) error {
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)

View File

@ -54,43 +54,38 @@ func sizeMessage(m protoreflect.Message) (size int) {
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)
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 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(keyf, key.Value()) + sizeField(valf, value))
size += wire.SizeBytes(sizeField(fd.MapKey(), key.Value()) + sizeField(fd.MapValue(), value))
return true
})
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))
}
return size
}

View File

@ -637,9 +637,9 @@ type Field struct {
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 @@ func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDes
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 @@ func (field *Field) init(gen *Plugin) error {
}
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)

View File

@ -96,12 +96,14 @@ func ToDescriptorProto(message protoreflect.MessageDescriptor) *descriptorpb.Des
// 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 @@ func ToFieldDescriptorProto(field protoreflect.FieldDescriptor) *descriptorpb.Fi
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

View File

@ -285,23 +285,41 @@ type FieldDescriptor interface {
// 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 @@ type FieldDescriptor interface {
// 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

View File

@ -381,7 +381,7 @@ typeLoop:
// 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)

View File

@ -26,10 +26,10 @@ func TestMessage(t testing.TB, message proto.Message) {
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 @@ func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
if fd.Cardinality() == pref.Repeated {
wantHas = false
}
if fd.Oneof() != nil {
if fd.ContainingOneof() != nil {
wantHas = true
}
}
@ -122,12 +122,12 @@ func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
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 @@ const (
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 @@ func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.Mess
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 newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pre
}
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)
}