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 5package impl 6 7import ( 8 "fmt" 9 "reflect" 10 "strconv" 11 "strings" 12 "sync" 13 "sync/atomic" 14 15 "google.golang.org/protobuf/internal/genname" 16 "google.golang.org/protobuf/reflect/protoreflect" 17 pref "google.golang.org/protobuf/reflect/protoreflect" 18) 19 20// MessageInfo provides protobuf related functionality for a given Go type 21// that represents a message. A given instance of MessageInfo is tied to 22// exactly one Go type, which must be a pointer to a struct type. 23// 24// The exported fields must be populated before any methods are called 25// and cannot be mutated after set. 26type MessageInfo struct { 27 // GoReflectType is the underlying message Go type and must be populated. 28 GoReflectType reflect.Type // pointer to struct 29 30 // Desc is the underlying message descriptor type and must be populated. 31 Desc pref.MessageDescriptor 32 33 // Exporter must be provided in a purego environment in order to provide 34 // access to unexported fields. 35 Exporter exporter 36 37 // OneofWrappers is list of pointers to oneof wrapper struct types. 38 OneofWrappers []interface{} 39 40 initMu sync.Mutex // protects all unexported fields 41 initDone uint32 42 43 reflectMessageInfo // for reflection implementation 44 coderMessageInfo // for fast-path method implementations 45} 46 47// exporter is a function that returns a reference to the ith field of v, 48// where v is a pointer to a struct. It returns nil if it does not support 49// exporting the requested field (e.g., already exported). 50type exporter func(v interface{}, i int) interface{} 51 52// getMessageInfo returns the MessageInfo for any message type that 53// is generated by our implementation of protoc-gen-go (for v2 and on). 54// If it is unable to obtain a MessageInfo, it returns nil. 55func getMessageInfo(mt reflect.Type) *MessageInfo { 56 m, ok := reflect.Zero(mt).Interface().(pref.ProtoMessage) 57 if !ok { 58 return nil 59 } 60 mr, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *MessageInfo }) 61 if !ok { 62 return nil 63 } 64 return mr.ProtoMessageInfo() 65} 66 67func (mi *MessageInfo) init() { 68 // This function is called in the hot path. Inline the sync.Once logic, 69 // since allocating a closure for Once.Do is expensive. 70 // Keep init small to ensure that it can be inlined. 71 if atomic.LoadUint32(&mi.initDone) == 0 { 72 mi.initOnce() 73 } 74} 75 76func (mi *MessageInfo) initOnce() { 77 mi.initMu.Lock() 78 defer mi.initMu.Unlock() 79 if mi.initDone == 1 { 80 return 81 } 82 83 t := mi.GoReflectType 84 if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct { 85 panic(fmt.Sprintf("got %v, want *struct kind", t)) 86 } 87 t = t.Elem() 88 89 si := mi.makeStructInfo(t) 90 mi.makeReflectFuncs(t, si) 91 mi.makeCoderMethods(t, si) 92 93 atomic.StoreUint32(&mi.initDone, 1) 94} 95 96// getPointer returns the pointer for a message, which should be of 97// the type of the MessageInfo. If the message is of a different type, 98// it returns ok==false. 99func (mi *MessageInfo) getPointer(m pref.Message) (p pointer, ok bool) { 100 switch m := m.(type) { 101 case *messageState: 102 return m.pointer(), m.messageInfo() == mi 103 case *messageReflectWrapper: 104 return m.pointer(), m.messageInfo() == mi 105 } 106 return pointer{}, false 107} 108 109type ( 110 SizeCache = int32 111 WeakFields = map[int32]protoreflect.ProtoMessage 112 UnknownFields = []byte 113 ExtensionFields = map[int32]ExtensionField 114) 115 116var ( 117 sizecacheType = reflect.TypeOf(SizeCache(0)) 118 weakFieldsType = reflect.TypeOf(WeakFields(nil)) 119 unknownFieldsType = reflect.TypeOf(UnknownFields(nil)) 120 extensionFieldsType = reflect.TypeOf(ExtensionFields(nil)) 121) 122 123type structInfo struct { 124 sizecacheOffset offset 125 weakOffset offset 126 unknownOffset offset 127 extensionOffset offset 128 129 fieldsByNumber map[pref.FieldNumber]reflect.StructField 130 oneofsByName map[pref.Name]reflect.StructField 131 oneofWrappersByType map[reflect.Type]pref.FieldNumber 132 oneofWrappersByNumber map[pref.FieldNumber]reflect.Type 133} 134 135func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo { 136 si := structInfo{ 137 sizecacheOffset: invalidOffset, 138 weakOffset: invalidOffset, 139 unknownOffset: invalidOffset, 140 extensionOffset: invalidOffset, 141 142 fieldsByNumber: map[pref.FieldNumber]reflect.StructField{}, 143 oneofsByName: map[pref.Name]reflect.StructField{}, 144 oneofWrappersByType: map[reflect.Type]pref.FieldNumber{}, 145 oneofWrappersByNumber: map[pref.FieldNumber]reflect.Type{}, 146 } 147 148fieldLoop: 149 for i := 0; i < t.NumField(); i++ { 150 switch f := t.Field(i); f.Name { 151 case genname.SizeCache, genname.SizeCacheA: 152 if f.Type == sizecacheType { 153 si.sizecacheOffset = offsetOf(f, mi.Exporter) 154 } 155 case genname.WeakFields, genname.WeakFieldsA: 156 if f.Type == weakFieldsType { 157 si.weakOffset = offsetOf(f, mi.Exporter) 158 } 159 case genname.UnknownFields, genname.UnknownFieldsA: 160 if f.Type == unknownFieldsType { 161 si.unknownOffset = offsetOf(f, mi.Exporter) 162 } 163 case genname.ExtensionFields, genname.ExtensionFieldsA, genname.ExtensionFieldsB: 164 if f.Type == extensionFieldsType { 165 si.extensionOffset = offsetOf(f, mi.Exporter) 166 } 167 default: 168 for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") { 169 if len(s) > 0 && strings.Trim(s, "0123456789") == "" { 170 n, _ := strconv.ParseUint(s, 10, 64) 171 si.fieldsByNumber[pref.FieldNumber(n)] = f 172 continue fieldLoop 173 } 174 } 175 if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 { 176 si.oneofsByName[pref.Name(s)] = f 177 continue fieldLoop 178 } 179 } 180 } 181 182 // Derive a mapping of oneof wrappers to fields. 183 oneofWrappers := mi.OneofWrappers 184 for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} { 185 if fn, ok := reflect.PtrTo(t).MethodByName(method); ok { 186 for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { 187 if vs, ok := v.Interface().([]interface{}); ok { 188 oneofWrappers = vs 189 } 190 } 191 } 192 } 193 for _, v := range oneofWrappers { 194 tf := reflect.TypeOf(v).Elem() 195 f := tf.Field(0) 196 for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") { 197 if len(s) > 0 && strings.Trim(s, "0123456789") == "" { 198 n, _ := strconv.ParseUint(s, 10, 64) 199 si.oneofWrappersByType[tf] = pref.FieldNumber(n) 200 si.oneofWrappersByNumber[pref.FieldNumber(n)] = tf 201 break 202 } 203 } 204 } 205 206 return si 207} 208 209func (mi *MessageInfo) New() protoreflect.Message { 210 return mi.MessageOf(reflect.New(mi.GoReflectType.Elem()).Interface()) 211} 212func (mi *MessageInfo) Zero() protoreflect.Message { 213 return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface()) 214} 215func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor { return mi.Desc } 216