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