mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-27 03:35:32 +00:00
fa02f4eaa6
This provides an implementation of the has, get, set, clear methods for each field in a message. The approach taken here is similar to the table-driven implementation in the current v1 proto package. The pointer_reflect.go and pointer_unsafe.go files are a simplified version of the same files in the v1 implementation. They provide a pointer abstraction that enables a high-efficiency approach in a non-purego environment. The unsafe fast-path is not implemented in this commit. This commit only implements the accessor methods for scalars using pure Go reflection. Change-Id: Icdf707e9d4e3385e55434f93b30a341a7680ae11 Reviewed-on: https://go-review.googlesource.com/135136 Reviewed-by: Damien Neil <dneil@google.com>
92 lines
2.9 KiB
Go
92 lines
2.9 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package impl
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
pref "google.golang.org/proto/reflect/protoreflect"
|
|
)
|
|
|
|
type MessageInfo struct {
|
|
// TODO: Split fields into dense and sparse maps similar to the current
|
|
// table-driven implementation in v1?
|
|
fields map[pref.FieldNumber]*fieldInfo
|
|
}
|
|
|
|
// generateFieldFuncs generates per-field functions for all common operations
|
|
// to be performed on each field. It takes in a reflect.Type representing the
|
|
// Go struct, and a protoreflect.MessageDescriptor to match with the fields
|
|
// in the struct.
|
|
//
|
|
// This code assumes that the struct is well-formed and panics if there are
|
|
// any discrepancies.
|
|
func (mi *MessageInfo) generateFieldFuncs(t reflect.Type, md pref.MessageDescriptor) {
|
|
// Generate a mapping of field numbers and names to Go struct field or type.
|
|
fields := map[pref.FieldNumber]reflect.StructField{}
|
|
oneofs := map[pref.Name]reflect.StructField{}
|
|
oneofFields := map[pref.FieldNumber]reflect.Type{}
|
|
special := map[string]reflect.StructField{}
|
|
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)
|
|
fields[pref.FieldNumber(n)] = f
|
|
continue fieldLoop
|
|
}
|
|
}
|
|
if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
|
|
oneofs[pref.Name(s)] = f
|
|
continue fieldLoop
|
|
}
|
|
switch f.Name {
|
|
case "XXX_weak", "XXX_unrecognized", "XXX_sizecache", "XXX_extensions", "XXX_InternalExtensions":
|
|
special[f.Name] = f
|
|
continue fieldLoop
|
|
}
|
|
}
|
|
if fn, ok := t.MethodByName("XXX_OneofFuncs"); ok {
|
|
vs := fn.Func.Call([]reflect.Value{reflect.New(fn.Type.In(0)).Elem()})[3]
|
|
oneofLoop:
|
|
for _, v := range vs.Interface().([]interface{}) {
|
|
tf := reflect.TypeOf(v).Elem()
|
|
f := tf.Field(0)
|
|
for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
|
|
if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
|
|
n, _ := strconv.ParseUint(s, 10, 64)
|
|
oneofFields[pref.FieldNumber(n)] = tf
|
|
continue oneofLoop
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mi.fields = map[pref.FieldNumber]*fieldInfo{}
|
|
for i := 0; i < md.Fields().Len(); i++ {
|
|
fd := md.Fields().Get(i)
|
|
fs := fields[fd.Number()]
|
|
var fi fieldInfo
|
|
switch {
|
|
case fd.IsWeak():
|
|
fi = fieldInfoForWeak(fd, special["XXX_weak"])
|
|
case fd.OneofType() != nil:
|
|
fi = fieldInfoForOneof(fd, oneofs[fd.OneofType().Name()], oneofFields[fd.Number()])
|
|
case fd.IsMap():
|
|
fi = fieldInfoForMap(fd, fs)
|
|
case fd.Cardinality() == pref.Repeated:
|
|
fi = fieldInfoForVector(fd, fs)
|
|
case fd.Kind() != pref.MessageKind && fd.Kind() != pref.GroupKind:
|
|
fi = fieldInfoForScalar(fd, fs)
|
|
default:
|
|
fi = fieldInfoForMessage(fd, fs)
|
|
}
|
|
mi.fields[fd.Number()] = &fi
|
|
}
|
|
}
|