vendor/google.golang.org/protobuf/internal/impl/message.go
changeset 256 6d9efbef00a9
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
       
     1 // Copyright 2018 The Go Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style
       
     3 // license that can be found in the LICENSE file.
       
     4 
       
     5 package impl
       
     6 
       
     7 import (
       
     8 	"fmt"
       
     9 	"reflect"
       
    10 	"strconv"
       
    11 	"strings"
       
    12 	"sync"
       
    13 	"sync/atomic"
       
    14 
       
    15 	"google.golang.org/protobuf/internal/genid"
       
    16 	"google.golang.org/protobuf/reflect/protoreflect"
       
    17 	pref "google.golang.org/protobuf/reflect/protoreflect"
       
    18 	preg "google.golang.org/protobuf/reflect/protoregistry"
       
    19 )
       
    20 
       
    21 // MessageInfo provides protobuf related functionality for a given Go type
       
    22 // that represents a message. A given instance of MessageInfo is tied to
       
    23 // exactly one Go type, which must be a pointer to a struct type.
       
    24 //
       
    25 // The exported fields must be populated before any methods are called
       
    26 // and cannot be mutated after set.
       
    27 type MessageInfo struct {
       
    28 	// GoReflectType is the underlying message Go type and must be populated.
       
    29 	GoReflectType reflect.Type // pointer to struct
       
    30 
       
    31 	// Desc is the underlying message descriptor type and must be populated.
       
    32 	Desc pref.MessageDescriptor
       
    33 
       
    34 	// Exporter must be provided in a purego environment in order to provide
       
    35 	// access to unexported fields.
       
    36 	Exporter exporter
       
    37 
       
    38 	// OneofWrappers is list of pointers to oneof wrapper struct types.
       
    39 	OneofWrappers []interface{}
       
    40 
       
    41 	initMu   sync.Mutex // protects all unexported fields
       
    42 	initDone uint32
       
    43 
       
    44 	reflectMessageInfo // for reflection implementation
       
    45 	coderMessageInfo   // for fast-path method implementations
       
    46 }
       
    47 
       
    48 // exporter is a function that returns a reference to the ith field of v,
       
    49 // where v is a pointer to a struct. It returns nil if it does not support
       
    50 // exporting the requested field (e.g., already exported).
       
    51 type exporter func(v interface{}, i int) interface{}
       
    52 
       
    53 // getMessageInfo returns the MessageInfo for any message type that
       
    54 // is generated by our implementation of protoc-gen-go (for v2 and on).
       
    55 // If it is unable to obtain a MessageInfo, it returns nil.
       
    56 func getMessageInfo(mt reflect.Type) *MessageInfo {
       
    57 	m, ok := reflect.Zero(mt).Interface().(pref.ProtoMessage)
       
    58 	if !ok {
       
    59 		return nil
       
    60 	}
       
    61 	mr, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *MessageInfo })
       
    62 	if !ok {
       
    63 		return nil
       
    64 	}
       
    65 	return mr.ProtoMessageInfo()
       
    66 }
       
    67 
       
    68 func (mi *MessageInfo) init() {
       
    69 	// This function is called in the hot path. Inline the sync.Once logic,
       
    70 	// since allocating a closure for Once.Do is expensive.
       
    71 	// Keep init small to ensure that it can be inlined.
       
    72 	if atomic.LoadUint32(&mi.initDone) == 0 {
       
    73 		mi.initOnce()
       
    74 	}
       
    75 }
       
    76 
       
    77 func (mi *MessageInfo) initOnce() {
       
    78 	mi.initMu.Lock()
       
    79 	defer mi.initMu.Unlock()
       
    80 	if mi.initDone == 1 {
       
    81 		return
       
    82 	}
       
    83 
       
    84 	t := mi.GoReflectType
       
    85 	if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
       
    86 		panic(fmt.Sprintf("got %v, want *struct kind", t))
       
    87 	}
       
    88 	t = t.Elem()
       
    89 
       
    90 	si := mi.makeStructInfo(t)
       
    91 	mi.makeReflectFuncs(t, si)
       
    92 	mi.makeCoderMethods(t, si)
       
    93 
       
    94 	atomic.StoreUint32(&mi.initDone, 1)
       
    95 }
       
    96 
       
    97 // getPointer returns the pointer for a message, which should be of
       
    98 // the type of the MessageInfo. If the message is of a different type,
       
    99 // it returns ok==false.
       
   100 func (mi *MessageInfo) getPointer(m pref.Message) (p pointer, ok bool) {
       
   101 	switch m := m.(type) {
       
   102 	case *messageState:
       
   103 		return m.pointer(), m.messageInfo() == mi
       
   104 	case *messageReflectWrapper:
       
   105 		return m.pointer(), m.messageInfo() == mi
       
   106 	}
       
   107 	return pointer{}, false
       
   108 }
       
   109 
       
   110 type (
       
   111 	SizeCache       = int32
       
   112 	WeakFields      = map[int32]protoreflect.ProtoMessage
       
   113 	UnknownFields   = unknownFieldsA // TODO: switch to unknownFieldsB
       
   114 	unknownFieldsA  = []byte
       
   115 	unknownFieldsB  = *[]byte
       
   116 	ExtensionFields = map[int32]ExtensionField
       
   117 )
       
   118 
       
   119 var (
       
   120 	sizecacheType       = reflect.TypeOf(SizeCache(0))
       
   121 	weakFieldsType      = reflect.TypeOf(WeakFields(nil))
       
   122 	unknownFieldsAType  = reflect.TypeOf(unknownFieldsA(nil))
       
   123 	unknownFieldsBType  = reflect.TypeOf(unknownFieldsB(nil))
       
   124 	extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
       
   125 )
       
   126 
       
   127 type structInfo struct {
       
   128 	sizecacheOffset offset
       
   129 	sizecacheType   reflect.Type
       
   130 	weakOffset      offset
       
   131 	weakType        reflect.Type
       
   132 	unknownOffset   offset
       
   133 	unknownType     reflect.Type
       
   134 	extensionOffset offset
       
   135 	extensionType   reflect.Type
       
   136 
       
   137 	fieldsByNumber        map[pref.FieldNumber]reflect.StructField
       
   138 	oneofsByName          map[pref.Name]reflect.StructField
       
   139 	oneofWrappersByType   map[reflect.Type]pref.FieldNumber
       
   140 	oneofWrappersByNumber map[pref.FieldNumber]reflect.Type
       
   141 }
       
   142 
       
   143 func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
       
   144 	si := structInfo{
       
   145 		sizecacheOffset: invalidOffset,
       
   146 		weakOffset:      invalidOffset,
       
   147 		unknownOffset:   invalidOffset,
       
   148 		extensionOffset: invalidOffset,
       
   149 
       
   150 		fieldsByNumber:        map[pref.FieldNumber]reflect.StructField{},
       
   151 		oneofsByName:          map[pref.Name]reflect.StructField{},
       
   152 		oneofWrappersByType:   map[reflect.Type]pref.FieldNumber{},
       
   153 		oneofWrappersByNumber: map[pref.FieldNumber]reflect.Type{},
       
   154 	}
       
   155 
       
   156 fieldLoop:
       
   157 	for i := 0; i < t.NumField(); i++ {
       
   158 		switch f := t.Field(i); f.Name {
       
   159 		case genid.SizeCache_goname, genid.SizeCacheA_goname:
       
   160 			if f.Type == sizecacheType {
       
   161 				si.sizecacheOffset = offsetOf(f, mi.Exporter)
       
   162 				si.sizecacheType = f.Type
       
   163 			}
       
   164 		case genid.WeakFields_goname, genid.WeakFieldsA_goname:
       
   165 			if f.Type == weakFieldsType {
       
   166 				si.weakOffset = offsetOf(f, mi.Exporter)
       
   167 				si.weakType = f.Type
       
   168 			}
       
   169 		case genid.UnknownFields_goname, genid.UnknownFieldsA_goname:
       
   170 			if f.Type == unknownFieldsAType || f.Type == unknownFieldsBType {
       
   171 				si.unknownOffset = offsetOf(f, mi.Exporter)
       
   172 				si.unknownType = f.Type
       
   173 			}
       
   174 		case genid.ExtensionFields_goname, genid.ExtensionFieldsA_goname, genid.ExtensionFieldsB_goname:
       
   175 			if f.Type == extensionFieldsType {
       
   176 				si.extensionOffset = offsetOf(f, mi.Exporter)
       
   177 				si.extensionType = f.Type
       
   178 			}
       
   179 		default:
       
   180 			for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
       
   181 				if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
       
   182 					n, _ := strconv.ParseUint(s, 10, 64)
       
   183 					si.fieldsByNumber[pref.FieldNumber(n)] = f
       
   184 					continue fieldLoop
       
   185 				}
       
   186 			}
       
   187 			if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
       
   188 				si.oneofsByName[pref.Name(s)] = f
       
   189 				continue fieldLoop
       
   190 			}
       
   191 		}
       
   192 	}
       
   193 
       
   194 	// Derive a mapping of oneof wrappers to fields.
       
   195 	oneofWrappers := mi.OneofWrappers
       
   196 	for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} {
       
   197 		if fn, ok := reflect.PtrTo(t).MethodByName(method); ok {
       
   198 			for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
       
   199 				if vs, ok := v.Interface().([]interface{}); ok {
       
   200 					oneofWrappers = vs
       
   201 				}
       
   202 			}
       
   203 		}
       
   204 	}
       
   205 	for _, v := range oneofWrappers {
       
   206 		tf := reflect.TypeOf(v).Elem()
       
   207 		f := tf.Field(0)
       
   208 		for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
       
   209 			if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
       
   210 				n, _ := strconv.ParseUint(s, 10, 64)
       
   211 				si.oneofWrappersByType[tf] = pref.FieldNumber(n)
       
   212 				si.oneofWrappersByNumber[pref.FieldNumber(n)] = tf
       
   213 				break
       
   214 			}
       
   215 		}
       
   216 	}
       
   217 
       
   218 	return si
       
   219 }
       
   220 
       
   221 func (mi *MessageInfo) New() protoreflect.Message {
       
   222 	return mi.MessageOf(reflect.New(mi.GoReflectType.Elem()).Interface())
       
   223 }
       
   224 func (mi *MessageInfo) Zero() protoreflect.Message {
       
   225 	return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())
       
   226 }
       
   227 func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor {
       
   228 	return mi.Desc
       
   229 }
       
   230 func (mi *MessageInfo) Enum(i int) protoreflect.EnumType {
       
   231 	mi.init()
       
   232 	fd := mi.Desc.Fields().Get(i)
       
   233 	return Export{}.EnumTypeOf(mi.fieldTypes[fd.Number()])
       
   234 }
       
   235 func (mi *MessageInfo) Message(i int) protoreflect.MessageType {
       
   236 	mi.init()
       
   237 	fd := mi.Desc.Fields().Get(i)
       
   238 	switch {
       
   239 	case fd.IsWeak():
       
   240 		mt, _ := preg.GlobalTypes.FindMessageByName(fd.Message().FullName())
       
   241 		return mt
       
   242 	case fd.IsMap():
       
   243 		return mapEntryType{fd.Message(), mi.fieldTypes[fd.Number()]}
       
   244 	default:
       
   245 		return Export{}.MessageTypeOf(mi.fieldTypes[fd.Number()])
       
   246 	}
       
   247 }
       
   248 
       
   249 type mapEntryType struct {
       
   250 	desc    protoreflect.MessageDescriptor
       
   251 	valType interface{} // zero value of enum or message type
       
   252 }
       
   253 
       
   254 func (mt mapEntryType) New() protoreflect.Message {
       
   255 	return nil
       
   256 }
       
   257 func (mt mapEntryType) Zero() protoreflect.Message {
       
   258 	return nil
       
   259 }
       
   260 func (mt mapEntryType) Descriptor() protoreflect.MessageDescriptor {
       
   261 	return mt.desc
       
   262 }
       
   263 func (mt mapEntryType) Enum(i int) protoreflect.EnumType {
       
   264 	fd := mt.desc.Fields().Get(i)
       
   265 	if fd.Enum() == nil {
       
   266 		return nil
       
   267 	}
       
   268 	return Export{}.EnumTypeOf(mt.valType)
       
   269 }
       
   270 func (mt mapEntryType) Message(i int) protoreflect.MessageType {
       
   271 	fd := mt.desc.Fields().Get(i)
       
   272 	if fd.Message() == nil {
       
   273 		return nil
       
   274 	}
       
   275 	return Export{}.MessageTypeOf(mt.valType)
       
   276 }