internal/impl: pull out message struct info into a type

Minor refactoring of impl.MessageType initialization: Pull the
information gathered about a message struct by makeKnownFieldsFunc out
into a struct that we can pass around.

At the moment, makeKnownFieldsFunc is the only user of this struct, but
this will simplify the table (un)marshaler.

Drop the 'specialByName' map indexing XXX_ fields because it currently
isn't used anywhere.

Change-Id: I992c9f490982a05f3919d7d4e08052e2ab54d44d
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/176220
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
Damien Neil 2019-05-09 11:33:55 -07:00
parent 00a323deed
commit 3eaddf0344

View File

@ -46,44 +46,40 @@ func (mi *MessageType) init() {
panic(fmt.Sprintf("got %v, want *struct kind", t))
}
mi.makeKnownFieldsFunc(t.Elem())
si := mi.makeStructInfo(t.Elem())
mi.makeKnownFieldsFunc(si)
mi.makeUnknownFieldsFunc(t.Elem())
mi.makeExtensionFieldsFunc(t.Elem())
})
}
// makeKnownFieldsFunc generates functions for operations that can be performed
// on each protobuf message field. It takes in a reflect.Type representing the
// Go struct and matches message fields with struct fields.
//
// This code assumes that the struct is well-formed and panics if there are
// any discrepancies.
func (mi *MessageType) makeKnownFieldsFunc(t reflect.Type) {
type structInfo struct {
fieldsByNumber map[pref.FieldNumber]reflect.StructField
oneofsByName map[pref.Name]reflect.StructField
oneofWrappersByType map[reflect.Type]pref.FieldNumber
oneofWrappersByNumber map[pref.FieldNumber]reflect.Type
}
func (mi *MessageType) makeStructInfo(t reflect.Type) structInfo {
// Generate a mapping of field numbers and names to Go struct field or type.
var (
fieldsByNumber = map[pref.FieldNumber]reflect.StructField{}
oneofsByName = map[pref.Name]reflect.StructField{}
oneofWrappersByType = map[reflect.Type]pref.FieldNumber{}
oneofWrappersByNumber = map[pref.FieldNumber]reflect.Type{}
specialByName = map[string]reflect.StructField{}
)
si := structInfo{
fieldsByNumber: map[pref.FieldNumber]reflect.StructField{},
oneofsByName: map[pref.Name]reflect.StructField{},
oneofWrappersByType: map[reflect.Type]pref.FieldNumber{},
oneofWrappersByNumber: map[pref.FieldNumber]reflect.Type{},
}
fieldLoop:
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
n, _ := strconv.ParseUint(s, 10, 64)
fieldsByNumber[pref.FieldNumber(n)] = f
si.fieldsByNumber[pref.FieldNumber(n)] = f
continue fieldLoop
}
}
if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
oneofsByName[pref.Name(s)] = f
continue fieldLoop
}
switch f.Name {
case "XXX_weak", "XXX_unrecognized", "XXX_sizecache", "XXX_extensions", "XXX_InternalExtensions":
specialByName[f.Name] = f
si.oneofsByName[pref.Name(s)] = f
continue fieldLoop
}
}
@ -100,21 +96,30 @@ fieldLoop:
for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
n, _ := strconv.ParseUint(s, 10, 64)
oneofWrappersByType[tf] = pref.FieldNumber(n)
oneofWrappersByNumber[pref.FieldNumber(n)] = tf
si.oneofWrappersByType[tf] = pref.FieldNumber(n)
si.oneofWrappersByNumber[pref.FieldNumber(n)] = tf
break
}
}
}
return si
}
// makeKnownFieldsFunc generates functions for operations that can be performed
// on each protobuf message field. It takes in a reflect.Type representing the
// Go struct and matches message fields with struct fields.
//
// This code assumes that the struct is well-formed and panics if there are
// any discrepancies.
func (mi *MessageType) makeKnownFieldsFunc(si structInfo) {
mi.fields = map[pref.FieldNumber]*fieldInfo{}
for i := 0; i < mi.PBType.Fields().Len(); i++ {
fd := mi.PBType.Fields().Get(i)
fs := fieldsByNumber[fd.Number()]
fs := si.fieldsByNumber[fd.Number()]
var fi fieldInfo
switch {
case fd.Oneof() != nil:
fi = fieldInfoForOneof(fd, oneofsByName[fd.Oneof().Name()], oneofWrappersByNumber[fd.Number()])
fi = fieldInfoForOneof(fd, si.oneofsByName[fd.Oneof().Name()], si.oneofWrappersByNumber[fd.Number()])
case fd.IsMap():
fi = fieldInfoForMap(fd, fs)
case fd.Cardinality() == pref.Repeated:
@ -130,7 +135,7 @@ fieldLoop:
mi.oneofs = map[pref.Name]*oneofInfo{}
for i := 0; i < mi.PBType.Oneofs().Len(); i++ {
od := mi.PBType.Oneofs().Get(i)
mi.oneofs[od.Name()] = makeOneofInfo(od, oneofsByName[od.Name()], oneofWrappersByType)
mi.oneofs[od.Name()] = makeOneofInfo(od, si.oneofsByName[od.Name()], si.oneofWrappersByType)
}
}